1## Unreleased
2
3* The default `NormalizePath` behavior now strips trailing slashes by default. This was
4  previously documented to be the case in v3 but the behavior now matches. The effect is that
5  routes defined with trailing slashes will become inaccessible when
6  using `NormalizePath::default()`.
7
8  Before: `#[get("/test/")`
9  After: `#[get("/test")`
10
11  Alternatively, explicitly require trailing slashes: `NormalizePath::new(TrailingSlash::Always)`.
12
13* Feature flag `compress` has been split into its supported algorithm (brotli, gzip, zstd).
14  By default all compression algorithms are enabled.
15  To select algorithm you want to include with `middleware::Compress` use following flags:
16  - `compress-brotli`
17  - `compress-gzip`
18  - `compress-zstd`
19  If you have set in your `Cargo.toml` dedicated `actix-web` features and you still want
20  to have compression enabled. Please change features selection like bellow:
21
22  Before: `"compress"`
23  After: `"compress-brotli", "compress-gzip", "compress-zstd"`
24
25
26## 3.0.0
27
28* The return type for `ServiceRequest::app_data::<T>()` was changed from returning a `Data<T>` to
29  simply a `T`. To access a `Data<T>` use `ServiceRequest::app_data::<Data<T>>()`.
30
31* Cookie handling has been offloaded to the `cookie` crate:
32  * `USERINFO_ENCODE_SET` is no longer exposed. Percent-encoding is still supported; check docs.
33  * Some types now require lifetime parameters.
34
35* The time crate was updated to `v0.2`, a major breaking change to the time crate, which affects
36  any `actix-web` method previously expecting a time v0.1 input.
37
38* Setting a cookie's SameSite property, explicitly, to `SameSite::None` will now
39  result in `SameSite=None` being sent with the response Set-Cookie header.
40  To create a cookie without a SameSite attribute, remove any calls setting same_site.
41
42* actix-http support for Actors messages was moved to actix-http crate and is enabled
43  with feature `actors`
44
45* content_length function is removed from actix-http.
46  You can set Content-Length by normally setting the response body or calling no_chunking function.
47
48* `BodySize::Sized64` variant has been removed. `BodySize::Sized` now receives a
49  `u64` instead of a `usize`.
50
51* Code that was using `path.<index>` to access a `web::Path<(A, B, C)>`s elements now needs to use
52  destructuring or `.into_inner()`. For example:
53
54  ```rust
55  // Previously:
56  async fn some_route(path: web::Path<(String, String)>) -> String {
57    format!("Hello, {} {}", path.0, path.1)
58  }
59
60  // Now (this also worked before):
61  async fn some_route(path: web::Path<(String, String)>) -> String {
62    let (first_name, last_name) = path.into_inner();
63    format!("Hello, {} {}", first_name, last_name)
64  }
65  // Or (this wasn't previously supported):
66  async fn some_route(web::Path((first_name, last_name)): web::Path<(String, String)>) -> String {
67    format!("Hello, {} {}", first_name, last_name)
68  }
69  ```
70
71* `middleware::NormalizePath` can now also be configured to trim trailing slashes instead of always keeping one.
72  It will need `middleware::normalize::TrailingSlash` when being constructed with `NormalizePath::new(...)`,
73  or for an easier migration you can replace `wrap(middleware::NormalizePath)` with `wrap(middleware::NormalizePath::new(TrailingSlash::MergeOnly))`.
74
75* `HttpServer::maxconn` is renamed to the more expressive `HttpServer::max_connections`.
76
77* `HttpServer::maxconnrate` is renamed to the more expressive `HttpServer::max_connection_rate`.
78
79
80## 2.0.0
81
82* `HttpServer::start()` renamed to `HttpServer::run()`. It also possible to
83  `.await` on `run` method result, in that case it awaits server exit.
84
85* `App::register_data()` renamed to `App::app_data()` and accepts any type `T: 'static`.
86  Stored data is available via `HttpRequest::app_data()` method at runtime.
87
88* Extractor configuration must be registered with `App::app_data()` instead of `App::data()`
89
90* Sync handlers has been removed. `.to_async()` method has been renamed to `.to()`
91  replace `fn` with `async fn` to convert sync handler to async
92
93* `actix_http_test::TestServer` moved to `actix_web::test` module. To start
94  test server use `test::start()` or `test_start_with_config()` methods
95
96* `ResponseError` trait has been reafctored. `ResponseError::error_response()` renders
97  http response.
98
99* Feature `rust-tls` renamed to `rustls`
100
101  instead of
102
103    ```rust
104    actix-web = { version = "2.0.0", features = ["rust-tls"] }
105    ```
106
107  use
108
109    ```rust
110    actix-web = { version = "2.0.0", features = ["rustls"] }
111    ```
112
113* Feature `ssl` renamed to `openssl`
114
115  instead of
116
117    ```rust
118    actix-web = { version = "2.0.0", features = ["ssl"] }
119    ```
120
121  use
122
123    ```rust
124    actix-web = { version = "2.0.0", features = ["openssl"] }
125    ```
126* `Cors` builder now requires that you call `.finish()` to construct the middleware
127
128## 1.0.1
129
130* Cors middleware has been moved to `actix-cors` crate
131
132  instead of
133
134  ```rust
135  use actix_web::middleware::cors::Cors;
136  ```
137
138  use
139
140  ```rust
141  use actix_cors::Cors;
142  ```
143
144* Identity middleware has been moved to `actix-identity` crate
145
146  instead of
147
148  ```rust
149  use actix_web::middleware::identity::{Identity, CookieIdentityPolicy, IdentityService};
150  ```
151
152  use
153
154  ```rust
155  use actix_identity::{Identity, CookieIdentityPolicy, IdentityService};
156  ```
157
158
159## 1.0.0
160
161* Extractor configuration. In version 1.0 this is handled with the new `Data` mechanism for both setting and retrieving the configuration
162
163  instead of
164
165  ```rust
166
167  #[derive(Default)]
168  struct ExtractorConfig {
169     config: String,
170  }
171
172  impl FromRequest for YourExtractor {
173     type Config = ExtractorConfig;
174     type Result = Result<YourExtractor, Error>;
175
176     fn from_request(req: &HttpRequest, cfg: &Self::Config) -> Self::Result {
177         println!("use the config: {:?}", cfg.config);
178         ...
179     }
180  }
181
182  App::new().resource("/route_with_config", |r| {
183     r.post().with_config(handler_fn, |cfg| {
184         cfg.0.config = "test".to_string();
185     })
186  })
187
188  ```
189
190  use the HttpRequest to get the configuration like any other `Data` with `req.app_data::<C>()` and set it with the `data()` method on the `resource`
191
192  ```rust
193  #[derive(Default)]
194  struct ExtractorConfig {
195     config: String,
196  }
197
198  impl FromRequest for YourExtractor {
199     type Error = Error;
200     type Future = Result<Self, Self::Error>;
201     type Config = ExtractorConfig;
202
203     fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future {
204         let cfg = req.app_data::<ExtractorConfig>();
205         println!("config data?: {:?}", cfg.unwrap().role);
206         ...
207     }
208  }
209
210  App::new().service(
211     resource("/route_with_config")
212         .data(ExtractorConfig {
213             config: "test".to_string(),
214         })
215         .route(post().to(handler_fn)),
216  )
217  ```
218
219* Resource registration. 1.0 version uses generalized resource
220  registration via `.service()` method.
221
222  instead of
223
224  ```rust
225    App.new().resource("/welcome", |r| r.f(welcome))
226  ```
227
228  use App's or Scope's `.service()` method. `.service()` method accepts
229  object that implements `HttpServiceFactory` trait. By default
230  actix-web provides `Resource` and `Scope` services.
231
232  ```rust
233    App.new().service(
234        web::resource("/welcome")
235            .route(web::get().to(welcome))
236            .route(web::post().to(post_handler))
237  ```
238
239* Scope registration.
240
241  instead of
242
243  ```rust
244      let app = App::new().scope("/{project_id}", |scope| {
245            scope
246                .resource("/path1", |r| r.f(|_| HttpResponse::Ok()))
247                .resource("/path2", |r| r.f(|_| HttpResponse::Ok()))
248                .resource("/path3", |r| r.f(|_| HttpResponse::MethodNotAllowed()))
249      });
250  ```
251
252  use `.service()` for registration and `web::scope()` as scope object factory.
253
254  ```rust
255      let app = App::new().service(
256          web::scope("/{project_id}")
257              .service(web::resource("/path1").to(|| HttpResponse::Ok()))
258              .service(web::resource("/path2").to(|| HttpResponse::Ok()))
259              .service(web::resource("/path3").to(|| HttpResponse::MethodNotAllowed()))
260      );
261  ```
262
263* `.with()`, `.with_async()` registration methods have been renamed to `.to()` and `.to_async()`.
264
265  instead of
266
267  ```rust
268    App.new().resource("/welcome", |r| r.with(welcome))
269  ```
270
271  use `.to()` or `.to_async()` methods
272
273  ```rust
274    App.new().service(web::resource("/welcome").to(welcome))
275  ```
276
277* Passing arguments to handler with extractors, multiple arguments are allowed
278
279  instead of
280
281  ```rust
282  fn welcome((body, req): (Bytes, HttpRequest)) -> ... {
283    ...
284  }
285  ```
286
287  use multiple arguments
288
289  ```rust
290  fn welcome(body: Bytes, req: HttpRequest) -> ... {
291    ...
292  }
293  ```
294
295* `.f()`, `.a()` and `.h()` handler registration methods have been removed.
296  Use `.to()` for handlers and `.to_async()` for async handlers. Handler function
297  must use extractors.
298
299  instead of
300
301  ```rust
302    App.new().resource("/welcome", |r| r.f(welcome))
303  ```
304
305  use App's `to()` or `to_async()` methods
306
307  ```rust
308    App.new().service(web::resource("/welcome").to(welcome))
309  ```
310
311* `HttpRequest` does not provide access to request's payload stream.
312
313  instead of
314
315  ```rust
316  fn index(req: &HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
317    req
318       .payload()
319       .from_err()
320       .fold((), |_, chunk| {
321            ...
322        })
323       .map(|_| HttpResponse::Ok().finish())
324       .responder()
325  }
326  ```
327
328  use `Payload` extractor
329
330  ```rust
331  fn index(stream: web::Payload) -> impl Future<Item=HttpResponse, Error=Error> {
332     stream
333       .from_err()
334       .fold((), |_, chunk| {
335            ...
336        })
337       .map(|_| HttpResponse::Ok().finish())
338  }
339  ```
340
341* `State` is now `Data`.  You register Data during the App initialization process
342  and then access it from handlers either using a Data extractor or using
343  HttpRequest's api.
344
345  instead of
346
347  ```rust
348    App.with_state(T)
349  ```
350
351  use App's `data` method
352
353  ```rust
354	App.new()
355       .data(T)
356  ```
357
358  and either use the Data extractor within your handler
359
360  ```rust
361    use actix_web::web::Data;
362
363	fn endpoint_handler(Data<T>)){
364      ...
365    }
366  ```
367
368  .. or access your Data element from the HttpRequest
369
370  ```rust
371	fn endpoint_handler(req: HttpRequest) {
372		let data: Option<Data<T>> = req.app_data::<T>();
373    }
374  ```
375
376
377* AsyncResponder is removed, use `.to_async()` registration method and `impl Future<>` as result type.
378
379  instead of
380
381  ```rust
382	use actix_web::AsyncResponder;
383
384    fn endpoint_handler(...) -> impl Future<Item=HttpResponse, Error=Error>{
385		...
386        .responder()
387	}
388  ```
389
390  .. simply omit AsyncResponder and the corresponding responder() finish method
391
392
393* Middleware
394
395  instead of
396
397  ```rust
398      let app = App::new()
399           .middleware(middleware::Logger::default())
400  ```
401
402  use `.wrap()` method
403
404  ```rust
405      let app = App::new()
406           .wrap(middleware::Logger::default())
407           .route("/index.html", web::get().to(index));
408  ```
409
410* `HttpRequest::body()`, `HttpRequest::urlencoded()`, `HttpRequest::json()`, `HttpRequest::multipart()`
411  method have been removed. Use `Bytes`, `String`, `Form`, `Json`, `Multipart` extractors instead.
412
413  instead of
414
415  ```rust
416  fn index(req: &HttpRequest) -> Responder {
417     req.body()
418       .and_then(|body| {
419          ...
420       })
421  }
422  ```
423
424  use
425
426  ```rust
427  fn index(body: Bytes) -> Responder {
428     ...
429  }
430  ```
431
432* `actix_web::server` module has been removed. To start http server use `actix_web::HttpServer` type
433
434* StaticFiles and NamedFile have been moved to a separate crate.
435
436  instead of `use actix_web::fs::StaticFile`
437
438  use `use actix_files::Files`
439
440  instead of `use actix_web::fs::Namedfile`
441
442  use `use actix_files::NamedFile`
443
444* Multipart has been moved to a separate crate.
445
446  instead of `use actix_web::multipart::Multipart`
447
448  use `use actix_multipart::Multipart`
449
450* Response compression is not enabled by default.
451  To enable, use `Compress` middleware, `App::new().wrap(Compress::default())`.
452
453* Session middleware moved to actix-session crate
454
455* Actors support have been moved to `actix-web-actors` crate
456
457* Custom Error
458
459  Instead of error_response method alone, ResponseError now provides two methods: error_response and render_response respectively. Where, error_response creates the error response and render_response returns the error response to the caller.
460
461  Simplest migration from 0.7 to 1.0 shall include below method to the custom implementation of ResponseError:
462
463  ```rust
464  fn render_response(&self) -> HttpResponse {
465    self.error_response()
466  }
467  ```
468
469## 0.7.15
470
471* The `' '` character is not percent decoded anymore before matching routes. If you need to use it in
472  your routes, you should use `%20`.
473
474  instead of
475
476    ```rust
477    fn main() {
478         let app = App::new().resource("/my index", |r| {
479             r.method(http::Method::GET)
480                    .with(index);
481         });
482    }
483    ```
484
485  use
486
487    ```rust
488    fn main() {
489         let app = App::new().resource("/my%20index", |r| {
490             r.method(http::Method::GET)
491                    .with(index);
492         });
493    }
494    ```
495
496* If you used `AsyncResult::async` you need to replace it with `AsyncResult::future`
497
498
499## 0.7.4
500
501* `Route::with_config()`/`Route::with_async_config()` always passes configuration objects as tuple
502  even for handler with one parameter.
503
504
505## 0.7
506
507* `HttpRequest` does not implement `Stream` anymore. If you need to read request payload
508  use `HttpMessage::payload()` method.
509
510  instead of
511
512    ```rust
513    fn index(req: HttpRequest) -> impl Responder {
514         req
515            .from_err()
516            .fold(...)
517            ....
518    }
519    ```
520
521  use `.payload()`
522
523    ```rust
524    fn index(req: HttpRequest) -> impl Responder {
525         req
526            .payload()  // <- get request payload stream
527            .from_err()
528            .fold(...)
529            ....
530    }
531    ```
532
533* [Middleware](https://actix.rs/actix-web/actix_web/middleware/trait.Middleware.html)
534  trait uses `&HttpRequest` instead of `&mut HttpRequest`.
535
536* Removed `Route::with2()` and `Route::with3()` use tuple of extractors instead.
537
538    instead of
539
540    ```rust
541    fn index(query: Query<..>, info: Json<MyStruct) -> impl Responder {}
542    ```
543
544    use tuple of extractors and use `.with()` for registration:
545
546    ```rust
547    fn index((query, json): (Query<..>, Json<MyStruct)) -> impl Responder {}
548    ```
549
550* `Handler::handle()` uses `&self` instead of `&mut self`
551
552* `Handler::handle()` accepts reference to `HttpRequest<_>` instead of value
553
554* Removed deprecated `HttpServer::threads()`, use
555  [HttpServer::workers()](https://actix.rs/actix-web/actix_web/server/struct.HttpServer.html#method.workers) instead.
556
557* Renamed `client::ClientConnectorError::Connector` to
558  `client::ClientConnectorError::Resolver`
559
560* `Route::with()` does not return `ExtractorConfig`, to configure
561  extractor use `Route::with_config()`
562
563    instead of
564
565    ```rust
566    fn main() {
567         let app = App::new().resource("/index.html", |r| {
568             r.method(http::Method::GET)
569                    .with(index)
570                    .limit(4096);  // <- limit size of the payload
571         });
572    }
573    ```
574
575    use
576
577    ```rust
578
579    fn main() {
580         let app = App::new().resource("/index.html", |r| {
581             r.method(http::Method::GET)
582                    .with_config(index, |cfg| { // <- register handler
583                       cfg.limit(4096);  // <- limit size of the payload
584                     })
585         });
586    }
587    ```
588
589* `Route::with_async()` does not return `ExtractorConfig`, to configure
590  extractor use `Route::with_async_config()`
591
592
593## 0.6
594
595* `Path<T>` extractor return `ErrorNotFound` on failure instead of `ErrorBadRequest`
596
597* `ws::Message::Close` now includes optional close reason.
598  `ws::CloseCode::Status` and `ws::CloseCode::Empty` have been removed.
599
600* `HttpServer::threads()` renamed to `HttpServer::workers()`.
601
602* `HttpServer::start_ssl()` and `HttpServer::start_tls()` deprecated.
603  Use `HttpServer::bind_ssl()` and `HttpServer::bind_tls()` instead.
604
605* `HttpRequest::extensions()` returns read only reference to the request's Extension
606  `HttpRequest::extensions_mut()` returns mutable reference.
607
608* Instead of
609
610   `use actix_web::middleware::{
611        CookieSessionBackend, CookieSessionError, RequestSession,
612        Session, SessionBackend, SessionImpl, SessionStorage};`
613
614  use `actix_web::middleware::session`
615
616   `use actix_web::middleware::session{CookieSessionBackend, CookieSessionError,
617        RequestSession, Session, SessionBackend, SessionImpl, SessionStorage};`
618
619* `FromRequest::from_request()` accepts mutable reference to a request
620
621* `FromRequest::Result` has to implement `Into<Reply<Self>>`
622
623* [`Responder::respond_to()`](
624  https://actix.rs/actix-web/actix_web/trait.Responder.html#tymethod.respond_to)
625  is generic over `S`
626
627*  Use `Query` extractor instead of HttpRequest::query()`.
628
629   ```rust
630   fn index(q: Query<HashMap<String, String>>) -> Result<..> {
631       ...
632   }
633   ```
634
635   or
636
637   ```rust
638   let q = Query::<HashMap<String, String>>::extract(req);
639   ```
640
641* Websocket operations are implemented as `WsWriter` trait.
642  you need to use `use actix_web::ws::WsWriter`
643
644
645## 0.5
646
647* `HttpResponseBuilder::body()`, `.finish()`, `.json()`
648   methods return `HttpResponse` instead of `Result<HttpResponse>`
649
650* `actix_web::Method`, `actix_web::StatusCode`, `actix_web::Version`
651   moved to `actix_web::http` module
652
653* `actix_web::header` moved to `actix_web::http::header`
654
655* `NormalizePath` moved to `actix_web::http` module
656
657* `HttpServer` moved to `actix_web::server`, added new `actix_web::server::new()` function,
658  shortcut for `actix_web::server::HttpServer::new()`
659
660* `DefaultHeaders` middleware does not use separate builder, all builder methods moved to type itself
661
662* `StaticFiles::new()`'s show_index parameter removed, use `show_files_listing()` method instead.
663
664* `CookieSessionBackendBuilder` removed, all methods moved to `CookieSessionBackend` type
665
666* `actix_web::httpcodes` module is deprecated, `HttpResponse::Ok()`, `HttpResponse::Found()` and other `HttpResponse::XXX()`
667   functions should be used instead
668
669* `ClientRequestBuilder::body()` returns `Result<_, actix_web::Error>`
670  instead of `Result<_, http::Error>`
671
672* `Application` renamed to a `App`
673
674* `actix_web::Reply`, `actix_web::Resource` moved to `actix_web::dev`
675