diff --git a/content/docs/extractors.md b/content/docs/extractors.md
index f6668f6..df6c6bc 100644
--- a/content/docs/extractors.md
+++ b/content/docs/extractors.md
@@ -6,37 +6,26 @@ weight: 170
# Type-safe information extraction
-Actix provides facility for type-safe request information extraction. By default,
-actix provides several extractor implementations.
+Actix-web provides a facility for type-safe request information access called *extractors*
+(ie, `impl FromRequest`). By default, actix-web provides several extractor implementations.
-# Accessing Extractors
+## Extractors Within Handler Functions
-How you access an Extractor depends on whether you are using a handler function
-or a custom Handler type.
+An extractor can be accessed in a few different ways.
-## Within Handler Functions
+Option 1 - passed as a parameter to a handler function:
-An Extractor can be passed to a handler function as a function parameter
-*or* accessed within the function by calling the ExtractorType::<...>::extract(req)
-function.
+{{< include-example example="extractors" file="main.rs" section="option-one" >}}
-{{< include-example example="extractors" file="main.rs" section="main" >}}
+Option 2 - accessed by calling `extract()` on the Extractor
-## Within Custom Handler Types
-
-Like a handler function, a custom Handler type can *access* an Extractor by
-calling the ExtractorType::<...>::extract(&req) function. An Extractor
-*cannot* be passed as a parameter to a custom Handler type because a custom
-Handler type must follow the ``handle`` function signature specified by the
-Handler trait it implements.
-
-{{< include-example example="extractors" file="custom_handler.rs" section="custom-handler" >}}
+{{< include-example example="extractors" file="main.rs" section="option-two" >}}
# Path
-[*Path*](../../actix-web/actix_web/struct.Path.html) provides information that can
-be extracted from the Request's path. You can deserialize any variable
-segment from the path.
+[*Path*](https://docs.rs/actix-web/1.0.2/actix_web/dev/struct.Path.html) provides
+information that can be extracted from the Request's path. You can deserialize any
+variable segment from the path.
For instance, for resource that registered for the `/users/{userid}/{friend}` path
two segments could be deserialized, `userid` and `friend`. These segments
@@ -51,27 +40,31 @@ instead of a *tuple* type.
{{< include-example example="extractors" file="path_two.rs" section="path-two" >}}
+It is also possible to `get` or `query` the request for path parameters by name:
+
+{{< include-example example="extractors" file="path_three.rs" section="path-three" >}}
+
# Query
-Same can be done with the request's query.
-The [*Query*](../../actix-web/actix_web/struct.Query.html)
-type provides extraction functionality. Underneath it uses *serde_urlencoded* crate.
+The [*Query*](https://docs.rs/actix-web/1.0.2/actix_web/web/struct.Query.html)
+type provides extraction functionality for the request's query parameters. Underneath it
+uses *serde_urlencoded* crate.
{{< include-example example="extractors" file="query.rs" section="query" >}}
# Json
-[*Json*](../../actix-web/actix_web/struct.Json.html) allows to deserialize
+[*Json*](https://docs.rs/actix-web/1.0.2/actix_web/web/struct.Json.html) allows to deserialize
a request body into a struct. To extract typed information from a request's body,
the type `T` must implement the `Deserialize` trait from *serde*.
{{< include-example example="extractors" file="json_one.rs" section="json-one" >}}
Some extractors provide a way to configure the extraction process. Json extractor
-[*JsonConfig*](../../actix-web/actix_web/dev/struct.JsonConfig.html) type for configuration.
-When you register a handler using `Route::with()`, it returns a configuration instance. In case of
-a *Json* extractor it returns a *JsonConfig*. You can configure the maximum size of the json
-payload as well as a custom error handler function.
+[*JsonConfig*](https://docs.rs/actix-web/1.0.2/actix_web/web/struct.JsonConfig.html) type
+for configuration. When you register a handler using `Route::with()`, it returns a
+configuration instance. In case of a *Json* extractor it returns a *JsonConfig*. You can
+configure the maximum size of the json payload as well as a custom error handler function.
The following example limits the size of the payload to 4kb and uses a custom error handler.
@@ -83,14 +76,14 @@ At the moment only url-encoded forms are supported. The url-encoded body
could be extracted to a specific type. This type must implement
the `Deserialize` trait from the *serde* crate.
-[*FormConfig*](../../actix-web/actix_web/dev/struct.FormConfig.html) allows
+[*FormConfig*](https://docs.rs/actix-web/1.0.2/actix_web/web/struct.FormConfig.html) allows
configuring the extraction process.
{{< include-example example="extractors" file="form.rs" section="form" >}}
# Multiple extractors
-Actix provides extractor implementations for tuples (up to 10 elements)
+Actix-web provides extractor implementations for tuples (up to 10 elements)
whose elements implement `FromRequest`.
For example we can use a path extractor and a query extractor at the same time.
@@ -99,15 +92,42 @@ For example we can use a path extractor and a query extractor at the same time.
# Other
-Actix also provides several other extractors:
+Actix-web also provides several other extractors:
-* [*Data*](../../actix-web/actix_web/web/struct.Data.html) - If you need
- access to an application state. This is similar to a `HttpRequest::app_data()`.
+* [*Data*](https://docs.rs/actix-web/1.0.2/actix_web/web/struct.Data.html) - If you need
+ access to an application state.
* *HttpRequest* - *HttpRequest* itself is an extractor which returns self,
in case you need access to the request.
* *String* - You can convert a request's payload to a *String*.
- [*Example*](../../actix-web/actix_web/trait.FromRequest.html#example-1)
+ [*Example*](https://docs.rs/actix-web/1.0.2/actix_web/trait.FromRequest.html#example-2)
is available in doc strings.
* *bytes::Bytes* - You can convert a request's payload into *Bytes*.
- [*Example*](../../actix-web/actix_web/trait.FromRequest.html#example)
+ [*Example*](https://docs.rs/actix-web/1.0.2/actix_web/trait.FromRequest.html#example-4)
is available in doc strings.
+* *Payload* - You can access a request's payload.
+ [*Example*](https://docs.rs/actix-web/1.0.2/actix_web/web/struct.Payload.html)
+
+# Async Data Access
+
+Application state is accessible from the handler with the `web::Data` extractor;
+however, state is accessible as a read-only reference. If you need mutable access to state,
+it must be implemented.
+
+> **Beware**, actix creates multiple copies of the application state and the handlers,
+> unique for each thread. If you run your application in several threads, actix will
+> create the same amount as number of threads of application state objects and handler
+> objects.
+
+Here is an example of a handler that stores the number of processed requests:
+
+{{< include-example example="request-handlers" file="main.rs" section="data" >}}
+
+Although this handler will work, `self.0` will be different depending on the number of threads and
+number of requests processed per thread. A proper implementation would use `Arc` and `AtomicUsize`.
+
+{{< include-example example="request-handlers" file="handlers_arc.rs" section="arc" >}}
+
+> Be careful with synchronization primitives like `Mutex` or `RwLock`. The `actix-web` framework
+> handles requests asynchronously. By blocking thread execution, all concurrent
+> request handling processes would block. If you need to share or update some state
+> from multiple threads, consider using the [actix](https://actix.github.io/actix/actix/) actor system.
diff --git a/examples/extractors/src/custom_handler.rs b/examples/extractors/src/custom_handler.rs
deleted file mode 100644
index 93596d9..0000000
--- a/examples/extractors/src/custom_handler.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-use actix_web::{web, HttpRequest, HttpResponse};
-
-struct MyHandler {}
-struct MyInfo {}
-
-//
-impl Handler for MyHandler {
- type Result = HttpResponse;
-
- /// Handle request
- fn handle(&self, req: &HttpRequest) -> Self::Result {
- let params = web::Path::<(String, String)>::extract(req);
- let info = web::Json::::extract(req);
-
- HttpResponse::Ok().into()
- }
-}
-//
diff --git a/examples/extractors/src/form.rs b/examples/extractors/src/form.rs
index 1af09d4..394a255 100644
--- a/examples/extractors/src/form.rs
+++ b/examples/extractors/src/form.rs
@@ -1,5 +1,5 @@
//
pub fn main() {
- App::new().route("", web::post().to(index));
+ HttpServer::new(|| App::new().route("/", web::post().to(index)))
+ .bind("127.0.0.1:8088")
+ .unwrap()
+ .run()
+ .unwrap();
}
diff --git a/examples/extractors/src/json_one.rs b/examples/extractors/src/json_one.rs
index d54459b..255959d 100644
--- a/examples/extractors/src/json_one.rs
+++ b/examples/extractors/src/json_one.rs
@@ -1,5 +1,5 @@
//
-use actix_web::{web, App, Result};
+use actix_web::{web, App, HttpServer, Result};
use serde::Deserialize;
#[derive(Deserialize)]
@@ -11,8 +11,12 @@ struct Info {
fn index(info: web::Json) -> Result {
Ok(format!("Welcome {}!", info.username))
}
+//
pub fn main() {
- App::new().route("/", web::get().to(index));
+ HttpServer::new(|| App::new().route("/", web::post().to(index)))
+ .bind("127.0.0.1:8088")
+ .unwrap()
+ .run()
+ .unwrap();
}
-//
diff --git a/examples/extractors/src/json_two.rs b/examples/extractors/src/json_two.rs
index c6464ac..e5e8a22 100644
--- a/examples/extractors/src/json_two.rs
+++ b/examples/extractors/src/json_two.rs
@@ -1,5 +1,5 @@
//
-use actix_web::{error, web, App, FromRequest, HttpResponse, Responder};
+use actix_web::{error, web, App, FromRequest, HttpResponse, HttpServer, Responder};
use serde::Deserialize;
#[derive(Deserialize)]
@@ -13,22 +13,28 @@ fn index(info: web::Json) -> impl Responder {
}
pub fn main() {
- App::new().service(
- web::resource("/")
- .data(
- // change json extractor configuration
- web::Json::::configure(|cfg| {
- cfg.limit(4096).error_handler(|err, _req| {
- // <- create custom error response
- error::InternalError::from_response(
- err,
- HttpResponse::Conflict().finish(),
- )
- .into()
- })
- }),
- )
- .route(web::post().to(index)),
- );
+ HttpServer::new(|| {
+ App::new().service(
+ web::resource("/")
+ .data(
+ // change json extractor configuration
+ web::Json::::configure(|cfg| {
+ cfg.limit(4096).error_handler(|err, _req| {
+ // <- create custom error response
+ error::InternalError::from_response(
+ err,
+ HttpResponse::Conflict().finish(),
+ )
+ .into()
+ })
+ }),
+ )
+ .route(web::post().to(index)),
+ )
+ })
+ .bind("127.0.0.1:8088")
+ .unwrap()
+ .run()
+ .unwrap();
}
//
diff --git a/examples/extractors/src/main.rs b/examples/extractors/src/main.rs
index 276b1b6..0925a79 100644
--- a/examples/extractors/src/main.rs
+++ b/examples/extractors/src/main.rs
@@ -8,6 +8,7 @@ pub mod json_one;
pub mod json_two;
pub mod multiple;
pub mod path_one;
+pub mod path_three;
pub mod path_two;
pub mod query;
@@ -17,13 +18,13 @@ struct MyInfo {
id: u32,
}
-//
-// Option 1: passed as a parameter to a handler function
+//
fn index(path: web::Path<(String, String)>, json: web::Json) -> impl Responder {
format!("{} {} {} {}", path.0, path.1, json.id, json.username)
}
+//
-// Option 2: accessed by calling extract() on the Extractor
+//
fn extract(req: HttpRequest) -> impl Responder {
let params = web::Path::<(String, String)>::extract(&req).unwrap();
@@ -33,7 +34,7 @@ fn extract(req: HttpRequest) -> impl Responder {
format!("{} {} {} {}", params.0, params.1, info.username, info.id)
}
-//
+//
fn main() {
HttpServer::new(|| {
diff --git a/examples/extractors/src/multiple.rs b/examples/extractors/src/multiple.rs
index 1d861d4..118dd5c 100644
--- a/examples/extractors/src/multiple.rs
+++ b/examples/extractors/src/multiple.rs
@@ -1,5 +1,5 @@
//
-use actix_web::{web, App};
+use actix_web::{web, App, HttpServer};
use serde::Deserialize;
#[derive(Deserialize)]
@@ -7,14 +7,23 @@ struct Info {
username: String,
}
-fn index((_path, query): (web::Path<(u32, String)>, web::Query)) -> String {
- format!("Welcome {}!", query.username)
+fn index((path, query): (web::Path<(u32, String)>, web::Query)) -> String {
+ format!(
+ "Welcome {}, friend {}, useri {}!",
+ query.username, path.1, path.0
+ )
}
pub fn main() {
- App::new().route(
- "/users/{userid}/{friend}", // <- define path parameters
- web::get().to(index),
- );
+ HttpServer::new(|| {
+ App::new().route(
+ "/users/{userid}/{friend}", // <- define path parameters
+ web::get().to(index),
+ )
+ })
+ .bind("127.0.0.1:8088")
+ .unwrap()
+ .run()
+ .unwrap();
}
//
diff --git a/examples/extractors/src/path_one.rs b/examples/extractors/src/path_one.rs
index eb46b9b..0b83de8 100644
--- a/examples/extractors/src/path_one.rs
+++ b/examples/extractors/src/path_one.rs
@@ -1,17 +1,23 @@
//
-use actix_web::{web, App, Result};
+use actix_web::{web, App, HttpServer, Result};
/// extract path info from "/users/{userid}/{friend}" url
/// {userid} - - deserializes to a u32
/// {friend} - deserializes to a String
fn index(info: web::Path<(u32, String)>) -> Result {
- Ok(format!("Welcome {}! {}", info.1, info.0))
+ Ok(format!("Welcome {}, userid {}!", info.1, info.0))
}
pub fn main() {
- App::new().route(
- "/users/{userid}/{friend}", // <- define path parameters
- web::get().to(index),
- );
+ HttpServer::new(|| {
+ App::new().route(
+ "/users/{userid}/{friend}", // <- define path parameters
+ web::get().to(index),
+ )
+ })
+ .bind("127.0.0.1:8088")
+ .unwrap()
+ .run()
+ .unwrap();
}
//
diff --git a/examples/extractors/src/path_two.rs b/examples/extractors/src/path_two.rs
index 7c5a4c3..aa836d6 100644
--- a/examples/extractors/src/path_two.rs
+++ b/examples/extractors/src/path_two.rs
@@ -1,5 +1,5 @@
//
-use actix_web::{web, App, Result};
+use actix_web::{web, App, HttpServer, Result};
use serde::Deserialize;
#[derive(Deserialize)]
@@ -14,9 +14,15 @@ fn index(info: web::Path) -> Result {
}
pub fn main() {
- App::new().route(
- "/users/{userid}/{friend}", // <- define path parameters
- web::get().to(index),
- );
+ HttpServer::new(|| {
+ App::new().route(
+ "/users/{userid}/{friend}", // <- define path parameters
+ web::get().to(index),
+ )
+ })
+ .bind("127.0.0.1:8088")
+ .unwrap()
+ .run()
+ .unwrap();
}
//
diff --git a/examples/extractors/src/query.rs b/examples/extractors/src/query.rs
index ff1883b..10af0ce 100644
--- a/examples/extractors/src/query.rs
+++ b/examples/extractors/src/query.rs
@@ -1,5 +1,5 @@
//
-use actix_web::{web, App};
+use actix_web::{web, App, HttpServer};
use serde::Deserialize;
#[derive(Deserialize)]
@@ -11,8 +11,12 @@ struct Info {
fn index(info: web::Query) -> String {
format!("Welcome {}!", info.username)
}
+//
pub fn main() {
- App::new().route("/", web::get().to(index));
+ HttpServer::new(|| App::new().route("/", web::get().to(index)))
+ .bind("127.0.0.1:8088")
+ .unwrap()
+ .run()
+ .unwrap();
}
-//
diff --git a/examples/request-handlers/Cargo.toml b/examples/request-handlers/Cargo.toml
index da4764a..325b659 100644
--- a/examples/request-handlers/Cargo.toml
+++ b/examples/request-handlers/Cargo.toml
@@ -1,8 +1,7 @@
[package]
name = "request-handlers"
-version = "0.7.0"
+version = "1.0.0"
edition = "2018"
[dependencies]
-actix-web = "0.7"
-actix = "0.7"
+actix-web = "1.0"
diff --git a/examples/request-handlers/src/handlers_arc.rs b/examples/request-handlers/src/handlers_arc.rs
index 9858355..f3002d8 100644
--- a/examples/request-handlers/src/handlers_arc.rs
+++ b/examples/request-handlers/src/handlers_arc.rs
@@ -1,34 +1,37 @@
//
-use actix_web::{dev::Handler, server, App, HttpRequest, HttpResponse};
+use actix_web::{web, App, HttpServer, Responder};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
-struct MyHandler(Arc);
+#[derive(Clone)]
+struct AppState {
+ count: Arc,
+}
-impl Handler for MyHandler {
- type Result = HttpResponse;
+fn show_count(data: web::Data) -> impl Responder {
+ format!("count: {}", data.count.load(Ordering::Relaxed))
+}
- /// Handle request
- fn handle(&self, _req: &HttpRequest) -> Self::Result {
- self.0.fetch_add(1, Ordering::Relaxed);
- HttpResponse::Ok().into()
- }
+fn add_one(data: web::Data) -> impl Responder {
+ data.count.fetch_add(1, Ordering::Relaxed);
+
+ format!("count: {}", data.count.load(Ordering::Relaxed))
}
pub fn main() {
- let sys = actix::System::new("example");
+ let data = AppState {
+ count: Arc::new(AtomicUsize::new(0)),
+ };
- let inc = Arc::new(AtomicUsize::new(0));
-
- server::new(move || {
- let cloned = inc.clone();
- App::new().resource("/", move |r| r.h(MyHandler(cloned)))
+ HttpServer::new(move || {
+ App::new()
+ .data(data.clone())
+ .route("/", web::to(show_count))
+ .route("/add", web::to(add_one))
})
.bind("127.0.0.1:8088")
.unwrap()
- .start();
-
- println!("Started http server: 127.0.0.1:8088");
- let _ = sys.run();
+ .run()
+ .unwrap();
}
//
diff --git a/examples/request-handlers/src/main.rs b/examples/request-handlers/src/main.rs
index 8756e7d..48d7842 100644
--- a/examples/request-handlers/src/main.rs
+++ b/examples/request-handlers/src/main.rs
@@ -1,25 +1,38 @@
-mod handlers_arc;
-//
-use actix_web::{dev::Handler, server, App, HttpRequest, HttpResponse};
+pub mod handlers_arc;
+//
+use actix_web::{web, App, HttpServer, Responder};
use std::cell::Cell;
-struct MyHandler(Cell);
+#[derive(Clone)]
+struct AppState {
+ count: Cell,
+}
-impl Handler for MyHandler {
- type Result = HttpResponse;
+fn show_count(data: web::Data) -> impl Responder {
+ format!("count: {}", data.count.get())
+}
- /// Handle request
- fn handle(&self, _req: &HttpRequest) -> Self::Result {
- let i = self.0.get();
- self.0.set(i + 1);
- HttpResponse::Ok().into()
- }
+fn add_one(data: web::Data) -> impl Responder {
+ let count = data.count.get();
+ data.count.set(count + 1);
+
+ format!("count: {}", data.count.get())
}
fn main() {
- server::new(|| App::new().resource("/", |r| r.h(MyHandler(Cell::new(0))))) //use r.h() to bind handler, not the r.f()
- .bind("127.0.0.1:8088")
- .unwrap()
- .run();
+ let data = AppState {
+ count: Cell::new(0),
+ };
+
+ HttpServer::new(move || {
+ App::new()
+ .data(data.clone())
+ .route("/", web::to(show_count))
+ .route("/add", web::to(add_one))
+ })
+ .bind("127.0.0.1:8088")
+ .unwrap()
+ .run()
+ .unwrap();
}
-//
+//