1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-11-24 07:53:00 +01:00

move guide to separate repo; update links

This commit is contained in:
Nikolay Kim 2018-04-13 16:20:23 -07:00
parent 113f5ad1a8
commit a8567da3e2
19 changed files with 7 additions and 2679 deletions

View File

@ -33,27 +33,12 @@ before_install:
# Add clippy
before_script:
- |
if [[ "$TRAVIS_RUST_VERSION" == "nightly" ]]; then
( ( cargo install clippy && export CLIPPY=true ) || export CLIPPY=false );
fi
- export PATH=$PATH:~/.cargo/bin
script:
- |
if [[ "$TRAVIS_RUST_VERSION" == "stable" ]]; then
cargo clean
USE_SKEPTIC=1 cargo test --features=alpn
else
cargo clean
cargo test -- --nocapture
# --features=alpn
fi
- |
if [[ "$TRAVIS_RUST_VERSION" == "nightly" && $CLIPPY ]]; then
cargo clippy
fi
cargo clean
cargo test --features="alpn,tls" -- --nocapture
# Upload docs
after_success:
@ -61,8 +46,6 @@ after_success:
if [[ "$TRAVIS_OS_NAME" == "linux" && "$TRAVIS_PULL_REQUEST" = "false" && "$TRAVIS_BRANCH" == "master" && "$TRAVIS_RUST_VERSION" == "beta" ]]; then
cargo doc --features "alpn, tls, session" --no-deps &&
echo "<meta http-equiv=refresh content=0;url=os_balloon/index.html>" > target/doc/index.html &&
curl -sL https://github.com/rust-lang-nursery/mdBook/releases/download/v0.1.2/mdbook-v0.1.2-x86_64-unknown-linux-gnu.tar.gz | tar xvz -C $HOME/.cargo/bin &&
cd guide && mdbook build -d ../target/doc/guide && cd .. &&
git clone https://github.com/davisp/ghp-import.git &&
./ghp-import/ghp_import.py -n -p -f -m "Documentation upload" -r https://"$GH_TOKEN"@github.com/"$TRAVIS_REPO_SLUG.git" target/doc &&
echo "Uploaded documentation"

View File

@ -12,17 +12,17 @@ Actix web is a simple, pragmatic and extremely fast web framework for Rust.
* Multipart streams
* Static assets
* SSL support with OpenSSL or `native-tls`
* Middlewares ([Logger](https://actix.rs/actix-web/guide/qs_10.html#logging),
[Session](https://actix.rs/actix-web/guide/qs_10.html#user-sessions),
* Middlewares ([Logger](https://actix.rs/book/actix-web/sec-9-middlewares.html#logging),
[Session](https://actix.rs/book/actix-web/sec-9-middlewares.html#user-sessions),
[Redis sessions](https://github.com/actix/actix-redis),
[DefaultHeaders](https://actix.rs/actix-web/guide/qs_10.html#default-headers),
[DefaultHeaders](https://actix.rs/book/actix-web/sec-9-middlewares.html#default-headers),
[CORS](https://actix.rs/actix-web/actix_web/middleware/cors/index.html),
[CSRF](https://actix.rs/actix-web/actix_web/middleware/csrf/index.html))
* Built on top of [Actix actor framework](https://github.com/actix/actix)
## Documentation & community resources
* [User Guide](https://actix.rs/actix-web/guide/)
* [User Guide](https://actix.rs/book/actix-web/)
* [API Documentation (Development)](https://actix.rs/actix-web/actix_web/)
* [API Documentation (Releases)](https://docs.rs/actix-web/)
* [Chat on gitter](https://gitter.im/actix/actix)

View File

@ -1,7 +0,0 @@
[book]
title = "Actix web"
description = "Actix web framework guide"
author = "Actix Project and Contributors"
[output.html]
google-analytics = "UA-110322332-1"

View File

@ -1,16 +0,0 @@
# Summary
[Quickstart](./qs_1.md)
- [Getting Started](./qs_2.md)
- [Application](./qs_3.md)
- [Server](./qs_3_5.md)
- [Handler](./qs_4.md)
- [Errors](./qs_4_5.md)
- [URL Dispatch](./qs_5.md)
- [Request & Response](./qs_7.md)
- [Testing](./qs_8.md)
- [Middlewares](./qs_10.md)
- [Static file handling](./qs_12.md)
- [WebSockets](./qs_9.md)
- [HTTP/2](./qs_13.md)
- [Database integration](./qs_14.md)

View File

@ -1,32 +0,0 @@
# Quick start
## Install Rust
Before we begin, we need to install Rust using [rustup](https://www.rustup.rs/):
```bash
curl https://sh.rustup.rs -sSf | sh
```
If you already have rustup installed, run this command to ensure you have the latest version of Rust:
```bash
rustup update
```
Actix web framework requires rust version 1.21 and up.
## Running Examples
The fastest way to start experimenting with actix web is to clone the
[repository](https://github.com/actix/actix-web) and run the included examples.
The following set of commands runs the `basics` example:
```bash
git clone https://github.com/actix/example
cd examples/basics
cargo run
```
Check [examples/](https://github.com/actix/examples/tree/master/) directory for more examples.

View File

@ -1,251 +0,0 @@
# Middleware
Actix's middleware system allows us to add additional behavior to request/response processing.
Middleware can hook into an incoming request process, enabling us to modify requests
as well as halt request processing to return a response early.
Middleware can also hook into response processing.
Typically, middleware is involved in the following actions:
* Pre-process the Request
* Post-process a Response
* Modify application state
* Access external services (redis, logging, sessions)
Middleware is registered for each application and executed in same order as
registration. In general, a *middleware* is a type that implements the
[*Middleware trait*](../actix_web/middlewares/trait.Middleware.html). Each method
in this trait has a default implementation. Each method can return a result immediately
or a *future* object.
The following demonstrates using middleware to add request and response headers:
```rust
# extern crate http;
# extern crate actix_web;
use http::{header, HttpTryFrom};
use actix_web::{App, HttpRequest, HttpResponse, Result};
use actix_web::middleware::{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<S> Middleware<S> 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<S>) -> Result<Started> {
req.headers_mut().insert(
header::CONTENT_TYPE, header::HeaderValue::from_static("text/plain"));
Ok(Started::Done)
}
/// Method is called when handler returns response,
/// but before sending http message to peer.
fn response(&self, req: &mut HttpRequest<S>, mut resp: HttpResponse) -> Result<Response> {
resp.headers_mut().insert(
header::HeaderName::try_from("X-VERSION").unwrap(),
header::HeaderValue::from_static("0.2"));
Ok(Response::Done(resp))
}
}
fn main() {
App::new()
.middleware(Headers) // <- Register middleware, this method can be called multiple times
.resource("/", |r| r.f(|_| HttpResponse::Ok()));
}
```
> Actix provides several useful middlewares, such as *logging*, *user sessions*, etc.
## Logging
Logging is implemented as a middleware.
It is common to register a logging middleware as the first middleware for the application.
Logging middleware must be registered for each application.
The `Logger` middleware uses the standard log crate to log information. You should enable logger
for *actix_web* package to see access log ([env_logger](https://docs.rs/env_logger/*/env_logger/)
or similar).
### Usage
Create `Logger` middleware with the specified `format`.
Default `Logger` can be created with `default` method, it uses the default format:
```ignore
%a %t "%r" %s %b "%{Referer}i" "%{User-Agent}i" %T
```
```rust
# extern crate actix_web;
extern crate env_logger;
use actix_web::App;
use actix_web::middleware::Logger;
fn main() {
std::env::set_var("RUST_LOG", "actix_web=info");
env_logger::init();
App::new()
.middleware(Logger::default())
.middleware(Logger::new("%a %{User-Agent}i"))
.finish();
}
```
The following is an example of the default logging format:
```
INFO:actix_web::middleware::logger: 127.0.0.1:59934 [02/Dec/2017:00:21:43 -0800] "GET / HTTP/1.1" 302 0 "-" "curl/7.54.0" 0.000397
INFO:actix_web::middleware::logger: 127.0.0.1:59947 [02/Dec/2017:00:22:40 -0800] "GET /index.html HTTP/1.1" 200 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:57.0) Gecko/20100101 Firefox/57.0" 0.000646
```
### Format
`%%` The percent sign
`%a` Remote IP-address (IP-address of proxy if using reverse proxy)
`%t` Time when the request was started to process
`%P` The process ID of the child that serviced the request
`%r` First line of request
`%s` Response status code
`%b` Size of response in bytes, including HTTP headers
`%T` Time taken to serve the request, in seconds with floating fraction in .06f format
`%D` Time taken to serve the request, in milliseconds
`%{FOO}i` request.headers['FOO']
`%{FOO}o` response.headers['FOO']
`%{FOO}e` os.environ['FOO']
## Default headers
To set default response headers, the `DefaultHeaders` middleware can be used. The
*DefaultHeaders* middleware does not set the header if response headers already contain
a specified header.
```rust
# extern crate actix_web;
use actix_web::{http, middleware, App, HttpResponse};
fn main() {
let app = App::new()
.middleware(
middleware::DefaultHeaders::new()
.header("X-Version", "0.2"))
.resource("/test", |r| {
r.method(http::Method::GET).f(|req| HttpResponse::Ok());
r.method(http::Method::HEAD).f(|req| HttpResponse::MethodNotAllowed());
})
.finish();
}
```
## User sessions
Actix provides a general solution for session management. The
[**SessionStorage**](../actix_web/middleware/struct.SessionStorage.html) middleware can be
used with different backend types to store session data in different backends.
> By default, only cookie session backend is implemented. Other backend implementations
> can be added.
[**CookieSessionBackend**](../actix_web/middleware/struct.CookieSessionBackend.html)
uses cookies as session storage. `CookieSessionBackend` creates sessions which
are limited to storing fewer than 4000 bytes of data, as the payload must fit into a
single cookie. An internal server error is generated if a session contains more than 4000 bytes.
A cookie may have a security policy of *signed* or *private*. Each has a respective `CookieSessionBackend` constructor.
A *signed* cookie may be viewed but not modified by the client. A *private* cookie may neither be viewed nor modified by the client.
The constructors take a key as an argument. This is the private key for cookie session - when this value is changed, all session data is lost.
In general, you create a
`SessionStorage` middleware and initialize it with specific backend implementation,
such as a `CookieSessionBackend`. To access session data,
[*HttpRequest::session()*](../actix_web/middleware/trait.RequestSession.html#tymethod.session)
must be used. This method returns a
[*Session*](../actix_web/middleware/struct.Session.html) object, which allows us to get or set
session data.
```rust
# extern crate actix;
# extern crate actix_web;
use actix_web::{server, App, HttpRequest, Result};
use actix_web::middleware::{RequestSession, SessionStorage, CookieSessionBackend};
fn index(mut req: HttpRequest) -> Result<&'static str> {
// access session data
if let Some(count) = req.session().get::<i32>("counter")? {
println!("SESSION value: {}", count);
req.session().set("counter", count+1)?;
} else {
req.session().set("counter", 1)?;
}
Ok("Welcome!")
}
fn main() {
# let sys = actix::System::new("basic-example");
server::new(
|| App::new()
.middleware(SessionStorage::new( // <- create session middleware
CookieSessionBackend::signed(&[0; 32]) // <- create signed cookie session backend
.secure(false)
)))
.bind("127.0.0.1:59880").unwrap()
.start();
# actix::Arbiter::system().do_send(actix::msgs::SystemExit(0));
# let _ = sys.run();
}
```
## Error handlers
`ErrorHandlers` middleware allows us to provide custom handlers for responses.
You can use the `ErrorHandlers::handler()` method to register a custom error handler
for a specific status code. You can modify an existing response or create a completly new
one. The error handler can return a response immediately or return a future that resolves
into a response.
```rust
# extern crate actix_web;
use actix_web::{
App, HttpRequest, HttpResponse, Result,
http, middleware::Response, middleware::ErrorHandlers};
fn render_500<S>(_: &mut HttpRequest<S>, resp: HttpResponse) -> Result<Response> {
let mut builder = resp.into_builder();
builder.header(http::header::CONTENT_TYPE, "application/json");
Ok(Response::Done(builder.into()))
}
fn main() {
let app = App::new()
.middleware(
ErrorHandlers::new()
.handler(http::StatusCode::INTERNAL_SERVER_ERROR, render_500))
.resource("/test", |r| {
r.method(http::Method::GET).f(|_| HttpResponse::Ok());
r.method(http::Method::HEAD).f(|_| HttpResponse::MethodNotAllowed());
})
.finish();
}
```

View File

@ -1,54 +0,0 @@
# Static file handling
## Individual file
It is possible to serve static files with a custom path pattern and `NamedFile`. To
match a path tail, we can use a `[.*]` regex.
```rust
# extern crate actix_web;
use std::path::PathBuf;
use actix_web::{App, HttpRequest, Result, http::Method, fs::NamedFile};
fn index(req: HttpRequest) -> Result<NamedFile> {
let path: PathBuf = req.match_info().query("tail")?;
Ok(NamedFile::open(path)?)
}
fn main() {
App::new()
.resource(r"/a/{tail:.*}", |r| r.method(Method::GET).f(index))
.finish();
}
```
## Directory
To serve files from specific directories and sub-directories, `StaticFiles` can be used.
`StaticFiles` must be registered with an `App::handler()` method, otherwise
it will be unable to serve sub-paths.
```rust
# extern crate actix_web;
use actix_web::*;
fn main() {
App::new()
.handler(
"/static",
fs::StaticFiles::new(".")
.show_files_listing())
.finish();
}
```
The parameter is the base directory. By default files listing for sub-directories
is disabled. Attempt to load directory listing will return *404 Not Found* response.
To enable files listing, use
[*StaticFiles::show_files_listing()*](../actix_web/s/struct.StaticFiles.html#method.show_files_listing)
method.
Instead of showing files listing for directory, it is possible to redirect
to a specific index file. Use the
[*StaticFiles::index_file()*](../actix_web/s/struct.StaticFiles.html#method.index_file)
method to configure this redirect.

View File

@ -1,46 +0,0 @@
# HTTP/2.0
Actix web automatically upgrades connections to *HTTP/2.0* if possible.
## Negotiation
*HTTP/2.0* protocol over tls without prior knowledge requires
[tls alpn](https://tools.ietf.org/html/rfc7301).
> Currently, only `rust-openssl` has support.
`alpn` negotiation requires enabling the feature. When enabled, `HttpServer` provides the
[serve_tls](../actix_web/struct.HttpServer.html#method.serve_tls) method.
```toml
[dependencies]
actix-web = { version = "0.3.3", features=["alpn"] }
openssl = { version="0.10", features = ["v110"] }
```
```rust,ignore
use std::fs::File;
use actix_web::*;
use openssl::ssl::{SslMethod, SslAcceptor, SslFiletype};
fn main() {
// load ssl keys
let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap();
builder.set_private_key_file("key.pem", SslFiletype::PEM).unwrap();
builder.set_certificate_chain_file("cert.pem").unwrap();
HttpServer::new(
|| App::new()
.resource("/index.html", |r| r.f(index)))
.bind("127.0.0.1:8080").unwrap();
.serve_ssl(builder).unwrap();
}
```
Upgrades to *HTTP/2.0* schema described in
[rfc section 3.2](https://http2.github.io/http2-spec/#rfc.section.3.2) is not supported.
Starting *HTTP/2* with prior knowledge is supported for both clear text connection
and tls connection. [rfc section 3.4](https://http2.github.io/http2-spec/#rfc.section.3.4)
> Check out [examples/tls](https://github.com/actix/actix-web/tree/master/examples/tls)
> for a concrete example.

View File

@ -1,128 +0,0 @@
# Database integration
## Diesel
At the moment, Diesel 1.0 does not support asynchronous operations,
but it possible to use the `actix` synchronous actor system as a database interface api.
Technically, sync actors are worker style actors. Multiple sync actors
can be run in parallel and process messages from same queue. Sync actors work in mpsc mode.
Let's create a simple database api that can insert a new user row into a SQLite table.
We must define a sync actor and a connection that this actor will use. The same approach
can be used for other databases.
```rust,ignore
use actix::prelude::*;
struct DbExecutor(SqliteConnection);
impl Actor for DbExecutor {
type Context = SyncContext<Self>;
}
```
This is the definition of our actor. Now, we must define the *create user* message and response.
```rust,ignore
struct CreateUser {
name: String,
}
impl Message for CreateUser {
type Result = Result<User, Error>;
}
```
We can send a `CreateUser` message to the `DbExecutor` actor, and as a result, we will receive a
`User` model instance. Next, we must define the handler implementation for this message.
```rust,ignore
impl Handler<CreateUser> for DbExecutor {
type Result = Result<User, Error>;
fn handle(&mut self, msg: CreateUser, _: &mut Self::Context) -> Self::Result
{
use self::schema::users::dsl::*;
// Create insertion model
let uuid = format!("{}", uuid::Uuid::new_v4());
let new_user = models::NewUser {
id: &uuid,
name: &msg.name,
};
// normal diesel operations
diesel::insert_into(users)
.values(&new_user)
.execute(&self.0)
.expect("Error inserting person");
let mut items = users
.filter(id.eq(&uuid))
.load::<models::User>(&self.0)
.expect("Error loading person");
Ok(items.pop().unwrap())
}
}
```
That's it! Now, we can use the *DbExecutor* actor from any http handler or middleware.
All we need is to start *DbExecutor* actors and store the address in a state where http handler
can access it.
```rust,ignore
/// This is state where we will store *DbExecutor* address.
struct State {
db: Addr<Syn, DbExecutor>,
}
fn main() {
let sys = actix::System::new("diesel-example");
// Start 3 parallel db executors
let addr = SyncArbiter::start(3, || {
DbExecutor(SqliteConnection::establish("test.db").unwrap())
});
// Start http server
HttpServer::new(move || {
App::with_state(State{db: addr.clone()})
.resource("/{name}", |r| r.method(Method::GET).a(index))})
.bind("127.0.0.1:8080").unwrap()
.start().unwrap();
println!("Started http server: 127.0.0.1:8080");
let _ = sys.run();
}
```
We will use the address in a request handler. The handle returns a future object;
thus, we receive the message response asynchronously.
`Route::a()` must be used for async handler registration.
```rust,ignore
/// Async handler
fn index(req: HttpRequest<State>) -> Box<Future<Item=HttpResponse, Error=Error>> {
let name = &req.match_info()["name"];
// Send message to `DbExecutor` actor
req.state().db.send(CreateUser{name: name.to_owned()})
.from_err()
.and_then(|res| {
match res {
Ok(user) => Ok(HttpResponse::Ok().json(user)),
Err(_) => Ok(HttpResponse::InternalServerError().into())
}
})
.responder()
}
```
> A full example is available in the
> [examples directory](https://github.com/actix/actix-web/tree/master/examples/diesel/).
> More information on sync actors can be found in the
> [actix documentation](https://docs.rs/actix/0.5.0/actix/sync/index.html).

View File

@ -1,100 +0,0 @@
# Getting Started
Lets write our first actix web application!
## Hello, world!
Start by creating a new binary-based Cargo project and changing into the new directory:
```bash
cargo new hello-world --bin
cd hello-world
```
Now, add actix and actix web as dependencies of your project by ensuring your Cargo.toml
contains the following:
```toml
[dependencies]
actix = "0.5"
actix-web = "0.5"
```
In order to implement a web server, we first need to create a request handler.
A request handler is a function that accepts an `HttpRequest` instance as its only parameter
and returns a type that can be converted into `HttpResponse`:
Filename: src/main.rs
```rust
# extern crate actix_web;
# use actix_web::*;
fn index(req: HttpRequest) -> &'static str {
"Hello world!"
}
# fn main() {}
```
Next, create an `Application` instance and register the
request handler with the application's `resource` on a particular *HTTP method* and *path*::
```rust
# extern crate actix_web;
# use actix_web::*;
# fn index(req: HttpRequest) -> &'static str {
# "Hello world!"
# }
# fn main() {
App::new()
.resource("/", |r| r.f(index));
# }
```
After that, the application instance can be used with `HttpServer` to listen for incoming
connections. The server accepts a function that should return an `HttpHandler` instance.
For simplicity `server::new` could be used, this function is shortcut for `HttpServer::new`:
```rust,ignore
server::new(
|| App::new()
.resource("/", |r| r.f(index)))
.bind("127.0.0.1:8088")?
.run();
```
That's it! Now, compile and run the program with `cargo run`.
Head over to ``http://localhost:8088/`` to see the results.
The full source of src/main.rs is listed below:
```rust
# use std::thread;
extern crate actix_web;
use actix_web::{server, App, HttpRequest, HttpResponse};
fn index(req: HttpRequest) -> &'static str {
"Hello world!"
}
fn main() {
# // In the doctest suite we can't run blocking code - deliberately leak a thread
# // If copying this example in show-all mode, make sure you skip the thread spawn
# // call.
# thread::spawn(|| {
server::new(
|| App::new()
.resource("/", |r| r.f(index)))
.bind("127.0.0.1:8088").expect("Can not bind to 127.0.0.1:8088")
.run();
# });
}
```
> **Note**: actix web is built upon [actix](https://github.com/actix/actix),
> an [actor model](https://en.wikipedia.org/wiki/Actor_model) framework in Rust.
`actix::System` initializes actor system, `HttpServer` is an actor and must run within a
properly configured actix system.
> For more information, check out the [actix documentation](https://actix.github.io/actix/actix/)
> and [actix guide](https://actix.github.io/actix/guide/).

View File

@ -1,110 +0,0 @@
# Application
Actix web provides various primitives to build web servers and applications with Rust.
It provides routing, middlewares, pre-processing of requests, post-processing of responses,
websocket protocol handling, multipart streams, etc.
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.
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.
> For an application with prefix `/app`,
> any request with the paths `/app`, `/app/`, or `/app/test` would match;
> however, the path `/application` would not match.
```rust,ignore
# extern crate actix_web;
# extern crate tokio_core;
# use actix_web::{*, http::Method};
# fn index(req: HttpRequest) -> &'static str {
# "Hello world!"
# }
# fn main() {
let app = App::new()
.prefix("/app")
.resource("/index.html", |r| r.method(Method::GET).f(index))
.finish()
# }
```
In this example, an application with the `/app` prefix and a `index.html` resource
are created. This resource is available through the `/app/index.html` url.
> For more information, check the
> [URL Dispatch](./qs_5.html#using-a-application-prefix-to-compose-applications) section.
Multiple applications can be served with one server:
```rust
# extern crate actix_web;
# extern crate tokio_core;
# use tokio_core::net::TcpStream;
# use std::net::SocketAddr;
use actix_web::{server, App, HttpResponse};
fn main() {
server::new(|| vec![
App::new()
.prefix("/app1")
.resource("/", |r| r.f(|r| HttpResponse::Ok())),
App::new()
.prefix("/app2")
.resource("/", |r| r.f(|r| HttpResponse::Ok())),
App::new()
.resource("/", |r| r.f(|r| HttpResponse::Ok())),
]);
}
```
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
prefix is registered before a less generic one, it would effectively block the less generic
application matching. For example, if an `App` with the prefix `"/"` was registered
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.
Let's write a simple application that uses shared state. We are going to store request count
in the state:
```rust
# extern crate actix;
# extern crate actix_web;
#
use std::cell::Cell;
use actix_web::{App, HttpRequest, http};
// This struct represents state
struct AppState {
counter: Cell<usize>,
}
fn index(req: HttpRequest<AppState>) -> 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() {
App::with_state(AppState{counter: Cell::new(0)})
.resource("/", |r| r.method(http::Method::GET).f(index))
.finish();
}
```
> **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`. Application state does not need to be `Send` and `Sync`,
> but the application factory must be `Send` + `Sync`.

View File

@ -1,210 +0,0 @@
# Server
The [**HttpServer**](../actix_web/server/struct.HttpServer.html) type is responsible for
serving http requests.
`HttpServer` accepts an application factory as a parameter, and the
application factory must have `Send` + `Sync` boundaries. More about that in the
*multi-threading* section.
To bind to a specific socket address, `bind()` must be used, and it may be called multiple times.
To start the http server, one of the start methods.
- use `start()` for a simple server
- use `start_tls()` or `start_ssl()` for a ssl server
`HttpServer` is an actix actor. It must be initialized within a properly configured actix system:
```rust
# extern crate actix;
# extern crate actix_web;
use actix_web::{server::HttpServer, App, HttpResponse};
fn main() {
let sys = actix::System::new("guide");
HttpServer::new(
|| App::new()
.resource("/", |r| r.f(|_| HttpResponse::Ok())))
.bind("127.0.0.1:59080").unwrap()
.start();
# actix::Arbiter::system().do_send(actix::msgs::SystemExit(0));
let _ = sys.run();
}
```
> It is possible to start a server in a separate thread with the `spawn()` method. In that
> case the server spawns a new thread and creates a new actix system in it. To stop
> this server, send a `StopServer` message.
`HttpServer` is implemented as an actix actor. It is possible to communicate with the server
via a messaging system. All start methods, e.g. `start()` and `start_ssl()`, return the
address of the started http server. It accepts several messages:
- `PauseServer` - Pause accepting incoming connections
- `ResumeServer` - Resume accepting incoming connections
- `StopServer` - Stop incoming connection processing, stop all workers and exit
```rust
# extern crate futures;
# extern crate actix;
# extern crate actix_web;
# use futures::Future;
use std::thread;
use std::sync::mpsc;
use actix_web::{server, App, HttpResponse};
fn main() {
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let sys = actix::System::new("http-server");
let addr = server::new(
|| App::new()
.resource("/", |r| r.f(|_| HttpResponse::Ok())))
.bind("127.0.0.1:0").expect("Can not bind to 127.0.0.1:0")
.shutdown_timeout(60) // <- Set shutdown timeout to 60 seconds
.start();
let _ = tx.send(addr);
let _ = sys.run();
});
let addr = rx.recv().unwrap();
let _ = addr.send(
server::StopServer{graceful:true}).wait(); // <- Send `StopServer` message to server.
}
```
## Multi-threading
`HttpServer` automatically starts an number of http workers, by default
this number is equal to number of logical CPUs in the system. This number
can be overridden with the `HttpServer::threads()` method.
```rust
# extern crate actix_web;
# extern crate tokio_core;
use actix_web::{App, HttpResponse, server::HttpServer};
fn main() {
HttpServer::new(
|| App::new()
.resource("/", |r| r.f(|_| HttpResponse::Ok())))
.threads(4); // <- Start 4 workers
}
```
The server creates a separate application instance for each created worker. Application state
is not shared between threads. To share state, `Arc` could be used.
> Application state does not need to be `Send` and `Sync`,
> but factories must be `Send` + `Sync`.
## SSL
There are two features for ssl server: `tls` and `alpn`. The `tls` feature is for `native-tls`
integration and `alpn` is for `openssl`.
```toml
[dependencies]
actix-web = { git = "https://github.com/actix/actix-web", features=["alpn"] }
```
```rust,ignore
use std::fs::File;
use actix_web::*;
fn main() {
// load ssl keys
let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap();
builder.set_private_key_file("key.pem", SslFiletype::PEM).unwrap();
builder.set_certificate_chain_file("cert.pem").unwrap();
server::new(
|| App::new()
.resource("/index.html", |r| r.f(index)))
.bind("127.0.0.1:8080").unwrap()
.serve_ssl(builder).unwrap();
}
```
> **Note**: the *HTTP/2.0* protocol requires
> [tls alpn](https://tools.ietf.org/html/rfc7301).
> At the moment, only `openssl` has `alpn` support.
> For a full example, check out
> [examples/tls](https://github.com/actix/actix-web/tree/master/examples/tls).
## Keep-Alive
Actix can wait for requests on a keep-alive connection.
> *keep alive* connection behavior is defined by server settings.
- `75`, `Some(75)`, `KeepAlive::Timeout(75)` - enable 75 second *keep alive* timer.
- `None` or `KeepAlive::Disabled` - disable *keep alive*.
- `KeepAlive::Tcp(75)` - use `SO_KEEPALIVE` socket option.
```rust
# extern crate actix_web;
# extern crate tokio_core;
use actix_web::{server, App, HttpResponse};
fn main() {
server::new(||
App::new()
.resource("/", |r| r.f(|_| HttpResponse::Ok())))
.keep_alive(75); // <- Set keep-alive to 75 seconds
server::new(||
App::new()
.resource("/", |r| r.f(|_| HttpResponse::Ok())))
.keep_alive(server::KeepAlive::Tcp(75)); // <- Use `SO_KEEPALIVE` socket option.
server::new(||
App::new()
.resource("/", |r| r.f(|_| HttpResponse::Ok())))
.keep_alive(None); // <- Disable keep-alive
}
```
If the first option is selected, then *keep alive* state is
calculated based on the response's *connection-type*. By default
`HttpResponse::connection_type` is not defined. In that case *keep alive* is
defined by the request's http version.
> *keep alive* is **off** for *HTTP/1.0* and is **on** for *HTTP/1.1* and *HTTP/2.0*.
*Connection type* can be change with `HttpResponseBuilder::connection_type()` method.
```rust
# extern crate actix_web;
use actix_web::{HttpRequest, HttpResponse, http};
fn index(req: HttpRequest) -> HttpResponse {
HttpResponse::Ok()
.connection_type(http::ConnectionType::Close) // <- Close connection
.force_close() // <- Alternative method
.finish()
}
# fn main() {}
```
## Graceful shutdown
`HttpServer` supports graceful shutdown. After receiving a stop signal, workers
have a specific amount of time to finish serving requests. Any workers still alive after the
timeout are force-dropped. By default the shutdown timeout is set to 30 seconds.
You can change this parameter with the `HttpServer::shutdown_timeout()` method.
You can send a stop message to the server with the server address and specify if you want
graceful shutdown or not. The `start()` methods returns address of the server.
`HttpServer` handles several OS signals. *CTRL-C* is available on all OSs,
other signals are available on unix systems.
- *SIGINT* - Force shutdown workers
- *SIGTERM* - Graceful shutdown workers
- *SIGQUIT* - Force shutdown workers
> It is possible to disable signal handling with `HttpServer::disable_signals()` method.

View File

@ -1,313 +0,0 @@
# Handler
A request handler can be any object that implements
[`Handler` trait](../actix_web/dev/trait.Handler.html).
Request handling happens in two stages. First the handler object is called,
returning any object that implements the
[`Responder` trait](../actix_web/trait.Responder.html#foreign-impls).
Then, `respond_to()` is called on the returned object, converting itself to a `Reply` or `Error`.
By default actix provides `Responder` implementations for some standard types,
such as `&'static str`, `String`, etc.
> For a complete list of implementations, check
> [*Responder documentation*](../actix_web/trait.Responder.html#foreign-impls).
Examples of valid handlers:
```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<Future<Item=HttpResponse, Error=Error>> {
...
}
```
*Handler* trait is generic over *S*, which defines the application state's type.
Application state is accessible from the handler with the `HttpRequest::state()` method;
however, state is accessible as a read-only reference. If you need mutable access to state,
it must be implemented.
> **Note**: Alternatively, the handler can mutably access its own state because the `handle` method takes
> mutable reference to *self*. **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:
```rust
# extern crate actix_web;
use actix_web::{App, HttpRequest, HttpResponse, dev::Handler};
struct MyHandler(usize);
impl<S> Handler<S> for MyHandler {
type Result = HttpResponse;
/// Handle request
fn handle(&mut self, req: HttpRequest<S>) -> Self::Result {
self.0 += 1;
HttpResponse::Ok().into()
}
}
# fn main() {}
```
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`.
```rust
# extern crate actix;
# extern crate actix_web;
use actix_web::{server, App, HttpRequest, HttpResponse, dev::Handler};
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
struct MyHandler(Arc<AtomicUsize>);
impl<S> Handler<S> for MyHandler {
type Result = HttpResponse;
/// Handle request
fn handle(&mut self, req: HttpRequest<S>) -> Self::Result {
self.0.fetch_add(1, Ordering::Relaxed);
HttpResponse::Ok().into()
}
}
fn main() {
let sys = actix::System::new("example");
let inc = Arc::new(AtomicUsize::new(0));
server::new(
move || {
let cloned = inc.clone();
App::new()
.resource("/", move |r| r.h(MyHandler(cloned)))
})
.bind("127.0.0.1:8088").unwrap()
.start();
println!("Started http server: 127.0.0.1:8088");
# actix::Arbiter::system().do_send(actix::msgs::SystemExit(0));
let _ = sys.run();
}
```
> Be careful with synchronization primitives like `Mutex` or `RwLock`. 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.
## Response with custom type
To return a custom type directly from a handler function, the type needs to implement the `Responder` trait.
Let's create a response for a custom type that serializes to an `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::{server, App, HttpRequest, HttpResponse, Error, Responder, http};
#[derive(Serialize)]
struct MyObj {
name: &'static str,
}
/// Responder
impl Responder for MyObj {
type Item = HttpResponse;
type Error = Error;
fn respond_to(self, req: HttpRequest) -> Result<HttpResponse, Error> {
let body = serde_json::to_string(&self)?;
// Create response and set content type
Ok(HttpResponse::Ok()
.content_type("application/json")
.body(body))
}
}
/// Because `MyObj` implements `Responder`, it is possible to return it directly
fn index(req: HttpRequest) -> MyObj {
MyObj{name: "user"}
}
fn main() {
let sys = actix::System::new("example");
server::new(
|| App::new()
.resource("/", |r| r.method(http::Method::GET).f(index)))
.bind("127.0.0.1:8088").unwrap()
.start();
println!("Started http server: 127.0.0.1:8088");
# actix::Arbiter::system().do_send(actix::msgs::SystemExit(0));
let _ = sys.run();
}
```
## Async handlers
There are two different types of async handlers. Response objects can be generated asynchronously
or more precisely, any type that implements the [*Responder*](../actix_web/trait.Responder.html) trait.
In this case, the handler must return a `Future` object that resolves to the *Responder* type, i.e:
```rust
# extern crate actix_web;
# extern crate futures;
# extern crate bytes;
# use actix_web::*;
# use bytes::Bytes;
# use futures::stream::once;
# use futures::future::{Future, result};
fn index(req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
result(Ok(HttpResponse::Ok()
.content_type("text/html")
.body(format!("Hello!"))))
.responder()
}
fn index2(req: HttpRequest) -> Box<Future<Item=&'static str, Error=Error>> {
result(Ok("Welcome!"))
.responder()
}
fn main() {
App::new()
.resource("/async", |r| r.route().a(index))
.resource("/", |r| r.route().a(index2))
.finish();
}
```
Or the response body can be generated asynchronously. In this case, body
must implement the stream trait `Stream<Item=Bytes, Error=Error>`, i.e:
```rust
# extern crate actix_web;
# extern crate futures;
# extern crate bytes;
# use actix_web::*;
# use bytes::Bytes;
# use futures::stream::once;
fn index(req: HttpRequest) -> HttpResponse {
let body = once(Ok(Bytes::from_static(b"test")));
HttpResponse::Ok()
.content_type("application/json")
.body(Body::Streaming(Box::new(body)))
}
fn main() {
App::new()
.resource("/async", |r| r.f(index))
.finish();
}
```
Both methods can be combined. (i.e Async response with streaming body)
It is possible to return a `Result` where the `Result::Item` type can be `Future`.
In this example, the `index` handler can return an error immediately or return a
future that resolves to a `HttpResponse`.
```rust
# extern crate actix_web;
# extern crate futures;
# extern crate bytes;
# use actix_web::*;
# use bytes::Bytes;
# use futures::stream::once;
# use futures::future::{Future, result};
fn index(req: HttpRequest) -> Result<Box<Future<Item=HttpResponse, Error=Error>>, Error> {
if is_error() {
Err(error::ErrorBadRequest("bad request"))
} else {
Ok(Box::new(
result(Ok(HttpResponse::Ok()
.content_type("text/html")
.body(format!("Hello!"))))))
}
}
#
# fn is_error() -> bool { true }
# fn main() {
# App::new()
# .resource("/async", |r| r.route().f(index))
# .finish();
# }
```
## Different return types (Either)
Sometimes, you need to return different types of responses. For example,
you can error check and return errors, return async responses, or any result that requires two different types.
For this case, the [`Either`](../actix_web/enum.Either.html) type can be used.
`Either` allows combining two different responder types into a single type.
```rust
# extern crate actix_web;
# extern crate futures;
# use actix_web::*;
# use futures::future::Future;
use futures::future::result;
use actix_web::{Either, Error, HttpResponse};
type RegisterResult = Either<HttpResponse, Box<Future<Item=HttpResponse, Error=Error>>>;
fn index(req: HttpRequest) -> RegisterResult {
if is_a_variant() { // <- choose variant A
Either::A(
HttpResponse::BadRequest().body("Bad data"))
} else {
Either::B( // <- variant B
result(Ok(HttpResponse::Ok()
.content_type("text/html")
.body(format!("Hello!")))).responder())
}
}
# fn is_a_variant() -> bool { true }
# fn main() {
# App::new()
# .resource("/register", |r| r.f(index))
# .finish();
# }
```
## Tokio core handle
Any actix web handler runs within a properly configured
[actix system](https://actix.github.io/actix/actix/struct.System.html)
and [arbiter](https://actix.github.io/actix/actix/struct.Arbiter.html).
You can always get access to the tokio handle via the
[Arbiter::handle()](https://actix.github.io/actix/actix/struct.Arbiter.html#method.handle)
method.

View File

@ -1,153 +0,0 @@
# Errors
Actix uses the [`Error` type](../actix_web/error/struct.Error.html)
and [`ResponseError` trait](../actix_web/error/trait.ResponseError.html)
for handling handler's errors.
Any error that implements the `ResponseError` trait can be returned as an error value.
`Handler` can return an `Result` object. By default, actix provides a
`Responder` implementation for compatible result types. Here is the implementation
definition:
```rust,ignore
impl<T: Responder, E: Into<Error>> Responder for Result<T, E>
```
Any error that implements `ResponseError` can be converted into an `Error` object.
For example, if the *handler* function returns `io::Error`, it would be converted
into an `HttpInternalServerError` response. Implementation for `io::Error` is provided
by default.
```rust
# extern crate actix_web;
# use actix_web::*;
use std::io;
fn index(req: HttpRequest) -> io::Result<fs::NamedFile> {
Ok(fs::NamedFile::open("static/index.html")?)
}
#
# fn main() {
# App::new()
# .resource(r"/a/index.html", |r| r.f(index))
# .finish();
# }
```
## Custom error response
To add support for custom errors, all we need to do is implement the `ResponseError` trait
for the custom error type. The `ResponseError` trait has a default implementation
for the `error_response()` method: it generates a *500* response.
```rust
# extern crate actix_web;
#[macro_use] extern crate failure;
use actix_web::*;
#[derive(Fail, Debug)]
#[fail(display="my error")]
struct MyError {
name: &'static str
}
/// Use default implementation for `error_response()` method
impl error::ResponseError for MyError {}
fn index(req: HttpRequest) -> Result<&'static str, MyError> {
Err(MyError{name: "test"})
}
#
# fn main() {
# App::new()
# .resource(r"/a/index.html", |r| r.f(index))
# .finish();
# }
```
In this example the *index* handler always returns a *500* response. But it is easy
to return different responses for different types of errors.
```rust
# extern crate actix_web;
#[macro_use] extern crate failure;
use actix_web::{App, HttpRequest, HttpResponse, http, error};
#[derive(Fail, Debug)]
enum MyError {
#[fail(display="internal error")]
InternalError,
#[fail(display="bad request")]
BadClientData,
#[fail(display="timeout")]
Timeout,
}
impl error::ResponseError for MyError {
fn error_response(&self) -> HttpResponse {
match *self {
MyError::InternalError => HttpResponse::new(
http::StatusCode::INTERNAL_SERVER_ERROR),
MyError::BadClientData => HttpResponse::new(
http::StatusCode::BAD_REQUEST),
MyError::Timeout => HttpResponse::new(
http::StatusCode::GATEWAY_TIMEOUT),
}
}
}
fn index(req: HttpRequest) -> Result<&'static str, MyError> {
Err(MyError::BadClientData)
}
#
# fn main() {
# App::new()
# .resource(r"/a/index.html", |r| r.f(index))
# .finish();
# }
```
## Error helpers
Actix provides a set of error helper types. It is possible to use them for generating
specific error responses. We can use the helper types for the first example with a custom error.
```rust
# extern crate actix_web;
#[macro_use] extern crate failure;
use actix_web::*;
#[derive(Debug)]
struct MyError {
name: &'static str
}
fn index(req: HttpRequest) -> Result<&'static str> {
let result: Result<&'static str, MyError> = Err(MyError{name: "test"});
Ok(result.map_err(|e| error::ErrorBadRequest(e))?)
}
# fn main() {
# App::new()
# .resource(r"/a/index.html", |r| r.f(index))
# .finish();
# }
```
In this example, a *BAD REQUEST* response is generated for the `MyError` error.
## Error logging
Actix logs all errors with the log level `WARN`. If log level set to `DEBUG`
and `RUST_BACKTRACE` is enabled, the backtrace gets logged. The Error type uses
the cause's error backtrace if available. If the underlying failure does not provide
a backtrace, a new backtrace is constructed pointing to that conversion point
(rather than the origin of the error). This construction only happens if there
is no underlying backtrace; if it does have a backtrace, no new backtrace is constructed.
You can enable backtrace and debug logging with following command:
```
>> RUST_BACKTRACE=1 RUST_LOG=actix_web=debug cargo run
```

View File

@ -1,654 +0,0 @@
# URL Dispatch
URL dispatch provides a simple way for mapping URLs to `Handler` code using a simple pattern
matching language. If one of the patterns matches the path information associated with a request,
a particular handler object is invoked.
> A handler is a specific object that implements the
> `Handler` trait, defined in your application, that receives the request and returns
> a response object. More information is available in the [handler section](../qs_4.html).
## Resource configuration
Resource configuration is the act of adding a new resources to an application.
A resource has a name, which acts as an identifier to be used for URL generation.
The name also allows developers to add routes to existing resources.
A resource also has a pattern, meant to match against the *PATH* portion of a *URL*.
It does not match against the *QUERY* portion (the portion following the scheme and
port, e.g., */foo/bar* in the *URL* *http://localhost:8080/foo/bar?q=value*).
The [App::route](../actix_web/struct.App.html#method.route) method provides
simple way of registering routes. This method adds a single route to application
routing table. This method accepts a *path pattern*,
*http method* and a handler function. `route()` method could be called multiple times
for the same path, in that case, multiple routes register for the same resource path.
```rust
# extern crate actix_web;
use actix_web::{App, HttpRequest, HttpResponse, http::Method};
fn index(req: HttpRequest) -> HttpResponse {
unimplemented!()
}
fn main() {
App::new()
.route("/user/{name}", Method::GET, index)
.route("/user/{name}", Method::POST, index)
.finish();
}
```
While *App::route()* provides simple way of registering routes, to access
complete resource configuration, different method has to be used.
The [App::resource](../actix_web/struct.App.html#method.resource) method
adds a single resource to application routing table. This method accepts a *path pattern*
and a resource configuration function.
```rust
# extern crate actix_web;
use actix_web::{App, HttpRequest, HttpResponse, http::Method};
fn index(req: HttpRequest) -> HttpResponse {
unimplemented!()
}
fn main() {
App::new()
.resource("/prefix", |r| r.f(index))
.resource("/user/{name}",
|r| r.method(Method::GET).f(|req| HttpResponse::Ok()))
.finish();
}
```
The *Configuration function* has the following type:
```rust,ignore
FnOnce(&mut Resource<_>) -> ()
```
The *Configuration function* can set a name and register specific routes.
If a resource does not contain any route or does not have any matching routes, it
returns *NOT FOUND* http response.
## Configuring a Route
Resource contains a set of routes. Each route in turn has a set of predicates and a handler.
New routes can be created with `Resource::route()` method which returns a reference
to new *Route* instance. By default the *route* does not contain any predicates, so matches
all requests and the default handler is `HttpNotFound`.
The application routes incoming requests based on route criteria which are defined during
resource registration and route registration. Resource matches all routes it contains in
the order the routes were registered via `Resource::route()`.
> A *Route* can contain any number of *predicates* but only one handler.
```rust
# extern crate actix_web;
# use actix_web::*;
fn main() {
App::new()
.resource("/path", |resource|
resource.route()
.filter(pred::Get())
.filter(pred::Header("content-type", "text/plain"))
.f(|req| HttpResponse::Ok())
)
.finish();
}
```
In this example, `HttpResponse::Ok()` is returned for *GET* requests.
If a request contains `Content-Type` header, the value of this header is *text/plain*,
and path equals to `/path`, Resource calls handle of the first matching route.
If a resource can not match any route, a "NOT FOUND" response is returned.
[*Resource::route()*](../actix_web/struct.Resource.html#method.route) returns a
[*Route*](../actix_web/struct.Route.html) object. Route can be configured with a
builder-like pattern. Following configuration methods are available:
* [*Route::filter()*](../actix_web/struct.Route.html#method.filter) registers a new predicate.
Any number of predicates can be registered for each route.
* [*Route::f()*](../actix_web/struct.Route.html#method.f) registers handler function
for this route. Only one handler can be registered. Usually handler registration
is the last config operation. Handler function can be a function or closure and has the type
`Fn(HttpRequest<S>) -> R + 'static`
* [*Route::h()*](../actix_web/struct.Route.html#method.h) registers a handler object
that implements the `Handler` trait. This is similar to `f()` method - only one handler can
be registered. Handler registration is the last config operation.
* [*Route::a()*](../actix_web/struct.Route.html#method.a) registers an async handler
function for this route. Only one handler can be registered. Handler registration
is the last config operation. Handler function can be a function or closure and has the type
`Fn(HttpRequest<S>) -> Future<Item = HttpResponse, Error = Error> + 'static`
## Route matching
The main purpose of route configuration is to match (or not match) the request's `path`
against a URL path pattern. `path` represents the path portion of the URL that was requested.
The way that *actix* does this is very simple. When a request enters the system,
for each resource configuration declaration present in the system, actix checks
the request's path against the pattern declared. This checking happens in the order that
the routes were declared via `App::resource()` method. If resource can not be found,
the *default resource* is used as the matched resource.
When a route configuration is declared, it may contain route predicate arguments. All route
predicates associated with a route declaration must be `true` for the route configuration to
be used for a given request during a check. If any predicate in the set of route predicate
arguments provided to a route configuration returns `false` during a check, that route is
skipped and route matching continues through the ordered set of routes.
If any route matches, the route matching process stops and the handler associated with
the route is invoked. If no route matches after all route patterns are exhausted, a *NOT FOUND* response get returned.
## Resource pattern syntax
The syntax of the pattern matching language used by actix in the pattern
argument is straightforward.
The pattern used in route configuration may start with a slash character. If the pattern
does not start with a slash character, an implicit slash will be prepended
to it at matching time. For example, the following patterns are equivalent:
```
{foo}/bar/baz
```
and:
```
/{foo}/bar/baz
```
A *variable part* (replacement marker) is specified in the form *{identifier}*,
where this means "accept any characters up to the next slash character and use this
as the name in the `HttpRequest.match_info()` object".
A replacement marker in a pattern matches the regular expression `[^{}/]+`.
A match_info is the `Params` object representing the dynamic parts extracted from a
*URL* based on the routing pattern. It is available as *request.match_info*. For example, the
following pattern defines one literal segment (foo) and two replacement markers (baz, and bar):
```
foo/{baz}/{bar}
```
The above pattern will match these URLs, generating the following match information:
```
foo/1/2 -> Params {'baz':'1', 'bar':'2'}
foo/abc/def -> Params {'baz':'abc', 'bar':'def'}
```
It will not match the following patterns however:
```
foo/1/2/ -> No match (trailing slash)
bar/abc/def -> First segment literal mismatch
```
The match for a segment replacement marker in a segment will be done only up to
the first non-alphanumeric character in the segment in the pattern. So, for instance,
if this route pattern was used:
```
foo/{name}.html
```
The literal path */foo/biz.html* will match the above route pattern, and the match result
will be `Params{'name': 'biz'}`. However, the literal path */foo/biz* will not match,
because it does not contain a literal *.html* at the end of the segment represented
by *{name}.html* (it only contains biz, not biz.html).
To capture both segments, two replacement markers can be used:
```
foo/{name}.{ext}
```
The literal path */foo/biz.html* will match the above route pattern, and the match
result will be *Params{'name': 'biz', 'ext': 'html'}*. This occurs because there is a
literal part of *.* (period) between the two replacement markers *{name}* and *{ext}*.
Replacement markers can optionally specify a regular expression which will be used to decide
whether a path segment should match the marker. To specify that a replacement marker should
match only a specific set of characters as defined by a regular expression, you must use a
slightly extended form of replacement marker syntax. Within braces, the replacement marker
name must be followed by a colon, then directly thereafter, the regular expression. The default
regular expression associated with a replacement marker *[^/]+* matches one or more characters
which are not a slash. For example, under the hood, the replacement marker *{foo}* can more
verbosely be spelled as *{foo:[^/]+}*. You can change this to be an arbitrary regular expression
to match an arbitrary sequence of characters, such as *{foo:\d+}* to match only digits.
Segments must contain at least one character in order to match a segment replacement marker.
For example, for the URL */abc/*:
* */abc/{foo}* will not match.
* */{foo}/* will match.
> **Note**: path will be URL-unquoted and decoded into valid unicode string before
> matching pattern and values representing matched path segments will be URL-unquoted too.
So for instance, the following pattern:
```
foo/{bar}
```
When matching the following URL:
```
http://example.com/foo/La%20Pe%C3%B1a
```
The matchdict will look like so (the value is URL-decoded):
```
Params{'bar': 'La Pe\xf1a'}
```
Literal strings in the path segment should represent the decoded value of the
path provided to actix. You don't want to use a URL-encoded value in the pattern.
For example, rather than this:
```
/Foo%20Bar/{baz}
```
You'll want to use something like this:
```
/Foo Bar/{baz}
```
It is possible to get "tail match". For this purpose custom regex has to be used.
```
foo/{bar}/{tail:.*}
```
The above pattern will match these URLs, generating the following match information:
```
foo/1/2/ -> Params{'bar':'1', 'tail': '2/'}
foo/abc/def/a/b/c -> Params{'bar':u'abc', 'tail': 'def/a/b/c'}
```
## Match information
All values representing matched path segments are available in
[`HttpRequest::match_info`](../actix_web/struct.HttpRequest.html#method.match_info).
Specific values can be retrieved with
[`Params::get()`](../actix_web/dev/struct.Params.html#method.get).
Any matched parameter can be deserialized into a specific type if the type
implements the `FromParam` trait. For example most standard integer types
the trait, i.e.:
```rust
# extern crate actix_web;
use actix_web::*;
fn index(req: HttpRequest) -> Result<String> {
let v1: u8 = req.match_info().query("v1")?;
let v2: u8 = req.match_info().query("v2")?;
Ok(format!("Values {} {}", v1, v2))
}
fn main() {
App::new()
.resource(r"/a/{v1}/{v2}/", |r| r.f(index))
.finish();
}
```
For this example for path '/a/1/2/', values v1 and v2 will resolve to "1" and "2".
It is possible to create a `PathBuf` from a tail path parameter. The returned `PathBuf` is
percent-decoded. If a segment is equal to "..", the previous segment (if
any) is skipped.
For security purposes, if a segment meets any of the following conditions,
an `Err` is returned indicating the condition met:
* Decoded segment starts with any of: `.` (except `..`), `*`
* Decoded segment ends with any of: `:`, `>`, `<`
* Decoded segment contains any of: `/`
* On Windows, decoded segment contains any of: '\'
* Percent-encoding results in invalid UTF8.
As a result of these conditions, a `PathBuf` parsed from request path parameter is
safe to interpolate within, or use as a suffix of, a path without additional checks.
```rust
# extern crate actix_web;
use std::path::PathBuf;
use actix_web::{App, HttpRequest, Result, http::Method};
fn index(req: HttpRequest) -> Result<String> {
let path: PathBuf = req.match_info().query("tail")?;
Ok(format!("Path {:?}", path))
}
fn main() {
App::new()
.resource(r"/a/{tail:.*}", |r| r.method(Method::GET).f(index))
.finish();
}
```
List of `FromParam` implementations can be found in
[api docs](../actix_web/dev/trait.FromParam.html#foreign-impls)
## Path information extractor
Actix provides functionality for type safe path information extraction.
[Path](../actix_web/struct.Path.html) extracts information, destination type
could be defined in several different forms. Simplest approach is to use
`tuple` type. Each element in tuple must correpond to one element from
path pattern. i.e. you can match path pattern `/{id}/{username}/` against
`Pyth<(u32, String)>` type, but `Path<(String, String, String)>` type will
always fail.
```rust
# extern crate actix_web;
use actix_web::{App, Path, Result, http::Method};
// extract path info using serde
fn index(info: Path<(String, u32)>) -> Result<String> {
Ok(format!("Welcome {}! id: {}", info.0, info.1))
}
fn main() {
let app = App::new()
.resource("/{username}/{id}/index.html", // <- define path parameters
|r| r.method(Method::GET).with(index));
}
```
It also possible to extract path pattern information to a struct. In this case,
this struct must implement *serde's *`Deserialize` trait.
```rust
# extern crate actix_web;
#[macro_use] extern crate serde_derive;
use actix_web::{App, Path, Result, http::Method};
#[derive(Deserialize)]
struct Info {
username: String,
}
// extract path info using serde
fn index(info: Path<Info>) -> Result<String> {
Ok(format!("Welcome {}!", info.username))
}
fn main() {
let app = App::new()
.resource("/{username}/index.html", // <- define path parameters
|r| r.method(Method::GET).with(index));
}
```
[Query](../actix_web/struct.Query.html) provides similar functionality for
request query parameters.
## Generating resource URLs
Use the [HttpRequest.url_for()](../actix_web/struct.HttpRequest.html#method.url_for)
method to generate URLs based on resource patterns. For example, if you've configured a
resource with the name "foo" and the pattern "{a}/{b}/{c}", you might do this:
```rust
# extern crate actix_web;
# use actix_web::{App, Result, HttpRequest, HttpResponse, http::Method, http::header};
#
fn index(req: HttpRequest) -> Result<HttpResponse> {
let url = req.url_for("foo", &["1", "2", "3"])?; // <- generate url for "foo" resource
Ok(HttpResponse::Found()
.header(header::LOCATION, url.as_str())
.finish())
}
fn main() {
let app = App::new()
.resource("/test/{a}/{b}/{c}", |r| {
r.name("foo"); // <- set resource name, then it could be used in `url_for`
r.method(Method::GET).f(|_| HttpResponse::Ok());
})
.route("/test/", Method::GET, index)
.finish();
}
```
This would return something like the string *http://example.com/test/1/2/3* (at least if
the current protocol and hostname implied http://example.com).
`url_for()` method returns [*Url object*](https://docs.rs/url/1.6.0/url/struct.Url.html) so you
can modify this url (add query parameters, anchor, etc).
`url_for()` could be called only for *named* resources otherwise error get returned.
## External resources
Resources that are valid URLs, can be registered as external resources. They are useful
for URL generation purposes only and are never considered for matching at request time.
```rust
# extern crate actix_web;
use actix_web::{App, HttpRequest, HttpResponse, Error};
fn index(mut req: HttpRequest) -> Result<HttpResponse, Error> {
let url = req.url_for("youtube", &["oHg5SJYRHA0"])?;
assert_eq!(url.as_str(), "https://youtube.com/watch/oHg5SJYRHA0");
Ok(HttpResponse::Ok().into())
}
fn main() {
let app = App::new()
.resource("/index.html", |r| r.f(index))
.external_resource("youtube", "https://youtube.com/watch/{video_id}")
.finish();
}
```
## Path normalization and redirecting to slash-appended routes
By normalizing it means:
* Add a trailing slash to the path.
* Double slashes are replaced by one.
The handler returns as soon as it finds a path that resolves
correctly. The order if all enable is 1) merge, 3) both merge and append
and 3) append. If the path resolves with
at least one of those conditions, it will redirect to the new path.
If *append* is *true*, append slash when needed. If a resource is
defined with trailing slash and the request doesn't have one, it will
be appended automatically.
If *merge* is *true*, merge multiple consecutive slashes in the path into one.
This handler designed to be used as a handler for application's *default resource*.
```rust
# extern crate actix_web;
# #[macro_use] extern crate serde_derive;
# use actix_web::*;
use actix_web::http::NormalizePath;
#
# fn index(req: HttpRequest) -> HttpResponse {
# HttpResponse::Ok().into()
# }
fn main() {
let app = App::new()
.resource("/resource/", |r| r.f(index))
.default_resource(|r| r.h(NormalizePath::default()))
.finish();
}
```
In this example `/resource`, `//resource///` will be redirected to `/resource/`.
In this example, the path normalization handler is registered for all methods,
but you should not rely on this mechanism to redirect *POST* requests. The redirect of the
slash-appending *Not Found* will turn a *POST* request into a GET, losing any
*POST* data in the original request.
It is possible to register path normalization only for *GET* requests only:
```rust
# extern crate actix_web;
# #[macro_use] extern crate serde_derive;
use actix_web::{App, HttpRequest, http::Method, http::NormalizePath};
#
# fn index(req: HttpRequest) -> &'static str {
# "test"
# }
fn main() {
let app = App::new()
.resource("/resource/", |r| r.f(index))
.default_resource(|r| r.method(Method::GET).h(NormalizePath::default()))
.finish();
}
```
## Using an Application Prefix to Compose Applications
The `App::prefix()` method allows to set a specific application prefix.
This prefix represents a resource prefix that will be prepended to all resource patterns added
by the resource configuration. This can be used to help mount a set of routes at a different
location than the included callable's author intended while still maintaining the same
resource names.
For example:
```rust
# extern crate actix_web;
# use actix_web::*;
#
fn show_users(req: HttpRequest) -> HttpResponse {
unimplemented!()
}
fn main() {
App::new()
.prefix("/users")
.resource("/show", |r| r.f(show_users))
.finish();
}
```
In the above example, the *show_users* route will have an effective route pattern of
*/users/show* instead of */show* because the application's prefix argument will be prepended
to the pattern. The route will then only match if the URL path is */users/show*,
and when the `HttpRequest.url_for()` function is called with the route name show_users,
it will generate a URL with that same path.
## Custom route predicates
You can think of a predicate as a simple function that accepts a *request* object reference
and returns *true* or *false*. Formally, a predicate is any object that implements the
[`Predicate`](../actix_web/pred/trait.Predicate.html) trait. Actix provides
several predicates, you can check [functions section](../actix_web/pred/index.html#functions)
of api docs.
Here is a simple predicate that check that a request contains a specific *header*:
```rust
# extern crate actix_web;
# use actix_web::*;
use actix_web::{http, pred::Predicate, App, HttpRequest};
struct ContentTypeHeader;
impl<S: 'static> Predicate<S> for ContentTypeHeader {
fn check(&self, req: &mut HttpRequest<S>) -> bool {
req.headers().contains_key(http::header::CONTENT_TYPE)
}
}
fn main() {
App::new()
.resource("/index.html", |r|
r.route()
.filter(ContentTypeHeader)
.f(|_| HttpResponse::Ok()));
}
```
In this example, *index* handler will be called only if request contains *CONTENT-TYPE* header.
Predicates have access to the application's state via `HttpRequest::state()`.
Also predicates can store extra information in
[request extensions](../actix_web/struct.HttpRequest.html#method.extensions).
### Modifying predicate values
You can invert the meaning of any predicate value by wrapping it in a `Not` predicate.
For example, if you want to return "METHOD NOT ALLOWED" response for all methods
except "GET":
```rust
# extern crate actix_web;
# extern crate http;
# use actix_web::*;
use actix_web::{pred, App, HttpResponse};
fn main() {
App::new()
.resource("/index.html", |r|
r.route()
.filter(pred::Not(pred::Get()))
.f(|req| HttpResponse::MethodNotAllowed()))
.finish();
}
```
The `Any` predicate accepts a list of predicates and matches if any of the supplied
predicates match. i.e:
```rust,ignore
pred::Any(pred::Get()).or(pred::Post())
```
The `All` predicate accepts a list of predicates and matches if all of the supplied
predicates match. i.e:
```rust,ignore
pred::All(pred::Get()).and(pred::Header("content-type", "plain/text"))
```
## Changing the default Not Found response
If the path pattern can not be found in the routing table or a resource can not find matching
route, the default resource is used. The default response is *NOT FOUND*.
It is possible to override the *NOT FOUND* response with `App::default_resource()`.
This method accepts a *configuration function* same as normal resource configuration
with `App::resource()` method.
```rust
# extern crate actix_web;
use actix_web::{App, HttpResponse, http::Method, pred};
fn main() {
App::new()
.default_resource(|r| {
r.method(Method::GET).f(|req| HttpResponse::NotFound());
r.route().filter(pred::Not(pred::Get()))
.f(|req| HttpResponse::MethodNotAllowed());
})
# .finish();
}
```

View File

@ -1,357 +0,0 @@
# Request & Response
## Response
A builder-like pattern is used to construct an instance of `HttpResponse`.
`HttpResponse` provides several methods that return a `HttpResponseBuilder` instance,
which implements various convenience methods for building responses.
> Check the [documentation](../actix_web/dev/struct.HttpResponseBuilder.html)
> for type descriptions.
The methods `.body`, `.finish`, and `.json` finalize response creation and
return a constructed *HttpResponse* instance. If this methods is called on the same
builder instance multiple times, the builder will panic.
```rust
# extern crate actix_web;
use actix_web::{HttpRequest, HttpResponse, http::ContentEncoding};
fn index(req: HttpRequest) -> HttpResponse {
HttpResponse::Ok()
.content_encoding(ContentEncoding::Br)
.content_type("plain/text")
.header("X-Hdr", "sample")
.body("data")
}
# fn main() {}
```
## Content encoding
Actix automatically *compresses*/*decompresses* payloads. The following codecs are supported:
* Brotli
* Gzip
* Deflate
* Identity
If request headers contain a `Content-Encoding` header, the request payload is decompressed
according to the header value. Multiple codecs are not supported,
i.e: `Content-Encoding: br, gzip`.
Response payload is compressed based on the *content_encoding* parameter.
By default, `ContentEncoding::Auto` is used. If `ContentEncoding::Auto` is selected,
then the compression depends on the request's `Accept-Encoding` header.
> `ContentEncoding::Identity` can be used to disable compression.
> If another content encoding is selected, the compression is enforced for that codec.
For example, to enable `brotli` use `ContentEncoding::Br`:
```rust
# extern crate actix_web;
use actix_web::{HttpRequest, HttpResponse, http::ContentEncoding};
fn index(req: HttpRequest) -> HttpResponse {
HttpResponse::Ok()
.content_encoding(ContentEncoding::Br)
.body("data")
}
# fn main() {}
```
In this case we explicitly disable content compression
by setting content encoding to a `Identity` value:
```rust
# extern crate actix_web;
use actix_web::{HttpRequest, HttpResponse, http::ContentEncoding};
fn index(req: HttpRequest) -> HttpResponse {
HttpResponse::Ok()
.content_encoding(ContentEncoding::Identity) // <- disable compression
.body("data")
}
# fn main() {}
```
Also it is possible to set default content encoding on application level, by
default `ContentEncoding::Auto` is used, which implies automatic content compression
negotiation.
```rust
# extern crate actix_web;
use actix_web::{App, HttpRequest, HttpResponse, http::ContentEncoding};
fn index(req: HttpRequest) -> HttpResponse {
HttpResponse::Ok()
.body("data")
}
fn main() {
let app = App::new()
.default_encoding(ContentEncoding::Identity) // <- disable compression for all routes
.resource("/index.html", |r| r.with(index));
}
```
## JSON Request
There are several options for json body deserialization.
The first option is to use *Json* extractor. First, you define a handler function
that accepts `Json<T>` as a parameter, then, you use the `.with()` method for registering
this handler. It is also possible to accept arbitrary valid json object by
using `serde_json::Value` as a type `T`.
```rust
# extern crate actix_web;
#[macro_use] extern crate serde_derive;
use actix_web::{App, Json, Result, http};
#[derive(Deserialize)]
struct Info {
username: String,
}
/// extract `Info` using serde
fn index(info: Json<Info>) -> Result<String> {
Ok(format!("Welcome {}!", info.username))
}
fn main() {
let app = App::new().resource(
"/index.html",
|r| r.method(http::Method::POST).with(index)); // <- use `with` extractor
}
```
Another option is to use *HttpResponse::json()*. This method returns a
[*JsonBody*](../actix_web/dev/struct.JsonBody.html) object which resolves into
the deserialized value.
```rust
# extern crate actix;
# extern crate actix_web;
# extern crate futures;
# extern crate serde_json;
# #[macro_use] extern crate serde_derive;
# use actix_web::*;
# use futures::Future;
#[derive(Debug, Serialize, Deserialize)]
struct MyObj {
name: String,
number: i32,
}
fn index(mut req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
req.json().from_err()
.and_then(|val: MyObj| {
println!("model: {:?}", val);
Ok(HttpResponse::Ok().json(val)) // <- send response
})
.responder()
}
# fn main() {}
```
You may also manually load the payload into memory and then deserialize it.
In the following example, we will deserialize a *MyObj* struct. We need to load the request
body first and then deserialize the json into an object.
```rust
# extern crate actix_web;
# extern crate futures;
# use actix_web::*;
# #[macro_use] extern crate serde_derive;
extern crate serde_json;
use futures::{Future, Stream};
#[derive(Serialize, Deserialize)]
struct MyObj {name: String, number: i32}
fn index(req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
// `concat2` will asynchronously read each chunk of the request body and
// return a single, concatenated, chunk
req.concat2()
// `Future::from_err` acts like `?` in that it coerces the error type from
// the future into the final error type
.from_err()
// `Future::and_then` can be used to merge an asynchronous workflow with a
// synchronous workflow
.and_then(|body| { // <- body is loaded, now we can deserialize json
let obj = serde_json::from_slice::<MyObj>(&body)?;
Ok(HttpResponse::Ok().json(obj)) // <- send response
})
.responder()
}
# fn main() {}
```
> A complete example for both options is available in
> [examples directory](https://github.com/actix/actix-web/tree/master/examples/json/).
## JSON Response
The `Json` type allows to respond with well-formed JSON data: simply return a value of
type Json<T> where `T` is the type of a structure to serialize into *JSON*.
The type `T` must implement the `Serialize` trait from *serde*.
```rust
# extern crate actix_web;
#[macro_use] extern crate serde_derive;
use actix_web::{App, HttpRequest, Json, Result, http::Method};
#[derive(Serialize)]
struct MyObj {
name: String,
}
fn index(req: HttpRequest) -> Result<Json<MyObj>> {
Ok(Json(MyObj{name: req.match_info().query("name")?}))
}
fn main() {
App::new()
.resource(r"/a/{name}", |r| r.method(Method::GET).f(index))
.finish();
}
```
## Chunked transfer encoding
Actix automatically decodes *chunked* encoding. `HttpRequest::payload()` already contains
the decoded byte stream. If the request payload is compressed with one of the supported
compression codecs (br, gzip, deflate), then the byte stream is decompressed.
Chunked encoding on a response can be enabled with `HttpResponseBuilder::chunked()`.
This takes effect only for `Body::Streaming(BodyStream)` or `Body::StreamingContext` bodies.
If the response payload compression is enabled and a streaming body is used, chunked encoding
is enabled automatically.
> Enabling chunked encoding for *HTTP/2.0* responses is forbidden.
```rust
# extern crate bytes;
# extern crate actix_web;
# extern crate futures;
# use futures::Stream;
use actix_web::*;
use bytes::Bytes;
use futures::stream::once;
fn index(req: HttpRequest) -> HttpResponse {
HttpResponse::Ok()
.chunked()
.body(Body::Streaming(Box::new(once(Ok(Bytes::from_static(b"data"))))))
}
# fn main() {}
```
## Multipart body
Actix provides multipart stream support.
[*Multipart*](../actix_web/multipart/struct.Multipart.html) is implemented as
a stream of multipart items. Each item can be a
[*Field*](../actix_web/multipart/struct.Field.html) or a nested *Multipart* stream.
`HttpResponse::multipart()` returns the *Multipart* stream for the current request.
The following demonstrates multipart stream handling for a simple form:
```rust,ignore
# extern crate actix_web;
use actix_web::*;
fn index(req: HttpRequest) -> Box<Future<...>> {
req.multipart() // <- get multipart stream for current request
.and_then(|item| { // <- iterate over multipart items
match item {
// Handle multipart Field
multipart::MultipartItem::Field(field) => {
println!("==== FIELD ==== {:?} {:?}", field.headers(), field.content_type());
Either::A(
// Field in turn is a stream of *Bytes* objects
field.map(|chunk| {
println!("-- CHUNK: \n{}",
std::str::from_utf8(&chunk).unwrap());})
.fold((), |_, _| result(Ok(()))))
},
multipart::MultipartItem::Nested(mp) => {
// Or item could be nested Multipart stream
Either::B(result(Ok(())))
}
}
})
}
```
> A full example is available in the
> [examples directory](https://github.com/actix/actix-web/tree/master/examples/multipart/).
## Urlencoded body
Actix provides support for *application/x-www-form-urlencoded* encoded bodies.
`HttpResponse::urlencoded()` returns a
[*UrlEncoded*](../actix_web/dev/struct.UrlEncoded.html) future, which resolves
to the deserialized instance. The type of the instance must implement the
`Deserialize` trait from *serde*.
The *UrlEncoded* future can resolve into an error in several cases:
* content type is not `application/x-www-form-urlencoded`
* transfer encoding is `chunked`.
* content-length is greater than 256k
* payload terminates with error.
```rust
# extern crate actix_web;
# extern crate futures;
#[macro_use] extern crate serde_derive;
use actix_web::*;
use futures::future::{Future, ok};
#[derive(Deserialize)]
struct FormData {
username: String,
}
fn index(mut req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
req.urlencoded::<FormData>() // <- get UrlEncoded future
.from_err()
.and_then(|data| { // <- deserialized instance
println!("USERNAME: {:?}", data.username);
ok(HttpResponse::Ok().into())
})
.responder()
}
# fn main() {}
```
## Streaming request
*HttpRequest* is a stream of `Bytes` objects. It can be used to read the request
body payload.
In the following example, we read and print the request payload chunk by chunk:
```rust
# extern crate actix_web;
# extern crate futures;
# use futures::future::result;
use actix_web::*;
use futures::{Future, Stream};
fn index(mut req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
req.from_err()
.fold((), |_, chunk| {
println!("Chunk: {:?}", chunk);
result::<_, error::PayloadError>(Ok(()))
})
.map(|_| HttpResponse::Ok().finish())
.responder()
}
# fn main() {}
```

View File

@ -1,176 +0,0 @@
# Testing
Every application should be well tested. Actix provides tools to perform unit and
integration tests.
## Unit tests
For unit testing, actix provides a request builder type and a simple handler runner.
[*TestRequest*](../actix_web/test/struct.TestRequest.html) implements a builder-like pattern.
You can generate a `HttpRequest` instance with `finish()`, or you can
run your handler with `run()` or `run_async()`.
```rust
# extern crate actix_web;
use actix_web::{http, test, HttpRequest, HttpResponse, HttpMessage};
fn index(req: HttpRequest) -> HttpResponse {
if let Some(hdr) = req.headers().get(http::header::CONTENT_TYPE) {
if let Ok(s) = hdr.to_str() {
return HttpResponse::Ok().into()
}
}
HttpResponse::BadRequest().into()
}
fn main() {
let resp = test::TestRequest::with_header("content-type", "text/plain")
.run(index)
.unwrap();
assert_eq!(resp.status(), http::StatusCode::OK);
let resp = test::TestRequest::default()
.run(index)
.unwrap();
assert_eq!(resp.status(), http::StatusCode::BAD_REQUEST);
}
```
## Integration tests
There are several methods for testing your application. Actix provides
[*TestServer*](../actix_web/test/struct.TestServer.html), which can be used
to run the application with specific handlers in a real http server.
`TestServer::get()`, `TestServer::post()`, and `TestServer::client()`
methods can be used to send requests to the test server.
A simple form `TestServer` can be configured to use a handler.
`TestServer::new` method accepts a configuration function, and the only argument
for this function is a *test application* instance.
> Check the [api documentation](../actix_web/test/struct.TestApp.html) for more information.
```rust
# extern crate actix_web;
use actix_web::{HttpRequest, HttpResponse, HttpMessage};
use actix_web::test::TestServer;
fn index(req: HttpRequest) -> HttpResponse {
HttpResponse::Ok().into()
}
fn main() {
let mut srv = TestServer::new(|app| app.handler(index)); // <- Start new test server
let request = srv.get().finish().unwrap(); // <- create client request
let response = srv.execute(request.send()).unwrap(); // <- send request to the server
assert!(response.status().is_success()); // <- check response
let bytes = srv.execute(response.body()).unwrap(); // <- read response body
}
```
The other option is to use an application factory. In this case, you need to pass the factory
function the same way as you would for real http server configuration.
```rust
# extern crate actix_web;
use actix_web::{http, test, App, HttpRequest, HttpResponse};
fn index(req: HttpRequest) -> HttpResponse {
HttpResponse::Ok().into()
}
/// This function get called by http server.
fn create_app() -> App {
App::new()
.resource("/test", |r| r.h(index))
}
fn main() {
let mut srv = test::TestServer::with_factory(create_app); // <- Start new test server
let request = srv.client(
http::Method::GET, "/test").finish().unwrap(); // <- create client request
let response = srv.execute(request.send()).unwrap(); // <- send request to the server
assert!(response.status().is_success()); // <- check response
}
```
If you need more complex application configuration, use the `TestServer::build_with_state()`
method. For example, you may need to initialize application state or start `SyncActor`'s for diesel
interation. This method accepts a closure that constructs the application state,
and it runs when the actix system is configured. Thus, you can initialize any additional actors.
```rust,ignore
#[test]
fn test() {
let srv = TestServer::build_with_state(|| { // <- construct builder with config closure
// we can start diesel actors
let addr = SyncArbiter::start(3, || {
DbExecutor(SqliteConnection::establish("test.db").unwrap())
});
// then we can construct custom state, or it could be `()`
MyState{addr: addr}
})
.start(|app| { // <- register server handlers and start test server
app.resource(
"/{username}/index.html", |r| r.with(
|p: Path<PParam>| format!("Welcome {}!", p.username)));
});
// now we can run our test code
);
```
## WebSocket server tests
It is possible to register a *handler* with `TestApp::handler()`, which
initiates a web socket connection. *TestServer* provides the method `ws()`, which connects to
the websocket server and returns ws reader and writer objects. *TestServer* also
provides an `execute()` method, which runs future objects to completion and returns
result of the future computation.
The following example demonstrates how to test a websocket handler:
```rust
# extern crate actix;
# extern crate actix_web;
# extern crate futures;
# extern crate http;
# extern crate bytes;
use actix_web::*;
use futures::Stream;
# use actix::prelude::*;
struct Ws; // <- WebSocket actor
impl Actor for Ws {
type Context = ws::WebsocketContext<Self>;
}
impl StreamHandler<ws::Message, ws::ProtocolError> for Ws {
fn handle(&mut self, msg: ws::Message, ctx: &mut Self::Context) {
match msg {
ws::Message::Text(text) => ctx.text(text),
_ => (),
}
}
}
fn main() {
let mut srv = test::TestServer::new( // <- start our server with ws handler
|app| app.handler(|req| ws::start(req, Ws)));
let (reader, mut writer) = srv.ws().unwrap(); // <- connect to ws server
writer.text("text"); // <- send message to server
let (item, reader) = srv.execute(reader.into_future()).unwrap(); // <- wait for one message
assert_eq!(item, Some(ws::Message::Text("text".to_owned())));
}
```

View File

@ -1,48 +0,0 @@
# WebSockets
Actix supports WebSockets out-of-the-box. It is possible to convert a request's `Payload`
to a stream of [*ws::Message*](../actix_web/ws/enum.Message.html) with
a [*ws::WsStream*](../actix_web/ws/struct.WsStream.html) and then use stream
combinators to handle actual messages, but it is simpler to handle websocket communications
with an http actor.
The following is an example of a simple websocket echo server:
```rust
# extern crate actix;
# extern crate actix_web;
use actix::*;
use actix_web::*;
/// Define http actor
struct Ws;
impl Actor for Ws {
type Context = ws::WebsocketContext<Self>;
}
/// Handler for ws::Message message
impl StreamHandler<ws::Message, ws::ProtocolError> for Ws {
fn handle(&mut self, msg: ws::Message, ctx: &mut Self::Context) {
match msg {
ws::Message::Ping(msg) => ctx.pong(&msg),
ws::Message::Text(text) => ctx.text(text),
ws::Message::Binary(bin) => ctx.binary(bin),
_ => (),
}
}
}
fn main() {
App::new()
.resource("/ws/", |r| r.f(|req| ws::start(req, Ws))) // <- register websocket route
.finish();
}
```
> A simple websocket echo server example is available in the
> [examples directory](https://github.com/actix/actix-web/blob/master/examples/websocket).
> An example chat server with the ability to chat over a websocket or tcp connection
> is available in [websocket-chat directory](https://github.com/actix/actix-web/tree/master/examples/websocket-chat/)

View File

@ -25,7 +25,7 @@
//! Besides the API documentation (which you are currently looking
//! at!), several other resources are available:
//!
//! * [User Guide](https://actix.rs/actix-web/guide/)
//! * [User Guide](https://actix.rs/book/actix-web/)
//! * [Chat on gitter](https://gitter.im/actix/actix)
//! * [GitHub repository](https://github.com/actix/actix-web)
//! * [Cargo package](https://crates.io/crates/actix-web)