diff --git a/guide/src/qs_4.md b/guide/src/qs_4.md new file mode 100644 index 000000000..969d01b8f --- /dev/null +++ b/guide/src/qs_4.md @@ -0,0 +1,143 @@ +# Handler + +A request handler can by any object that implements +[`Handler` trait](../actix_web/struct.HttpResponse.html#implementations). + +By default actix provdes several `Handler` implementations: + +* Simple function that accepts `HttpRequest` and returns any object that + can be converted to `HttpResponse` +* Function that accepts `HttpRequest` and returns `Result>` object. +* Function that accepts `HttpRequest` and return actor that has `HttpContext`as a context. + +Actix provides response conversion into `HttpResponse` for some standard types, +like `&'static str`, `String`, etc. +For complete list of implementations check +[HttpResponse documentation](../actix_web/struct.HttpResponse.html#implementations). + +Examples: + +```rust,ignore +fn index(req: HttpRequest) -> &'static str { + "Hello world!" +} +``` + +```rust,ignore +fn index(req: HttpRequest) -> String { + "Hello world!".to_owned() +} +``` + +```rust,ignore +fn index(req: HttpRequest) -> Bytes { + Bytes::from_static("Hello world!") +} +``` + +```rust,ignore +fn index(req: HttpRequest) -> Box> { + ... +} +``` + +## Custom conversion + +Let's create response for custom type that serializes to `application/json` response: + +```rust +extern crate actix; +extern crate actix_web; +extern crate serde; +extern crate serde_json; +#[macro_use] extern crate serde_derive; +use actix_web::*; + +#[derive(Serialize)] +struct MyObj { + name: String, +} + +/// we have to convert Error into HttpResponse as well, but with +/// specialization this could be handled genericly. +impl Into for MyObj { + fn into(self) -> HttpResponse { + let body = match serde_json::to_string(&self) { + Err(err) => return Error::from(err).into(), + Ok(body) => body, + }; + + // Create response and set content type + HttpResponse::Ok() + .content_type("application/json") + .body(body).unwrap() + } +} + +fn main() { + let sys = actix::System::new("example"); + + HttpServer::new( + Application::default("/") + .resource("/", |r| r.handler( + Method::GET, |req| {MyObj{name: "user".to_owned()}}))) + .serve::<_, ()>("127.0.0.1:8088").unwrap(); + + println!("Started http server: 127.0.0.1:8088"); + actix::Arbiter::system().send(actix::msgs::SystemExit(0)); // <- remove this line, this code stops system during testing + + let _ = sys.run(); +} +``` + +If `specialization` is enabled, conversion could be simplier: + +```rust,ignore +impl Into> for MyObj { + fn into(self) -> Result { + let body = serde_json::to_string(&self)?; + + Ok(HttpResponse::Ok() + .content_type("application/json") + .body(body)?) + } +} +``` + +## Async handlers + +There are two different types of async handlers. + +Response object could be generated asynchronously. In this case handle must +return `Future` object that resolves to `HttpResponse`, i.e: + +```rust,ignore +fn index(req: HttpRequest) -> Box> { + ... +} +``` + +This handler can be registered with `ApplicationBuilder::async()` and +`Resource::async()` methods. + +Or response body can be generated asynchronously. In this case body +must implement stream trait `Stream`, i.e: + + +```rust,ignore +fn index(req: HttpRequest) -> HttpResponse { + let body: Box> = Box::new(SomeStream::new()); + + HttpResponse::Ok(). + .content_type("application/json") + .body(Body::Streaming(body)).unwrap() +} + +fn main() { + Application::default("/") + .async("/async", index) + .finish(); +} +``` + +Both methods could be combined. (i.e Async response with streaming body) diff --git a/guide/src/qs_5.md b/guide/src/qs_5.md new file mode 100644 index 000000000..157b55c57 --- /dev/null +++ b/guide/src/qs_5.md @@ -0,0 +1,107 @@ +# Resources and Routes + +All resources and routes register for specific application. +Application routes incoming requests based on route criteria which is defined during +resource registration or path prefix for simple handlers. +Internally *router* is a list of *resources*. Resource is an entry in *route table* +which corresponds to requested URL. + +Prefix handler: + +```rust,ignore +fn index(req: Httprequest) -> HttpResponse { + ... +} + +fn main() { + Application::default("/") + .handler("/prefix", |req| index) + .finish(); +} +``` + +In this example `index` get called for any url which starts with `/prefix`. + +Application prefix combines with handler prefix i.e + +```rust,ignore +fn main() { + Application::default("/app") + .handler("/prefix", |req| index) + .finish(); +} +``` + +In this example `index` get called for any url which starts with`/app/prefix`. + +Resource contains set of route for same endpoint. Route corresponds to handling +*HTTP method* by calling *web handler*. Resource select route based on *http method*, +if no route could be matched default response `HTTPMethodNotAllowed` get resturned. + +```rust,ignore +fn main() { + Application::default("/") + .resource("/prefix", |r| { + r.get(HTTPOk) + r.post(HTTPForbidden) + }) + .finish(); +} +``` + +[`ApplicationBuilder::resource()` method](../actix_web/dev/struct.ApplicationBuilder.html#method.resource) +accepts configuration function, resource could be configured at once. +Check [`Resource`](../actix-web/target/doc/actix_web/struct.Resource.html) documentation +for more information. + +## Variable resources + +Resource may have *variable path*also. For instance, a resource with the +path '/a/{name}/c' would match all incoming requests with paths such +as '/a/b/c', '/a/1/c', and '/a/etc/c'. + +A *variable part*is specified in the form {identifier}, where the identifier can be +used later in a request handler to access the matched value for that part. This is +done by looking up the identifier in the `HttpRequest.match_info` object: + + +```rust +extern crate actix; +use actix_web::*; + +fn index(req: Httprequest) -> String { + format!("Hello, {}", req.match_info.get('name').unwrap()) +} + +fn main() { + Application::default("/") + .resource("/{name}", |r| r.get(index)) + .finish(); +} +``` + +By default, each part matches the regular expression `[^{}/]+`. + +You can also specify a custom regex in the form `{identifier:regex}`: + +```rust,ignore +fn main() { + Application::default("/") + .resource(r"{name:\d+}", |r| r.get(index)) + .finish(); +} +``` + +To match path tail, `{tail:*}` pattern could be used. Tail pattern has to be last +segment in path otherwise it panics. + +```rust,ignore +fn main() { + Application::default("/") + .resource(r"/test/{tail:*}", |r| r.get(index)) + .finish(); +} +``` + +Above example would match all incoming requests with path such as +'/test/b/c', '/test/index.html', and '/test/etc/test'. diff --git a/guide/src/qs_6.md b/guide/src/qs_6.md new file mode 100644 index 000000000..8060e455a --- /dev/null +++ b/guide/src/qs_6.md @@ -0,0 +1,36 @@ +# Application state + +Application state is shared with all routes within same application. +State could be accessed with `HttpRequest::state()` method. It is read-only +but interior mutability pattern with `RefCell` could be used to archive state mutability. +State could be accessed with `HttpRequest::state()` method or +`HttpContext::state()` in case of http actor. + +Let's write simple application that uses shared state. We are going to store requests count +in the state: + +```rust +extern crate actix; +extern crate actix_web; + +use std::cell::Cell; +use actix_web::*; + +// This struct represents state +struct AppState { + counter: Cell, +} + +fn index(req: HttpRequest) -> String { + let count = req.state().counter.get() + 1; // <- get count + req.state().counter.set(count); // <- store new count in state + + format!("Request number: {}", count) // <- response with count +} + +fn main() { + Application::build("/", AppState{counter: Cell::new(0)}) + .resource("/", |r| r.handler(Method::GET, index)) + .finish(); +} +```