diff --git a/guide/src/qs_10.md b/guide/src/qs_10.md index f7c49945..435e2966 100644 --- a/guide/src/qs_10.md +++ b/guide/src/qs_10.md @@ -1,8 +1,68 @@ # Middlewares +Actix middlewares system allows to add additional behaviour to request/response processing. +Middleware can hook into incomnig request process and modify request or halt request +processing and return response early. Also it can hook into response processing. + +Typically middlewares involves in following actions: + +* Pre-process the Request +* Post-process a Response +* Modify application state +* Access external services (redis, logging, sessions) + +Middlewares are registered for each application and get executed in same order as +registraton order. In general, *middleware* is a type that implements +[*Middleware trait*](../actix_web/middlewares/trait.Middleware.html). Each method +in this trait has default implementation. Each method can return result immidietly +or *future* object. + +Here is example of simple middleware that adds request and response headers: + +```rust +# extern crate http; +# extern crate actix_web; +use http::{header, HttpTryFrom}; +use actix_web::*; +use actix_web::middlewares::{Middleware, Started, Response}; + +struct Headers; // <- Our middleware + +/// Middleware implementation, middlewares are generic over application state, +/// so you can access state with `HttpRequest::state()` method. +impl Middleware for Headers { + + /// Method is called when request is ready. It may return + /// future, which should resolve before next middleware get called. + fn start(&self, req: &mut HttpRequest) -> Started { + req.headers_mut().insert( + header::CONTENT_TYPE, header::HeaderValue::from_static("text/plain")); + Started::Done + } + + /// Method is called when handler returns response, + /// but before sending http message to peer. + fn response(&self, req: &mut HttpRequest, mut resp: HttpResponse) -> Response { + resp.headers_mut().insert( + header::HeaderName::try_from("X-VERSION").unwrap(), + header::HeaderValue::from_static("0.2")); + Response::Done(resp) + } +} + +fn main() { + Application::new() + .middleware(Headers) // <- Register middleware, this method could be called multiple times + .resource("/", |r| r.h(httpcodes::HTTPOk)); +} +``` + +Active provides several useful middlewares, like *logging*, *user sessions*, etc. + + ## Logging -Logging is implemented as middleware. Middlewares get executed in same order as registraton order. +Logging is implemented as middleware. It is common to register logging middleware as first middleware for application. Logging middleware has to be registered for each application. diff --git a/guide/src/qs_14.md b/guide/src/qs_14.md index 0378c6b4..6c6fd1aa 100644 --- a/guide/src/qs_14.md +++ b/guide/src/qs_14.md @@ -8,7 +8,7 @@ Technically sync actors are worker style actors, multiple of them can be run in parallel and process messages from same queue (sync actors work in mpmc mode). Let's create simple db api that can insert new user row into sqlite table. -We need to define sync actor and connection that this actor will use. Same approach +We have to define sync actor and connection that this actor will use. Same approach could used for other databases. ```rust,ignore @@ -24,14 +24,11 @@ impl Actor for DbExecutor { This is definition of our actor. Now we need to define *create user* message and response. ```rust,ignore +#[derive(Message)] +#[rtype(User, Error)] struct CreateUser { name: String, } - -impl ResponseType for CreateUser { - type Item = models::User; - type Error = Error; -} ``` We can send `CreateUser` message to `DbExecutor` actor, and as result we can get @@ -68,11 +65,11 @@ impl Handler for DbExecutor { ``` That is it. Now we can use *DbExecutor* actor from any http handler or middleware. -All we need is to start *DbExecutor* actors and store address in state where http handler +All we need is to start *DbExecutor* actors and store address in a state where http handler can access it. ```rust,ignore -/// This is state where we sill store *DbExecutor* address. +/// This is state where we store *DbExecutor* address. struct State { db: SyncAddress, } @@ -97,7 +94,7 @@ fn main() { } ``` -And finally we can use this state in handler function. We get message response +And finally we can use this state in a requst handler. We get message response asynchronously, so handler needs to return future object, also `Route::a()` needs to be used for async handler registration.