2017-12-11 23:16:29 +01:00
|
|
|
# Request & Response
|
2017-12-02 20:41:20 +01:00
|
|
|
|
2017-12-05 05:38:38 +01:00
|
|
|
## Response
|
|
|
|
|
2018-03-28 22:16:01 +02:00
|
|
|
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.
|
2017-12-05 05:38:38 +01:00
|
|
|
Check [documentation](../actix_web/dev/struct.HttpResponseBuilder.html)
|
2018-03-28 22:16:01 +02:00
|
|
|
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
|
|
|
|
builder instance multiple times, the builder will panic.
|
2017-12-05 05:38:38 +01:00
|
|
|
|
|
|
|
```rust
|
|
|
|
# extern crate actix_web;
|
2018-03-31 02:31:18 +02:00
|
|
|
use actix_web::{HttpRequest, HttpResponse, http::ContentEncoding};
|
2017-12-05 05:38:38 +01:00
|
|
|
|
|
|
|
fn index(req: HttpRequest) -> HttpResponse {
|
|
|
|
HttpResponse::Ok()
|
|
|
|
.content_encoding(ContentEncoding::Br)
|
|
|
|
.content_type("plain/text")
|
|
|
|
.header("X-Hdr", "sample")
|
2018-03-31 08:07:33 +02:00
|
|
|
.body("data")
|
2017-12-05 05:38:38 +01:00
|
|
|
}
|
|
|
|
# fn main() {}
|
|
|
|
```
|
|
|
|
|
2017-12-02 20:41:20 +01:00
|
|
|
## Content encoding
|
|
|
|
|
2018-03-28 22:16:01 +02:00
|
|
|
Actix automatically *compresses*/*decompresses* payloads. Following codecs are supported:
|
2017-12-02 20:41:20 +01:00
|
|
|
|
|
|
|
* Brotli
|
|
|
|
* Gzip
|
|
|
|
* Deflate
|
|
|
|
* Identity
|
2018-03-28 22:16:01 +02:00
|
|
|
|
|
|
|
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.
|
2017-12-04 05:09:46 +01:00
|
|
|
By default `ContentEncoding::Auto` is used. If `ContentEncoding::Auto` is selected
|
2018-03-28 22:16:01 +02:00
|
|
|
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`:
|
2017-12-04 05:09:46 +01:00
|
|
|
|
|
|
|
```rust
|
2017-12-05 01:26:40 +01:00
|
|
|
# extern crate actix_web;
|
2018-03-31 02:31:18 +02:00
|
|
|
use actix_web::{HttpRequest, HttpResponse, http::ContentEncoding};
|
2017-12-04 03:58:15 +01:00
|
|
|
|
|
|
|
fn index(req: HttpRequest) -> HttpResponse {
|
|
|
|
HttpResponse::Ok()
|
|
|
|
.content_encoding(ContentEncoding::Br)
|
2018-03-31 08:07:33 +02:00
|
|
|
.body("data")
|
2017-12-04 03:58:15 +01:00
|
|
|
}
|
2017-12-04 05:09:46 +01:00
|
|
|
# fn main() {}
|
2017-12-04 03:58:15 +01:00
|
|
|
```
|
2017-12-21 00:12:43 +01:00
|
|
|
|
|
|
|
|
|
|
|
## JSON Request
|
|
|
|
|
2018-03-31 18:18:25 +02:00
|
|
|
There are several options for json body deserialization.
|
2017-12-21 00:12:43 +01:00
|
|
|
|
2018-03-31 18:18:25 +02:00
|
|
|
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
|
|
|
|
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
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
The second option is to use *HttpResponse::json()*. This method returns a
|
2018-03-28 22:16:01 +02:00
|
|
|
[*JsonBody*](../actix_web/dev/struct.JsonBody.html) object which resolves into
|
|
|
|
the deserialized value.
|
2017-12-21 00:12:43 +01:00
|
|
|
|
2017-12-21 05:30:54 +01:00
|
|
|
```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)]
|
2017-12-21 00:12:43 +01:00
|
|
|
struct MyObj {
|
|
|
|
name: String,
|
|
|
|
number: i32,
|
|
|
|
}
|
2017-12-21 05:30:54 +01:00
|
|
|
|
|
|
|
fn index(mut req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
|
|
|
|
req.json().from_err()
|
|
|
|
.and_then(|val: MyObj| {
|
|
|
|
println!("model: {:?}", val);
|
2018-03-31 08:07:33 +02:00
|
|
|
Ok(HttpResponse::Ok().json(val)) // <- send response
|
2017-12-21 05:30:54 +01:00
|
|
|
})
|
|
|
|
.responder()
|
|
|
|
}
|
|
|
|
# fn main() {}
|
2017-12-21 00:12:43 +01:00
|
|
|
```
|
|
|
|
|
2018-03-28 22:16:01 +02:00
|
|
|
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
|
|
|
|
body first and then deserialize the json into an object.
|
2017-12-21 00:12:43 +01:00
|
|
|
|
2017-12-25 17:12:13 +01:00
|
|
|
```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}
|
|
|
|
|
2018-02-26 17:02:58 +01:00
|
|
|
fn index(req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
|
2017-12-21 01:05:07 +01:00
|
|
|
// `concat2` will asynchronously read each chunk of the request body and
|
|
|
|
// return a single, concatenated, chunk
|
2018-02-26 17:02:58 +01:00
|
|
|
req.concat2()
|
2017-12-21 01:05:07 +01:00
|
|
|
// `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
|
2017-12-21 01:13:21 +01:00
|
|
|
.and_then(|body| { // <- body is loaded, now we can deserialize json
|
|
|
|
let obj = serde_json::from_slice::<MyObj>(&body)?;
|
2018-03-31 08:07:33 +02:00
|
|
|
Ok(HttpResponse::Ok().json(obj)) // <- send response
|
2017-12-21 01:05:07 +01:00
|
|
|
})
|
2017-12-25 17:12:13 +01:00
|
|
|
.responder()
|
2017-12-21 00:12:43 +01:00
|
|
|
}
|
2017-12-25 17:12:13 +01:00
|
|
|
# fn main() {}
|
2017-12-21 00:12:43 +01:00
|
|
|
```
|
|
|
|
|
2018-03-28 22:16:01 +02:00
|
|
|
A complete example for both options is available in
|
2017-12-21 00:12:43 +01:00
|
|
|
[examples directory](https://github.com/actix/actix-web/tree/master/examples/json/).
|
|
|
|
|
|
|
|
|
2017-12-04 03:51:52 +01:00
|
|
|
## JSON Response
|
|
|
|
|
2018-03-31 18:18:25 +02:00
|
|
|
The `Json` type allows to respond with well-formed JSON data: simply return a value of
|
2018-03-28 22:16:01 +02:00
|
|
|
type Json<T> where T is the type of a structure to serialize into *JSON*. The
|
2017-12-04 03:51:52 +01:00
|
|
|
type `T` must implement the `Serialize` trait from *serde*.
|
|
|
|
|
|
|
|
```rust
|
2017-12-05 01:26:40 +01:00
|
|
|
# extern crate actix_web;
|
2017-12-04 03:51:52 +01:00
|
|
|
#[macro_use] extern crate serde_derive;
|
2018-03-31 09:16:55 +02:00
|
|
|
use actix_web::{App, HttpRequest, Json, Result, http::Method};
|
2017-12-04 03:51:52 +01:00
|
|
|
|
|
|
|
#[derive(Serialize)]
|
|
|
|
struct MyObj {
|
|
|
|
name: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
fn index(req: HttpRequest) -> Result<Json<MyObj>> {
|
|
|
|
Ok(Json(MyObj{name: req.match_info().query("name")?}))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn main() {
|
2018-03-31 09:16:55 +02:00
|
|
|
App::new()
|
2017-12-04 23:07:53 +01:00
|
|
|
.resource(r"/a/{name}", |r| r.method(Method::GET).f(index))
|
2017-12-04 03:51:52 +01:00
|
|
|
.finish();
|
|
|
|
}
|
|
|
|
```
|
2017-12-14 07:36:28 +01:00
|
|
|
|
|
|
|
## Chunked transfer encoding
|
|
|
|
|
2018-03-28 22:16:01 +02:00
|
|
|
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.
|
2017-12-14 07:36:28 +01:00
|
|
|
|
2018-03-28 22:16:01 +02:00
|
|
|
Chunked encoding on response can be enabled with `HttpResponseBuilder::chunked()`.
|
2017-12-14 07:36:28 +01:00
|
|
|
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
|
2018-03-28 22:16:01 +02:00
|
|
|
is enabled automatically.
|
2017-12-14 07:36:28 +01:00
|
|
|
|
|
|
|
Enabling chunked encoding for *HTTP/2.0* responses is forbidden.
|
|
|
|
|
|
|
|
```rust
|
2018-02-27 01:41:57 +01:00
|
|
|
# extern crate bytes;
|
2017-12-14 07:36:28 +01:00
|
|
|
# extern crate actix_web;
|
2018-02-26 17:02:58 +01:00
|
|
|
# extern crate futures;
|
|
|
|
# use futures::Stream;
|
2017-12-14 07:36:28 +01:00
|
|
|
use actix_web::*;
|
2018-02-27 01:41:57 +01:00
|
|
|
use bytes::Bytes;
|
|
|
|
use futures::stream::once;
|
2017-12-14 07:36:28 +01:00
|
|
|
|
|
|
|
fn index(req: HttpRequest) -> HttpResponse {
|
|
|
|
HttpResponse::Ok()
|
|
|
|
.chunked()
|
2018-03-31 08:07:33 +02:00
|
|
|
.body(Body::Streaming(Box::new(once(Ok(Bytes::from_static(b"data"))))))
|
2017-12-14 07:36:28 +01:00
|
|
|
}
|
|
|
|
# fn main() {}
|
|
|
|
```
|
|
|
|
|
|
|
|
## Multipart body
|
|
|
|
|
2018-03-28 22:16:01 +02:00
|
|
|
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.
|
2017-12-19 18:55:49 +01:00
|
|
|
|
2018-03-28 22:16:01 +02:00
|
|
|
In simple form multipart stream handling can be implemented similar to this example
|
2017-12-19 18:55:49 +01:00
|
|
|
|
2017-12-19 19:10:03 +01:00
|
|
|
```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) => {
|
2018-01-13 20:17:48 +01:00
|
|
|
println!("==== FIELD ==== {:?} {:?}", field.headers(), field.content_type());
|
2018-03-28 22:16:01 +02:00
|
|
|
|
2017-12-19 19:10:03 +01:00
|
|
|
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) => {
|
2018-03-28 22:16:01 +02:00
|
|
|
// Or item could be nested Multipart stream
|
2017-12-19 19:10:03 +01:00
|
|
|
Either::B(result(Ok(())))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2018-03-28 22:16:01 +02:00
|
|
|
A full example is available in the
|
2017-12-19 19:10:03 +01:00
|
|
|
[examples directory](https://github.com/actix/actix-web/tree/master/examples/multipart/).
|
2017-12-14 07:36:28 +01:00
|
|
|
|
|
|
|
## Urlencoded body
|
|
|
|
|
2018-03-28 22:16:01 +02:00
|
|
|
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
|
2017-12-19 23:03:01 +01:00
|
|
|
into `HashMap<String, String>` which contains decoded parameters.
|
2018-03-28 22:16:01 +02:00
|
|
|
The *UrlEncoded* future can resolve into a error in several cases:
|
2017-12-19 23:03:01 +01:00
|
|
|
|
|
|
|
* 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;
|
|
|
|
use actix_web::*;
|
|
|
|
use futures::future::{Future, ok};
|
|
|
|
|
|
|
|
fn index(mut req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
|
2017-12-21 06:06:04 +01:00
|
|
|
req.urlencoded() // <- get UrlEncoded future
|
|
|
|
.from_err()
|
|
|
|
.and_then(|params| { // <- url encoded parameters
|
|
|
|
println!("==== BODY ==== {:?}", params);
|
2018-03-31 08:07:33 +02:00
|
|
|
ok(HttpResponse::Ok().into())
|
2017-12-21 06:06:04 +01:00
|
|
|
})
|
|
|
|
.responder()
|
2017-12-19 23:03:01 +01:00
|
|
|
}
|
|
|
|
# fn main() {}
|
|
|
|
```
|
|
|
|
|
2017-12-14 07:36:28 +01:00
|
|
|
|
|
|
|
## Streaming request
|
|
|
|
|
2018-03-28 22:16:01 +02:00
|
|
|
*HttpRequest* is a stream of `Bytes` objects. It can be used to read the request
|
2018-02-27 00:26:27 +01:00
|
|
|
body payload.
|
2017-12-19 09:18:57 +01:00
|
|
|
|
2018-03-28 22:16:01 +02:00
|
|
|
In this example handle reads the request payload chunk by chunk and prints every chunk.
|
2017-12-19 09:18:57 +01:00
|
|
|
|
|
|
|
```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>> {
|
2018-02-25 18:34:26 +01:00
|
|
|
req.from_err()
|
2017-12-21 06:06:04 +01:00
|
|
|
.fold((), |_, chunk| {
|
|
|
|
println!("Chunk: {:?}", chunk);
|
|
|
|
result::<_, error::PayloadError>(Ok(()))
|
|
|
|
})
|
2018-03-31 08:07:33 +02:00
|
|
|
.map(|_| HttpResponse::Ok().finish())
|
2017-12-21 06:06:04 +01:00
|
|
|
.responder()
|
2017-12-19 09:18:57 +01:00
|
|
|
}
|
|
|
|
# fn main() {}
|
|
|
|
```
|