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

Merge pull request #163 from memoryruins/guide

Guide: edits to the second half
This commit is contained in:
Nikolay Kim 2018-04-06 19:11:12 -07:00 committed by GitHub
commit 602d78b76c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 153 additions and 141 deletions

View File

@ -2,7 +2,7 @@
## Install Rust
Before we begin, we need to install Rust using the [rustup](https://www.rustup.rs/):
Before we begin, we need to install Rust using [rustup](https://www.rustup.rs/):
```bash
curl https://sh.rustup.rs -sSf | sh

View File

@ -1,23 +1,25 @@
# Middleware
Actix' middleware system allows to add additional behavior to request/response processing.
Middleware can hook into incoming request process and modify request or halt request
processing and return response early. Also it can hook into response processing.
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.
Typically middlewares are involved in the following actions:
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)
Middlewares are registered for each application and are executed in same order as
registration order. In general, a *middleware* is a type that implements the
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.
Here is an example of a simple middleware that adds request and response headers:
The following demonstrates using middleware to add request and response headers:
```rust
# extern crate http;
@ -57,16 +59,17 @@ fn main() {
}
```
Actix provides several useful middlewares, like *logging*, *user sessions*, etc.
> 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 has to be registered for each application. *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).
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
@ -76,6 +79,7 @@ Default `Logger` can be created with `default` method, it uses the default forma
```ignore
%a %t "%r" %s %b "%{Referer}i" "%{User-Agent}i" %T
```
```rust
# extern crate actix_web;
extern crate env_logger;
@ -93,7 +97,7 @@ fn main() {
}
```
Here is an example of the default logging format:
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
@ -126,12 +130,11 @@ INFO:actix_web::middleware::logger: 127.0.0.1:59947 [02/Dec/2017:00:22:40 -0800]
`%{FOO}e` os.environ['FOO']
## Default headers
To set default response headers the `DefaultHeaders` middleware can be used. The
To set default response headers, the `DefaultHeaders` middleware can be used. The
*DefaultHeaders* middleware does not set the header if response headers already contain
the specified header.
a specified header.
```rust
# extern crate actix_web;
@ -153,27 +156,28 @@ fn main() {
## User sessions
Actix provides a general solution for session management. The
[*Session storage*](../actix_web/middleware/struct.SessionStorage.html) middleware can be
[**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
could be added later.
[*Cookie session backend*](../actix_web/middleware/struct.CookieSessionBackend.html)
uses signed cookies as session storage. *Cookie session backend* creates sessions which
are limited to storing fewer than 4000 bytes of data (as the payload must fit into a
single cookie). Internal server error is generated if session contains more than 4000 bytes.
> By default, only cookie session backend is implemented. Other backend implementations
> can be added.
You need to pass a random value to the constructor of *CookieSessionBackend*.
This is private key for cookie session. When this value is changed, all session data is lost.
Note that whatever you write into your session is visible by the user (but not modifiable).
[**CookieSessionBackend**](../actix_web/middleware/struct.CookieSessionBackend.html)
uses signed 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.
In general case, you create
[*Session storage*](../actix_web/middleware/struct.SessionStorage.html) middleware
and initializes it with specific backend implementation, like *CookieSessionBackend*.
To access session data
You need to pass a random value to the constructor of `CookieSessionBackend`.
This is a private key for cookie session. When this value is changed, all session data is lost.
> **Note**: anything you write into the session is visible by the user, but it is not modifiable.
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)
has to be used. This method returns a
[*Session*](../actix_web/middleware/struct.Session.html) object, which allows to get or set
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
@ -212,12 +216,12 @@ fn main() {
## Error handlers
`ErrorHandlers` middleware allows to provide custom handlers for responses.
`ErrorHandlers` middleware allows us to provide custom handlers for responses.
You can use `ErrorHandlers::handler()` method to register a custom error handler
for specific status code. You can modify existing response or create completly new
one. Error handler can return response immediately or return future that resolves
to a response.
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;

View File

@ -2,8 +2,8 @@
## Individual file
It is possible to serve static files with custom path pattern and `NamedFile`. To
match path tail we can use `[.*]` regex.
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;
@ -24,9 +24,9 @@ fn main() {
## Directory
To serve files from specific directory and sub-directories `StaticFiles` could be used.
`StaticFiles` must be registered with `App::handler()` method otherwise
it won't be able to serve sub-paths.
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;
@ -39,11 +39,11 @@ fn main() {
}
```
First parameter is a base directory. Second parameter is *show_index*, if it is set to *true*
directory listing would be returned for directories, if it is set to *false*
then *404 Not Found* would be returned instead of directory listing.
The first parameter is the base directory. If the second parameter, *show_index*, is set to **true**,
the directory listing will be returned, and if it is set to **false**,
*404 Not Found* will be returned.
Instead of showing files listing for directory, it is possible to redirect to specific
index file. Use
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,13 +1,15 @@
# HTTP/2.0
Actix web automatically upgrades connection to *HTTP/2.0* if possible.
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). At the moment only
`rust-openssl` has support. Turn on the `alpn` feature to enable `alpn` negotiation.
With enabled `alpn` feature `HttpServer` provides the
[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
@ -35,10 +37,10 @@ fn main() {
}
```
Upgrade to *HTTP/2.0* schema described in
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)
Please check [example](https://github.com/actix/actix-web/tree/master/examples/tls)
for a concrete example.
> Check out [examples/tls](https://github.com/actix/actix-web/tree/master/examples/tls)
> for a concrete example.

View File

@ -2,13 +2,14 @@
## Diesel
At the moment of 1.0 release Diesel does not support asynchronous operations.
But it possible to use the `actix` synchronous actor system as a db interface api.
Technically sync actors are worker style actors, multiple of them
can be run in parallel and process messages from same queue (sync actors work in mpsc mode).
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.
Let's create a simple db api that can insert a new user row into an SQLite table.
We have to define sync actor and connection that this actor will use. The same approach
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
@ -21,7 +22,7 @@ impl Actor for DbExecutor {
}
```
This is the definition of our actor. Now we need to define the *create user* message and response.
This is the definition of our actor. Now, we must define the *create user* message and response.
```rust,ignore
struct CreateUser {
@ -33,8 +34,8 @@ impl Message for CreateUser {
}
```
We can send a `CreateUser` message to the `DbExecutor` actor, and as a result we get a
`User` model instance. Now we need to define the actual handler implementation for this message.
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 {
@ -67,7 +68,7 @@ impl Handler<CreateUser> for DbExecutor {
}
```
That's it. Now we can use the *DbExecutor* actor from any http handler or middleware.
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.
@ -97,9 +98,9 @@ fn main() {
}
```
And finally we can use the address in a request handler. We get a message response
asynchronously, so the handler needs to return a future object, also `Route::a()` needs to be
used for async handler registration.
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
@ -120,8 +121,8 @@ fn index(req: HttpRequest<State>) -> Box<Future<Item=HttpResponse, Error=Error>>
}
```
Full example is available in the
[examples directory](https://github.com/actix/actix-web/tree/master/examples/diesel/).
> 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).
> 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

@ -4,10 +4,13 @@
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 that helps building responses.
Check [documentation](../actix_web/dev/struct.HttpResponseBuilder.html)
for type descriptions. The methods `.body`, `.finish`, `.json` finalize response creation and
return a constructed *HttpResponse* instance. If this methods is called for the same
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
@ -26,7 +29,7 @@ fn index(req: HttpRequest) -> HttpResponse {
## Content encoding
Actix automatically *compresses*/*decompresses* payloads. Following codecs are supported:
Actix automatically *compresses*/*decompresses* payloads. The following codecs are supported:
* Brotli
* Gzip
@ -37,11 +40,13 @@ Actix automatically *compresses*/*decompresses* payloads. Following codecs are s
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 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 this codec. For example,
to enable `brotli` use `ContentEncoding::Br`:
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;
@ -55,15 +60,14 @@ fn index(req: HttpRequest) -> HttpResponse {
# fn main() {}
```
## JSON Request
There are several options for json body deserialization.
The first option is to use *Json* extractor. You define handler function
that accepts `Json<T>` as a parameter and use `.with()` method for registering
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`
using `serde_json::Value` as a type `T`.
```rust
# extern crate actix_web;
@ -87,7 +91,7 @@ fn main() {
}
```
The second option is to use *HttpResponse::json()*. This method returns a
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.
@ -116,8 +120,9 @@ fn index(mut req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
# fn main() {}
```
Or you can manually load the payload into memory and then deserialize it.
Here is a simple example. We will deserialize a *MyObj* struct. We need to load the request
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
@ -149,15 +154,14 @@ fn index(req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
# fn main() {}
```
A complete example for both options is available in
[examples directory](https://github.com/actix/actix-web/tree/master/examples/json/).
> 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*.
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;
@ -184,14 +188,14 @@ fn main() {
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) the byte stream is decompressed.
compression codecs (br, gzip, deflate), then the byte stream is decompressed.
Chunked encoding on response can be enabled with `HttpResponseBuilder::chunked()`.
But this takes effect only for `Body::Streaming(BodyStream)` or `Body::StreamingContext` bodies.
Also if response payload compression is enabled and streaming body is used, chunked encoding
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.
> Enabling chunked encoding for *HTTP/2.0* responses is forbidden.
```rust
# extern crate bytes;
@ -214,11 +218,11 @@ fn index(req: HttpRequest) -> HttpResponse {
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
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.
In simple form multipart stream handling can be implemented similar to this example
The following demonstrates multipart stream handling for a simple form:
```rust,ignore
# extern crate actix_web;
@ -248,17 +252,18 @@ fn index(req: HttpRequest) -> Box<Future<...>> {
}
```
A full example is available in the
[examples directory](https://github.com/actix/actix-web/tree/master/examples/multipart/).
> 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
a error in several cases:
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`.
@ -294,7 +299,7 @@ fn index(mut req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
*HttpRequest* is a stream of `Bytes` objects. It can be used to read the request
body payload.
In this example handle reads the request payload chunk by chunk and prints every chunk.
In the following example, we read and print the request payload chunk by chunk:
```rust
# extern crate actix_web;

View File

@ -5,9 +5,9 @@ integration tests.
## Unit tests
For unit testing actix provides a request builder type and simple handler runner.
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
You can generate a `HttpRequest` instance with `finish()`, or you can
run your handler with `run()` or `run_async()`.
```rust
@ -36,19 +36,20 @@ fn main() {
}
```
## Integration tests
There are several methods how you can test your application. Actix provides
[*TestServer*](../actix_web/test/struct.TestServer.html)
server that can be used to run the whole application of just specific handlers
in real http server. *TestServer::get()*, *TestServer::post()* or *TestServer::client()*
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.
In simple form *TestServer* can be configured to use handler. *TestServer::new* method
accepts configuration function, only argument for this function is *test application*
instance. You can check the [api documentation](../actix_web/test/struct.TestApp.html)
for more information.
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;
@ -70,8 +71,8 @@ fn main() {
}
```
The other option is to use an application factory. In this case you need to pass the factory
function same way as you would for real http server configuration.
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;
@ -98,11 +99,10 @@ fn main() {
}
```
If you need more complex application configuration, for example you may need to
initialize application state or start `SyncActor`'s for diesel interation, you
can use `TestServer::build_with_state()` method. This method accepts closure
that has to construct application state. This closure runs when actix system is
configured already, so you can initialize any additional actors.
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]
@ -127,13 +127,13 @@ fn test() {
## WebSocket server tests
It is possible to register a *handler* with `TestApp::handler()` that
initiates a web socket connection. *TestServer* provides `ws()` which connects to
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
provides an `execute()` method, which runs future objects to completion and returns
result of the future computation.
Here is a simple example that shows how to test server websocket handler.
The following example demonstrates how to test a websocket handler:
```rust
# extern crate actix;

View File

@ -3,10 +3,10 @@
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
combinators to handle actual messages, but it is simpler to handle websocket communications
with an http actor.
This is example of a simple websocket echo server:
The following is an example of a simple websocket echo server:
```rust
# extern crate actix;
@ -41,8 +41,8 @@ fn main() {
}
```
A simple websocket echo server example is available in the
[examples directory](https://github.com/actix/actix-web/blob/master/examples/websocket).
> 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/)
> 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/)