diff --git a/content/docs/application.md b/content/docs/application.md index 68f2aad..80eb660 100644 --- a/content/docs/application.md +++ b/content/docs/application.md @@ -10,16 +10,16 @@ weight: 140 It provides routing, middlewares, pre-processing of requests, post-processing of responses, etc. -All actix web servers are built around the `App` instance. It is used for +All `actix-web` servers are built around the `App` instance. It is used for registering routes for resources and middlewares. It also stores application -state shared across all handlers within same application. +state shared across all handlers within same scope. -Applications act as a namespace for all routes, i.e. all routes for a specific application -have the same url path prefix. The application prefix always contains a leading "/" slash. -If a supplied prefix does not contain leading slash, it is automatically inserted. -The prefix should consist of value path segments. +An application's `scope` acts as a namespace for all routes, i.e. all routes for a +specific application scope have the same url path prefix. The application prefix always +contains a leading "/" slash. If a supplied prefix does not contain leading slash, +it is automatically inserted. The prefix should consist of value path segments. -> For an application with prefix `/app`, +> For an application with scope `/app`, > any request with the paths `/app`, `/app/`, or `/app/test` would match; > however, the path `/application` would not match. @@ -31,9 +31,9 @@ are created. This resource is available through the `/app/index.html` url. > For more information, check the > [URL Dispatch](/docs/url-dispatch/index.html#using-an-application-prefix-to-compose-applications) section. -Multiple applications can be served with one server: +Multiple application scopes can be served with one server: -{{< include-example example="application" file="main.rs" section="run_server" >}} +{{< include-example example="application" file="main.rs" section="multi" >}} All `/app1` requests route to the first application, `/app2` to the second, and all other to the third. **Applications get matched based on registration order**. If an application with a more generic @@ -43,10 +43,10 @@ as the first application, it would match all incoming requests. ## State -Application state is shared with all routes and resources within the same application. -When using an http actor, state can be accessed with the `HttpRequest::state()` as read-only, -but interior mutability with `RefCell` can be used to achieve state mutability. -State is also available for route matching predicates and middlewares. +Application state is shared with all routes and resources within the same scope. State +can be accessed with `web::Data` as read-only, but interior mutability with +`Cell` can be used to achieve state mutability. State is also available for route +matching guards and middlewares. Let's write a simple application that uses shared state. We are going to store request count in the state: @@ -57,10 +57,12 @@ When the app is initialized it needs to be passed the initial state: {{< include-example example="application" file="state.rs" section="make_app" >}} -> **Note**: http server accepts an application factory rather than an application -> instance. Http server constructs an application instance for each thread, thus application state -> must be constructed multiple times. If you want to share state between different threads, a -> shared object should be used, e.g. `Arc`. There is also an [Example](https://github.com/actix/examples/blob/master/state/src/main.rs) using `Arc` for this. Application state does not need to be `Send` and `Sync`, +> **Note**: `HttpServer` accepts an application factory rather than an application +> instance. `HttpServer` constructs an application instance for each thread, thus +> application state must be constructed multiple times. If you want to share state between +> different threads, a shared object should be used, e.g. `Arc`. There is also an +> [Example](https://github.com/actix/examples/blob/master/state/src/main.rs) using `Arc` +> for this. Application state does not need to be `Send` and `Sync`, > but the application factory must be `Send` + `Sync`. To start the previous app, create it into a closure: @@ -71,10 +73,6 @@ To start the previous app, create it into a closure: Combining multiple applications with different state is possible as well. -[server::new](https://docs.rs/actix-web/*/actix_web/server/fn.new.html) requires the handler to have a single type. - -This limitation can easily be overcome with the [App::boxed](https://docs.rs/actix-web/*/actix_web/struct.App.html#method.boxed) method, which converts an App into a boxed trait object. - {{< include-example example="application" file="combine.rs" section="combine" >}} ## Using an Application Scope to Compose Applications @@ -87,7 +85,7 @@ resource names. For example: -{{< include-example example="url-dispatch" file="scope.rs" section="scope" >}} +{{< include-example example="application" file="scope.rs" section="scope" >}} In the above example, the *show_users* route will have an effective route pattern of */users/show* instead of */show* because the application's scope argument will be prepended @@ -99,11 +97,31 @@ it will generate a URL with that same path. You can think of a guard as a simple function that accepts a *request* object reference and returns *true* or *false*. Formally, a guard is any object that implements the -[`Guard`](../actix_web/guard/trait.Guard.html) trait. Actix provides -several guards, you can check -[functions section](../../actix-web/actix_web/guard/index.html#functions) of api docs. +[`Guard`](https://docs.rs/actix-web/1.0.2/actix_web/guard/trait.Guard.html) trait. Actix-web +provides several guards, you can check +[functions section](https://docs.rs/actix-web/1.0.2/actix_web/guard/index.html#functions) +of api docs. -One of the provided guards is [`Host`](../actix_web/guard/fn.Host.html), it can be used -as application's filter based on request's host information. +One of the provided guards is [`Header`](https://docs.rs/actix-web/1.0.2/actix_web/guard/fn.Header.html), +it can be used as application's filter based on request's header information. {{< include-example example="application" file="vh.rs" section="vh" >}} + +# Configure + +For simplicity and reusability both `App` and `web::scope` provide the `configure` method. +This function is useful for moving parts of configuration to a different module or even +library. For example, some of the resource's configuration could be moved to different +module. + +{{< include-example example="application" file="config.rs" section="config" >}} + +The result of the above example would be: + +``` +/ -> "/" +/app -> "app" +/api/test -> "test" +``` + +Each `ServiceConfig` can have it's own `data`, `routes`, and `services` diff --git a/content/docs/getting-started.md b/content/docs/getting-started.md index 042a1ac..a4fe727 100644 --- a/content/docs/getting-started.md +++ b/content/docs/getting-started.md @@ -6,7 +6,7 @@ weight: 130 # Getting Started -Let’s write our first actix web application! +Let’s write our first `actix-web` application! ## Hello, world! @@ -27,17 +27,16 @@ actix-web = "{{< actix-version "actix-web" >}}" In order to implement a web server, we first need to create a request handler. -A request handler is a function that accepts any type that can be extracted from a -request (ie, `impl FromRequest`) as its only parameter and returns a type that -can be converted into an `HttpResponse` (ie, `impl Responder`): +A request handler is a function that accepts zero or more parameters that can be +extracted from a request (ie, `impl FromRequest`) and returns a type that can be +converted into an `HttpResponse` (ie, `impl Responder`): {{< include-example example="getting-started" section="setup" >}} -Next, create an `App` instance and register the request handler with -the application's `route` on a particular *HTTP method* and *path* and -after that, the application instance can be used with `HttpServer` to listen -for incoming connections. The server accepts a function that should return an -application factory. +Next, create an `App` instance and register the request handler with the application's +`route` on a *path* and with a particular *HTTP method*. After that, the application +instance can be used with `HttpServer` to listen for incoming connections. The server +accepts a function that should return an application factory. {{< include-example example="getting-started" section="main" >}} diff --git a/content/docs/server.md b/content/docs/server.md index 614411f..2208dca 100644 --- a/content/docs/server.md +++ b/content/docs/server.md @@ -6,7 +6,7 @@ weight: 150 # The HTTP Server -The [**HttpServer**](../../actix-web/actix_web/server/struct.HttpServer.html) type is responsible for +The [**HttpServer**](https://docs.rs/actix-web/1.0.2/actix_web/struct.HttpServer.html) type is responsible for serving http requests. `HttpServer` accepts an application factory as a parameter, and the diff --git a/examples/application/src/app.rs b/examples/application/src/app.rs index 375c2a3..1f53cd3 100644 --- a/examples/application/src/app.rs +++ b/examples/application/src/app.rs @@ -5,7 +5,10 @@ fn index(_req: HttpRequest) -> impl Responder { "Hello world!" } +#[rustfmt::skip] pub fn main() { - App::new().service(web::scope("/app").route("/index.html", web::get().to(index))); + App::new().service( + web::scope("/app") + .route("/index.html", web::get().to(index))); } // diff --git a/examples/application/src/combine.rs b/examples/application/src/combine.rs index 1057f68..0ce5a88 100644 --- a/examples/application/src/combine.rs +++ b/examples/application/src/combine.rs @@ -8,13 +8,13 @@ struct State2; pub fn main() { HttpServer::new(|| { App::new() - .data(State1) - .data(State2) .service( web::scope("/app1") + .data(State1) .route("/", web::to(|| HttpResponse::Ok()))) .service( web::scope("/app2") + .data(State2) .route("/", web::to(|| HttpResponse::Ok()))) }) .bind("127.0.0.1:8088") diff --git a/examples/application/src/config.rs b/examples/application/src/config.rs new file mode 100644 index 0000000..6d1b9a3 --- /dev/null +++ b/examples/application/src/config.rs @@ -0,0 +1,34 @@ +// +use actix_web::{web, App, HttpResponse, HttpServer}; + +// this function could be located in different module +fn scoped_config(cfg: &mut web::ServiceConfig) { + cfg.service( + web::resource("/test") + .route(web::get().to(|| HttpResponse::Ok().body("test"))) + .route(web::head().to(|| HttpResponse::MethodNotAllowed())), + ); +} + +// this function could be located in different module +fn config(cfg: &mut web::ServiceConfig) { + cfg.service( + web::resource("/app") + .route(web::get().to(|| HttpResponse::Ok().body("app"))) + .route(web::head().to(|| HttpResponse::MethodNotAllowed())), + ); +} + +pub fn main() { + HttpServer::new(|| { + App::new() + .configure(config) + .service(web::scope("/api").configure(scoped_config)) + .route("/", web::get().to(|| HttpResponse::Ok().body("/"))) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); +} +// diff --git a/examples/application/src/main.rs b/examples/application/src/main.rs index be51f1d..a8fe4e1 100644 --- a/examples/application/src/main.rs +++ b/examples/application/src/main.rs @@ -1,22 +1,22 @@ -use actix_web::{web, App, HttpResponse, HttpServer}; +use actix_web::{web, App, HttpResponse}; pub mod app; pub mod combine; +pub mod config; +pub mod scope; pub mod state; pub mod vh; #[rustfmt::skip] -// +// fn main() { - HttpServer::new(|| { - App::new() - .service( - web::scope("/app1") - .route("/", web::to(|| HttpResponse::Ok()))) - .service( - web::scope("/app2") - .route("/", web::to(|| HttpResponse::Ok()))) - .route("/", web::to(|| HttpResponse::Ok())) - }); + App::new() + .service( + web::scope("/app1") + .route("/", web::to(|| HttpResponse::Ok()))) + .service( + web::scope("/app2") + .route("/", web::to(|| HttpResponse::Ok()))) + .route("/", web::to(|| HttpResponse::Ok())); } -// +// diff --git a/examples/application/src/scope.rs b/examples/application/src/scope.rs new file mode 100644 index 0000000..b9c5742 --- /dev/null +++ b/examples/application/src/scope.rs @@ -0,0 +1,15 @@ +use actix_web::{web, App, HttpRequest, Responder}; + +fn show_users(_req: HttpRequest) -> impl Responder { + unimplemented!() +} + +#[rustfmt::skip] +// +pub fn main() { + App::new() + .service( + web::scope("/users") + .route("/show", web::get().to(show_users))); +} +// diff --git a/examples/application/src/state.rs b/examples/application/src/state.rs index 9944412..6f5c278 100644 --- a/examples/application/src/state.rs +++ b/examples/application/src/state.rs @@ -4,7 +4,7 @@ use std::cell::Cell; // This struct represents state struct AppState { - counter: Cell, + counter: Cell, } fn index(data: web::Data) -> String { diff --git a/examples/application/src/vh.rs b/examples/application/src/vh.rs index 88f60bd..bd8e34e 100644 --- a/examples/application/src/vh.rs +++ b/examples/application/src/vh.rs @@ -1,22 +1,24 @@ -#![allow(unused)] -use actix_web::{guard, web, App, HttpRequest, HttpResponse, HttpServer, Responder}; +use actix_web::{guard, web, App, HttpResponse, HttpServer}; // -fn main() { +pub fn main() { HttpServer::new(|| { App::new() .service( web::scope("/") .guard(guard::Header("Host", "www.rust-lang.org")) - .route("", web::to(|| HttpResponse::Ok())), + .route("", web::to(|| HttpResponse::Ok().body("www"))), ) .service( web::scope("/") .guard(guard::Header("Host", "users.rust-lang.org")) - .route("", web::to(|| HttpResponse::Ok())), + .route("", web::to(|| HttpResponse::Ok().body("user"))), ) .route("/", web::to(|| HttpResponse::Ok())) }) - .run(); + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // diff --git a/examples/getting-started/src/main.rs b/examples/getting-started/src/main.rs index f3f4186..821e428 100644 --- a/examples/getting-started/src/main.rs +++ b/examples/getting-started/src/main.rs @@ -1,17 +1,25 @@ // use actix_web::{web, App, HttpRequest, HttpResponse, HttpServer, Responder}; -fn index(_req: HttpRequest) -> impl Responder { +fn index() -> impl Responder { HttpResponse::Ok().body("Hello world!") } + +fn index2(_req: HttpRequest) -> impl Responder { + HttpResponse::Ok().body("Hello world again!") +} // //
fn main() { - HttpServer::new(|| App::new().route("/", web::get().to(index))) - .bind("127.0.0.1:8088") - .unwrap() - .run() - .unwrap(); + HttpServer::new(|| { + App::new() + .route("/", web::get().to(index)) + .route("/again", web::get().to(index2)) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } //