1
0
mirror of https://github.com/actix/actix-website synced 2024-11-27 18:12:57 +01:00

Intro: done-ish. Getting Started: done-ish. Application: done-ish.

This commit is contained in:
Cameron Dershem 2019-06-19 18:00:31 -04:00
parent da969fed1f
commit ea7bc84f8d
11 changed files with 145 additions and 66 deletions

View File

@ -10,16 +10,16 @@ weight: 140
It provides routing, middlewares, pre-processing of requests, post-processing of It provides routing, middlewares, pre-processing of requests, post-processing of
responses, etc. 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 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 An application's `scope` acts as a namespace for all routes, i.e. all routes for a
have the same url path prefix. The application prefix always contains a leading "/" slash. specific application scope have the same url path prefix. The application prefix always
If a supplied prefix does not contain leading slash, it is automatically inserted. contains a leading "/" slash. If a supplied prefix does not contain leading slash,
The prefix should consist of value path segments. 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; > any request with the paths `/app`, `/app/`, or `/app/test` would match;
> however, the path `/application` would not 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 > For more information, check the
> [URL Dispatch](/docs/url-dispatch/index.html#using-an-application-prefix-to-compose-applications) section. > [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. 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 **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 ## State
Application state is shared with all routes and resources within the same application. Application state is shared with all routes and resources within the same scope. State
When using an http actor, state can be accessed with the `HttpRequest::state()` as read-only, can be accessed with `web::Data<State>` as read-only, but interior mutability with
but interior mutability with `RefCell` can be used to achieve state mutability. `Cell` can be used to achieve state mutability. State is also available for route
State is also available for route matching predicates and middlewares. matching guards and middlewares.
Let's write a simple application that uses shared state. We are going to store request count Let's write a simple application that uses shared state. We are going to store request count
in the state: 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" >}} {{< include-example example="application" file="state.rs" section="make_app" >}}
> **Note**: http server accepts an application factory rather than an application > **Note**: `HttpServer` accepts an application factory rather than an application
> instance. Http server constructs an application instance for each thread, thus application state > instance. `HttpServer` constructs an application instance for each thread, thus
> must be constructed multiple times. If you want to share state between different threads, a > application state must be constructed multiple times. If you want to share state between
> 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`, > 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`. > but the application factory must be `Send` + `Sync`.
To start the previous app, create it into a closure: 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. 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" >}} {{< include-example example="application" file="combine.rs" section="combine" >}}
## Using an Application Scope to Compose Applications ## Using an Application Scope to Compose Applications
@ -87,7 +85,7 @@ resource names.
For example: 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 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 */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 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 and returns *true* or *false*. Formally, a guard is any object that implements the
[`Guard`](../actix_web/guard/trait.Guard.html) trait. Actix provides [`Guard`](https://docs.rs/actix-web/1.0.2/actix_web/guard/trait.Guard.html) trait. Actix-web
several guards, you can check provides several guards, you can check
[functions section](../../actix-web/actix_web/guard/index.html#functions) of api docs. [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 One of the provided guards is [`Header`](https://docs.rs/actix-web/1.0.2/actix_web/guard/fn.Header.html),
as application's filter based on request's host information. it can be used as application's filter based on request's header information.
{{< include-example example="application" file="vh.rs" section="vh" >}} {{< 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`

View File

@ -6,7 +6,7 @@ weight: 130
# Getting Started # Getting Started
Lets write our first actix web application! Lets write our first `actix-web` application!
## Hello, world! ## 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. 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 A request handler is a function that accepts zero or more parameters that can be
request (ie, `impl FromRequest`) as its only parameter and returns a type that extracted from a request (ie, `impl FromRequest`) and returns a type that can be
can be converted into an `HttpResponse` (ie, `impl Responder`): converted into an `HttpResponse` (ie, `impl Responder`):
{{< include-example example="getting-started" section="setup" >}} {{< include-example example="getting-started" section="setup" >}}
Next, create an `App` instance and register the request handler with Next, create an `App` instance and register the request handler with the application's
the application's `route` on a particular *HTTP method* and *path* and `route` on a *path* and with a particular *HTTP method*. After that, the application
after that, the application instance can be used with `HttpServer` to listen instance can be used with `HttpServer` to listen for incoming connections. The server
for incoming connections. The server accepts a function that should return an accepts a function that should return an application factory.
application factory.
{{< include-example example="getting-started" section="main" >}} {{< include-example example="getting-started" section="main" >}}

View File

@ -6,7 +6,7 @@ weight: 150
# The HTTP Server # 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. serving http requests.
`HttpServer` accepts an application factory as a parameter, and the `HttpServer` accepts an application factory as a parameter, and the

View File

@ -5,7 +5,10 @@ fn index(_req: HttpRequest) -> impl Responder {
"Hello world!" "Hello world!"
} }
#[rustfmt::skip]
pub fn main() { 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)));
} }
// </setup> // </setup>

View File

@ -8,13 +8,13 @@ struct State2;
pub fn main() { pub fn main() {
HttpServer::new(|| { HttpServer::new(|| {
App::new() App::new()
.data(State1)
.data(State2)
.service( .service(
web::scope("/app1") web::scope("/app1")
.data(State1)
.route("/", web::to(|| HttpResponse::Ok()))) .route("/", web::to(|| HttpResponse::Ok())))
.service( .service(
web::scope("/app2") web::scope("/app2")
.data(State2)
.route("/", web::to(|| HttpResponse::Ok()))) .route("/", web::to(|| HttpResponse::Ok())))
}) })
.bind("127.0.0.1:8088") .bind("127.0.0.1:8088")

View File

@ -0,0 +1,34 @@
// <config>
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();
}
// </config>

View File

@ -1,22 +1,22 @@
use actix_web::{web, App, HttpResponse, HttpServer}; use actix_web::{web, App, HttpResponse};
pub mod app; pub mod app;
pub mod combine; pub mod combine;
pub mod config;
pub mod scope;
pub mod state; pub mod state;
pub mod vh; pub mod vh;
#[rustfmt::skip] #[rustfmt::skip]
// <run_server> // <multi>
fn main() { fn main() {
HttpServer::new(|| { App::new()
App::new() .service(
.service( web::scope("/app1")
web::scope("/app1") .route("/", web::to(|| HttpResponse::Ok())))
.route("/", web::to(|| HttpResponse::Ok()))) .service(
.service( web::scope("/app2")
web::scope("/app2") .route("/", web::to(|| HttpResponse::Ok())))
.route("/", web::to(|| HttpResponse::Ok()))) .route("/", web::to(|| HttpResponse::Ok()));
.route("/", web::to(|| HttpResponse::Ok()))
});
} }
// </run_server> // </multi>

View File

@ -0,0 +1,15 @@
use actix_web::{web, App, HttpRequest, Responder};
fn show_users(_req: HttpRequest) -> impl Responder {
unimplemented!()
}
#[rustfmt::skip]
// <scope>
pub fn main() {
App::new()
.service(
web::scope("/users")
.route("/show", web::get().to(show_users)));
}
// </scope>

View File

@ -4,7 +4,7 @@ use std::cell::Cell;
// This struct represents state // This struct represents state
struct AppState { struct AppState {
counter: Cell<usize>, counter: Cell<i32>,
} }
fn index(data: web::Data<AppState>) -> String { fn index(data: web::Data<AppState>) -> String {

View File

@ -1,22 +1,24 @@
#![allow(unused)] use actix_web::{guard, web, App, HttpResponse, HttpServer};
use actix_web::{guard, web, App, HttpRequest, HttpResponse, HttpServer, Responder};
// <vh> // <vh>
fn main() { pub fn main() {
HttpServer::new(|| { HttpServer::new(|| {
App::new() App::new()
.service( .service(
web::scope("/") web::scope("/")
.guard(guard::Header("Host", "www.rust-lang.org")) .guard(guard::Header("Host", "www.rust-lang.org"))
.route("", web::to(|| HttpResponse::Ok())), .route("", web::to(|| HttpResponse::Ok().body("www"))),
) )
.service( .service(
web::scope("/") web::scope("/")
.guard(guard::Header("Host", "users.rust-lang.org")) .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())) .route("/", web::to(|| HttpResponse::Ok()))
}) })
.run(); .bind("127.0.0.1:8088")
.unwrap()
.run()
.unwrap();
} }
// </vh> // </vh>

View File

@ -1,17 +1,25 @@
// <setup> // <setup>
use actix_web::{web, App, HttpRequest, HttpResponse, HttpServer, Responder}; use actix_web::{web, App, HttpRequest, HttpResponse, HttpServer, Responder};
fn index(_req: HttpRequest) -> impl Responder { fn index() -> impl Responder {
HttpResponse::Ok().body("Hello world!") HttpResponse::Ok().body("Hello world!")
} }
fn index2(_req: HttpRequest) -> impl Responder {
HttpResponse::Ok().body("Hello world again!")
}
// </setup> // </setup>
// <main> // <main>
fn main() { fn main() {
HttpServer::new(|| App::new().route("/", web::get().to(index))) HttpServer::new(|| {
.bind("127.0.0.1:8088") App::new()
.unwrap() .route("/", web::get().to(index))
.run() .route("/again", web::get().to(index2))
.unwrap(); })
.bind("127.0.0.1:8088")
.unwrap()
.run()
.unwrap();
} }
// </main> // </main>