From 8aa39e1afb83deca0c86ca5adcedf3c983bdca2d Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Wed, 12 Jun 2019 04:51:45 -0400 Subject: [PATCH 01/68] begin update of docs to actix-web 1.0 --- config.toml | 2 +- content/docs/getting-started.md | 5 +++-- content/docs/installation.md | 4 ++-- examples/application/Cargo.toml | 2 +- examples/getting-started/Cargo.toml | 2 +- examples/getting-started/src/main.rs | 30 ++++++++++++++++++++++------ examples/server/Cargo.toml | 2 +- examples/url-dispatch/Cargo.toml | 2 +- layouts/index.html | 18 ++++++++--------- 9 files changed, 43 insertions(+), 24 deletions(-) diff --git a/config.toml b/config.toml index 5f25122..e815c7e 100644 --- a/config.toml +++ b/config.toml @@ -16,4 +16,4 @@ baseURL = "https://actix.rs" [params] actixVersion = "0.7" -actixWebVersion = "0.7" +actixWebVersion = "1.0" diff --git a/content/docs/getting-started.md b/content/docs/getting-started.md index b0833e6..50b6a34 100644 --- a/content/docs/getting-started.md +++ b/content/docs/getting-started.md @@ -27,6 +27,7 @@ actix-web = "{{< actix-version "actix-web" >}}" In order to implement a web server, we first need to create a request handler. + A request handler is a function that accepts an `HttpRequest` instance as its only parameter and returns a type that can be converted into `HttpResponse`: @@ -34,12 +35,12 @@ Filename: `src/main.rs` {{< include-example example="getting-started" section="setup" >}} + 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`: diff --git a/content/docs/url-dispatch.md b/content/docs/url-dispatch.md index 3f76b39..cef0595 100644 --- a/content/docs/url-dispatch.md +++ b/content/docs/url-dispatch.md @@ -391,7 +391,7 @@ resource names. For example: -{{< include-example example="url-dispatch" file="prefix.rs" section="prefix" >}} +{{< include-example example="url-dispatch" file="scope.rs" section="scope" >}} In the above example, the *show_users* route will have an effective route pattern of */users/show* instead of */show* because the application's prefix argument will be prepended diff --git a/examples/application/Cargo.toml b/examples/application/Cargo.toml index a201c1d..62e6064 100644 --- a/examples/application/Cargo.toml +++ b/examples/application/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "application" version = "0.7.0" +edition = "2018" workspace = "../" [dependencies] diff --git a/examples/application/src/main.rs b/examples/application/src/main.rs index 726f857..172c57e 100644 --- a/examples/application/src/main.rs +++ b/examples/application/src/main.rs @@ -1,36 +1,31 @@ -#![allow(unused)] -extern crate actix_web; -use actix_web::{http::Method, server, App, HttpRequest, HttpResponse, Responder}; +#![allow(unused_variables)] +use actix_web::{web, App, HttpRequest, HttpResponse, HttpServer, Responder}; mod state; mod vh; +#[rustfmt::skip] fn make_app() { + // -fn index(req: &HttpRequest) -> impl Responder { +fn index(_req: HttpRequest) -> impl Responder { "Hello world!" } let app = App::new() - .prefix("/app") - .resource("/index.html", |r| r.method(Method::GET).f(index)) - .finish() + .service(web::scope("/app").route("/index.html", web::get().to(index))); // -; + } +#[rustfmt::skip] fn run_server() { // -let server = 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())), - ] +let server = HttpServer::new(|| { + App::new() + .service(web::scope("/app1").route("/", web::to(|| HttpResponse::Ok()))) + .service(web::scope("/app2").route("/", web::to(|| HttpResponse::Ok()))) + .route("/", web::to(|| HttpResponse::Ok())) }); // } diff --git a/examples/application/src/state.rs b/examples/application/src/state.rs index 062006c..19fd96d 100644 --- a/examples/application/src/state.rs +++ b/examples/application/src/state.rs @@ -1,5 +1,6 @@ +#![allow(dead_code, unused)] // -use actix_web::{http, App, HttpRequest}; +use actix_web::{web, App, HttpRequest, HttpResponse, HttpServer}; use std::cell::Cell; // This struct represents state @@ -7,38 +8,41 @@ struct AppState { counter: Cell, } -fn index(req: &HttpRequest) -> String { - let count = req.state().counter.get() + 1; // <- get count - req.state().counter.set(count); // <- store new count in state +fn index(data: web::Data) -> String { + let count = data.counter.get() + 1; // <- get count + data.counter.set(count); // <- store new count in state format!("Request number: {}", count) // <- response with count } // +#[rustfmt::skip] fn make_app() { // -App::with_state(AppState { counter: Cell::new(0) }) - .resource("/", |r| r.method(http::Method::GET).f(index)) - .finish() +App::new() + .data( AppState { counter: Cell::new(0) }) + .route("/", web::get().to(index)); // -; } +#[rustfmt::skip] fn start_app() { // -server::new(|| { - App::with_state(AppState { counter: Cell::new(0) }) - .resource("/", |r| r.method(http::Method::GET).f(index)) -}).bind("127.0.0.1:8080") - .unwrap() - .run() +HttpServer::new(|| { + App::new() + .data( AppState { counter: Cell::new(0) }) + .route("/", web::get().to(index)) +}) +.bind("127.0.0.1:8088") +.unwrap() +.run() +.unwrap(); // -; } -use actix_web::{server, HttpResponse}; use std::thread; +#[rustfmt::skip] fn combine() { thread::spawn(|| { // @@ -46,20 +50,23 @@ struct State1; struct State2; fn main() { - server::new(|| { - vec![ - App::with_state(State1) - .prefix("/app1") - .resource("/", |r| r.f(|r| HttpResponse::Ok())) - .boxed(), - App::with_state(State2) - .prefix("/app2") - .resource("/", |r| r.f(|r| HttpResponse::Ok())) - .boxed(), - ] - }).bind("127.0.0.1:8080") - .unwrap() - .run() + HttpServer::new(|| { + App::new() + .data(State1) + .data(State2) + .service( + web::scope("/app1") + .route("/", web::to(|| HttpResponse::Ok())), + ) + .service( + web::scope("/app2") + .route("/", web::to(|| HttpResponse::Ok())), + ) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // }); diff --git a/examples/application/src/vh.rs b/examples/application/src/vh.rs index 12d3a56..88f60bd 100644 --- a/examples/application/src/vh.rs +++ b/examples/application/src/vh.rs @@ -1,20 +1,22 @@ #![allow(unused)] -use actix_web::{http::Method, pred, server, App, HttpRequest, HttpResponse, Responder}; +use actix_web::{guard, web, App, HttpRequest, HttpResponse, HttpServer, Responder}; // fn main() { - let server = server::new(|| { - vec![ - App::new() - .filter(pred::Host("www.rust-lang.org")) - .resource("/", |r| r.f(|r| HttpResponse::Ok())), - App::new() - .filter(pred::Host("users.rust-lang.org")) - .resource("/", |r| r.f(|r| HttpResponse::Ok())), - App::new().resource("/", |r| r.f(|r| HttpResponse::Ok())), - ] - }); - - server.run(); + HttpServer::new(|| { + App::new() + .service( + web::scope("/") + .guard(guard::Header("Host", "www.rust-lang.org")) + .route("", web::to(|| HttpResponse::Ok())), + ) + .service( + web::scope("/") + .guard(guard::Header("Host", "users.rust-lang.org")) + .route("", web::to(|| HttpResponse::Ok())), + ) + .route("/", web::to(|| HttpResponse::Ok())) + }) + .run(); } // diff --git a/examples/url-dispatch/Cargo.toml b/examples/url-dispatch/Cargo.toml index f73460f..0602c8e 100644 --- a/examples/url-dispatch/Cargo.toml +++ b/examples/url-dispatch/Cargo.toml @@ -9,4 +9,3 @@ actix-web = "1.0" futures = "0.1" openssl = "0.10" serde = "1.0" -serde_derive = "1.0" diff --git a/examples/url-dispatch/src/main.rs b/examples/url-dispatch/src/main.rs index ac19232..38b76a2 100644 --- a/examples/url-dispatch/src/main.rs +++ b/examples/url-dispatch/src/main.rs @@ -3,7 +3,6 @@ extern crate actix_web; extern crate futures; extern crate openssl; #[macro_use] -extern crate serde_derive; extern crate serde; mod cfg; @@ -16,9 +15,9 @@ mod path2; mod pbuf; mod pred; mod pred2; -mod prefix; mod resource; mod scope; +mod scope; mod url_ext; mod urls; diff --git a/examples/url-dispatch/src/prefix.rs b/examples/url-dispatch/src/prefix.rs deleted file mode 100644 index 8b3985d..0000000 --- a/examples/url-dispatch/src/prefix.rs +++ /dev/null @@ -1,14 +0,0 @@ -use actix_web::{App, HttpRequest, HttpResponse}; - -// -fn show_users(req: &HttpRequest) -> HttpResponse { - unimplemented!() -} - -fn main() { - App::new() - .prefix("/users") - .resource("/show", |r| r.f(show_users)) - .finish(); -} -// diff --git a/examples/url-dispatch/src/scope.rs b/examples/url-dispatch/src/scope.rs index 8c8f5bd..6180b07 100644 --- a/examples/url-dispatch/src/scope.rs +++ b/examples/url-dispatch/src/scope.rs @@ -1,54 +1,13 @@ -#![allow(dead_code)] -use actix_web::{http::Method, App, HttpRequest}; +use actix_web::{App, HttpRequest, HttpResponse}; -fn get_projects(_: &HttpRequest) -> String { - unimplemented!() -} -fn create_project(_: &HttpRequest) -> String { - unimplemented!() -} -fn update_project(_: HttpRequest) -> String { - unimplemented!() -} -fn delete_project(_: &HttpRequest) -> String { - unimplemented!() -} -fn get_tasks(_: &HttpRequest) -> String { - unimplemented!() -} -fn create_task(_: &HttpRequest) -> String { - unimplemented!() -} -fn update_task(_: HttpRequest) -> String { - unimplemented!() -} -fn delete_task(_: HttpRequest) -> String { - unimplemented!() -} - -fn main() { // -App::new().scope("/project", |proj_scope| { - proj_scope - .resource("", |r| { - r.method(Method::GET).f(get_projects); - r.method(Method::POST).f(create_project) - }) - .resource("/{project_id}", |r| { - r.method(Method::PUT).with(update_project); - r.method(Method::DELETE).f(delete_project) - }) - .nested("/{project_id}/task", |task_scope| { - task_scope - .resource("", |r| { - r.method(Method::GET).f(get_tasks); - r.method(Method::POST).f(create_task) - }) - .resource("/{task_id}", |r| { - r.method(Method::PUT).with(update_task); - r.method(Method::DELETE).with(delete_task) - }) - }) -}); -// +fn show_users(_req: HttpRequest) -> HttpResponse { + unimplemented!() } + +#[rustfmt::skip] +fn main() { + App::new().service( + web::scope("/users") .route("/show", web::to(show_users))) +} +// From 8ab3e358514b75c18fab7f499ec034dbaa8a3e3a Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Thu, 13 Jun 2019 17:10:51 -0400 Subject: [PATCH 11/68] First pass at Server section. --- content/docs/server.md | 15 +++++------- examples/server/Cargo.toml | 5 ++-- examples/server/rustfmt.toml | 1 + examples/server/src/ka.rs | 14 ----------- examples/server/src/ka_tp.rs | 2 +- examples/server/src/keep_alive.rs | 20 ++++++++++++++++ examples/server/src/keep_alive_tp.rs | 10 ++++++++ examples/server/src/main.rs | 23 ++++++++---------- examples/server/src/signals.rs | 35 +++++++++++++++++++--------- examples/server/src/ssl.rs | 18 ++++++++------ examples/server/src/workers.rs | 10 ++++---- 11 files changed, 92 insertions(+), 61 deletions(-) create mode 100644 examples/server/rustfmt.toml delete mode 100644 examples/server/src/ka.rs create mode 100644 examples/server/src/keep_alive.rs create mode 100644 examples/server/src/keep_alive_tp.rs diff --git a/content/docs/server.md b/content/docs/server.md index 697ac7b..614411f 100644 --- a/content/docs/server.md +++ b/content/docs/server.md @@ -17,15 +17,12 @@ To bind to a specific socket address, [`bind()`](../../actix-web/actix_web/server/struct.HttpServer.html#method.bind) must be used, and it may be called multiple times. To bind ssl socket, [`bind_ssl()`](../../actix-web/actix_web/server/struct.HttpServer.html#method.bind_ssl) -or [`bind_tls()`](../../actix-web/actix_web/server/struct.HttpServer.html#method.bind_tls) +or [`bind_rustls()`](../../actix-web/1.0.0/actix_web/struct.HttpServer.html#method.bind_rustls) should be used. To start the http server, use one of the start methods. - use [`start()`](../../actix-web/actix_web/server/struct.HttpServer.html#method.start) for a server -`HttpServer` is an actix actor. It must be initialized within a properly -configured actix system: - {{< include-example example="server" section="main" >}} > It is possible to start a server in a separate thread with the `run()` method. In that @@ -59,12 +56,12 @@ is not shared between threads. To share state, `Arc` could be used. ## SSL -There are two features for ssl server: `tls` and `alpn`. The `tls` feature is -for `native-tls` integration and `alpn` is for `openssl`. +There are two features for ssl server: `rust-tls` and `ssl`. The `tls` feature is +for `rust-tls` integration and `ssl` is for `openssl`. ```toml [dependencies] -actix-web = { version = "{{< actix-version "actix-web" >}}", features = ["alpn"] } +actix-web = { version = "{{< actix-version "actix-web" >}}", features = ["ssl"] } ``` {{< include-example example="server" file="ssl.rs" section="ssl" >}} @@ -95,7 +92,7 @@ Actix can wait for requests on a keep-alive connection. - `None` or `KeepAlive::Disabled` - disable *keep alive*. - `KeepAlive::Tcp(75)` - use `SO_KEEPALIVE` socket option. -{{< include-example example="server" file="ka.rs" section="ka" >}} +{{< include-example example="server" file="keep_alive.rs" section="keep-alive" >}} If the first option is selected, then *keep alive* state is calculated based on the response's *connection-type*. By default @@ -106,7 +103,7 @@ defined by the request's http version. *Connection type* can be changed with `HttpResponseBuilder::connection_type()` method. -{{< include-example example="server" file="ka_tp.rs" section="example" >}} +{{< include-example example="server" file="keep_alive_tp.rs" section="example" >}} ## Graceful shutdown diff --git a/examples/server/Cargo.toml b/examples/server/Cargo.toml index 56a56a3..d90d6fe 100644 --- a/examples/server/Cargo.toml +++ b/examples/server/Cargo.toml @@ -2,9 +2,10 @@ name = "server" version = "0.7.0" workspace = "../" +edition = "2018" [dependencies] -actix = "0.7" -actix-web = "1.0" +actix-rt = "0.2" +actix-web = { version = "1.0", features = ["ssl"] } futures = "0.1" openssl = "0.10" diff --git a/examples/server/rustfmt.toml b/examples/server/rustfmt.toml new file mode 100644 index 0000000..df99c69 --- /dev/null +++ b/examples/server/rustfmt.toml @@ -0,0 +1 @@ +max_width = 80 diff --git a/examples/server/src/ka.rs b/examples/server/src/ka.rs deleted file mode 100644 index 675110c..0000000 --- a/examples/server/src/ka.rs +++ /dev/null @@ -1,14 +0,0 @@ -// -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 -} -// diff --git a/examples/server/src/ka_tp.rs b/examples/server/src/ka_tp.rs index bb3c0a8..a9a9a7b 100644 --- a/examples/server/src/ka_tp.rs +++ b/examples/server/src/ka_tp.rs @@ -1,7 +1,7 @@ // use actix_web::{http, HttpRequest, HttpResponse}; -fn index(req: HttpRequest) -> HttpResponse { +pub fn index(req: HttpRequest) -> HttpResponse { HttpResponse::Ok() .connection_type(http::ConnectionType::Close) // <- Close connection .force_close() // <- Alternative method diff --git a/examples/server/src/keep_alive.rs b/examples/server/src/keep_alive.rs new file mode 100644 index 0000000..b078961 --- /dev/null +++ b/examples/server/src/keep_alive.rs @@ -0,0 +1,20 @@ +// +use actix_web::{web, App, HttpResponse, HttpServer}; + +fn main() { + HttpServer::new(|| { + App::new().route("/", web::get().to(|| HttpResponse::Ok())) + }) + .keep_alive(75); // <- Set keep-alive to 75 seconds + + HttpServer::new(|| { + App::new().route("/", web::get().to(|| HttpResponse::Ok())) + }) + .keep_alive(server::KeepAlive::Tcp(75)); // <- Use `SO_KEEPALIVE` socket option. + + HttpServer::new(|| { + App::new().route("/", web::get().to(|| HttpResponse::Ok())) + }) + .keep_alive(None); // <- Disable keep-alive +} +// diff --git a/examples/server/src/keep_alive_tp.rs b/examples/server/src/keep_alive_tp.rs new file mode 100644 index 0000000..aac81cc --- /dev/null +++ b/examples/server/src/keep_alive_tp.rs @@ -0,0 +1,10 @@ +// +use actix_web::{http, HttpRequest, HttpResponse}; + +fn index(req: HttpRequest) -> HttpResponse { + HttpResponse::Ok() + .connection_type(http::ConnectionType::Close) // <- Close connection + .force_close() // <- Alternative method + .finish() +} +// diff --git a/examples/server/src/main.rs b/examples/server/src/main.rs index 3006fe2..ef236f4 100644 --- a/examples/server/src/main.rs +++ b/examples/server/src/main.rs @@ -1,24 +1,21 @@ -extern crate actix; -extern crate actix_web; -extern crate futures; -extern crate openssl; - -mod ka; -mod ka_tp; +mod keep_alive; +mod keep_alive_tp; mod signals; mod ssl; mod workers; //
-use actix_web::{server::HttpServer, App, HttpResponse}; +use actix_web::{web, App, HttpResponse, HttpServer}; fn main() { - let sys = actix::System::new("guide"); + let sys = actix_rt::System::new("example"); - HttpServer::new(|| App::new().resource("/", |r| r.f(|_| HttpResponse::Ok()))) - .bind("127.0.0.1:59080") - .unwrap() - .start(); + HttpServer::new(|| { + App::new().route("/", web::get().to(|| HttpResponse::Ok())) + }) + .bind("127.0.0.1:8088") + .unwrap() + .start(); let _ = sys.run(); } diff --git a/examples/server/src/signals.rs b/examples/server/src/signals.rs index bc0d935..f926622 100644 --- a/examples/server/src/signals.rs +++ b/examples/server/src/signals.rs @@ -1,28 +1,41 @@ -use actix; +use actix_rt; use futures::Future; // -use actix_web::{server, App, HttpResponse}; +use actix_web::{web, App, HttpResponse, HttpServer}; use std::sync::mpsc; use std::thread; -fn main() { +pub 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())) + let sys = actix_rt::System::new("http-server"); + + let addr = HttpServer::new(|| { + App::new().route("/", web::get().to(|| 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(); + .bind("127.0.0.1:8088") + .unwrap() + .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. + let _ = addr + .pause() + .wait() + .map(|_| println!("`actix_server::ServerCommand::Pause`")); + let _ = addr + .resume() + .wait() + .map(|_| println!("`actix_server::ServerCommand::Resume`")); + let _ = addr + .stop(true) + .wait() + .map(|_| println!("`actix_server::ServerCommand::Stop`")); } // diff --git a/examples/server/src/ssl.rs b/examples/server/src/ssl.rs index 2b58256..08f9ce1 100644 --- a/examples/server/src/ssl.rs +++ b/examples/server/src/ssl.rs @@ -1,22 +1,26 @@ // -use actix_web::{server, App, HttpRequest, Responder}; +use actix_web::{web, App, HttpRequest, HttpServer, Responder}; use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod}; -fn index(req: &HttpRequest) -> impl Responder { +fn index(_req: HttpRequest) -> impl Responder { "Welcome!" } -fn main() { +pub fn main() { // load ssl keys - let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); + 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_ssl("127.0.0.1:8080", builder) + HttpServer::new(|| App::new().route("/", web::get().to(index))) + .bind_ssl("127.0.0.1:8088", builder) .unwrap() - .run(); + .run() + .unwrap(); } // +// +// sssl rust-tls diff --git a/examples/server/src/workers.rs b/examples/server/src/workers.rs index 89cf498..f7eba99 100644 --- a/examples/server/src/workers.rs +++ b/examples/server/src/workers.rs @@ -1,8 +1,10 @@ // -use actix_web::{server::HttpServer, App, HttpResponse}; +use actix_web::{web, App, HttpResponse, HttpServer}; -fn main() { - HttpServer::new(|| App::new().resource("/", |r| r.f(|_| HttpResponse::Ok()))) - .workers(4); // <- Start 4 workers +pub fn main() { + HttpServer::new(|| { + App::new().route("/", web::get().to(|| HttpResponse::Ok())) + }) + .workers(4); // <- Start 4 workers } // From ebc6a446507826660da5c82ec53440f7158fa25f Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Thu, 13 Jun 2019 17:13:45 -0400 Subject: [PATCH 12/68] Fixes typo. --- content/docs/application.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/application.md b/content/docs/application.md index c9178a5..c77f3e6 100644 --- a/content/docs/application.md +++ b/content/docs/application.md @@ -80,7 +80,7 @@ This limitation can easily be overcome with the [App::boxed](https://docs.rs/act ## Using an Application Scope to Compose Applications -The `web::wcope()` method allows to set a specific application prefix. +The `web::scope()` method allows to set a specific application prefix. This scope 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 From f7b22dfdc049c1950248ae91645cdb85a4897745 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Sat, 15 Jun 2019 16:37:08 -0400 Subject: [PATCH 13/68] First pass at Handlers chapter. --- content/docs/handlers.md | 191 +----------------- examples/Cargo.toml | 6 + examples/async-handlers/Cargo.toml | 9 + examples/async-handlers/src/async_stream.rs | 24 +++ examples/async-handlers/src/main.rs | 25 +++ examples/async-handlers/src/stream.rs | 17 ++ examples/either/Cargo.toml | 8 + examples/either/src/main.rs | 29 +++ examples/request-handlers/Cargo.toml | 8 + examples/request-handlers/src/handlers_arc.rs | 34 ++++ examples/request-handlers/src/main.rs | 25 +++ examples/responder-trait/Cargo.toml | 9 + examples/responder-trait/src/main.rs | 37 ++++ 13 files changed, 238 insertions(+), 184 deletions(-) create mode 100644 examples/async-handlers/Cargo.toml create mode 100644 examples/async-handlers/src/async_stream.rs create mode 100644 examples/async-handlers/src/main.rs create mode 100644 examples/async-handlers/src/stream.rs create mode 100644 examples/either/Cargo.toml create mode 100644 examples/either/src/main.rs create mode 100644 examples/request-handlers/Cargo.toml create mode 100644 examples/request-handlers/src/handlers_arc.rs create mode 100644 examples/request-handlers/src/main.rs create mode 100644 examples/responder-trait/Cargo.toml create mode 100644 examples/responder-trait/src/main.rs diff --git a/content/docs/handlers.md b/content/docs/handlers.md index f0bdc36..2923dbe 100644 --- a/content/docs/handlers.md +++ b/content/docs/handlers.md @@ -62,69 +62,12 @@ it must be implemented. Here is an example of a handler that stores the number of processed requests: -```rust -use actix_web::{App, HttpRequest, HttpResponse, dev::Handler}; - -struct MyHandler(Cell); - -impl Handler for MyHandler { - type Result = HttpResponse; - - /// Handle request - fn handle(&self, req: &HttpRequest) -> Self::Result { - let i = self.0.get(); - self.0.set(i + 1); - HttpResponse::Ok().into() - } -} - -fn main(){ - server::new(|| App::new() - .resource("/", |r| r.h(MyHandler(Cell::new(0))))) //use r.h() to bind handler, not the r.f() - .bind("127.0.0.1:8080") - .unwrap() - .run(); -} -``` +{{< include-example example="request-handlers" file="main.rs" section="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 -use actix_web::{server, App, HttpRequest, HttpResponse, dev::Handler}; -use std::sync::Arc; -use std::sync::atomic::{AtomicUsize, Ordering}; - -struct MyHandler(Arc); - -impl Handler for MyHandler { - type Result = HttpResponse; - - /// Handle request - fn handle(&self, req: &HttpRequest) -> 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"); - let _ = sys.run(); -} -``` +{{< include-example example="request-handlers" file="handlers_arc.rs" section="arc" >}} > Be careful with synchronization primitives like `Mutex` or `RwLock`. The `actix-web` framework > handles requests asynchronously. By blocking thread execution, all concurrent @@ -137,51 +80,7 @@ To return a custom type directly from a handler function, the type needs to impl 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 { - let body = serde_json::to_string(&self)?; - - // Create response and set content type - Ok(HttpResponse::Ok() - .content_type("application/json") - .body(body)) - } -} - -fn index(req: &HttpRequest) -> impl Responder { - 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"); - let _ = sys.run(); -} -``` +{{< include-example example="responder-trait" file="main.rs" section="main" >}} ## Async handlers @@ -190,55 +89,12 @@ or more precisely, any type that implements the [*Responder*](../../actix-web/ac In this case, the handler must return a `Future` object that resolves to the *Responder* type, i.e: -```rust -use actix_web::*; -use bytes::Bytes; -use futures::stream::once; -use futures::future::{Future, result}; - -fn index(req: &HttpRequest) -> Box> { - - result(Ok(HttpResponse::Ok() - .content_type("text/html") - .body(format!("Hello!")))) - .responder() -} - -fn index2(req: &HttpRequest) -> Box> { - result(Ok("Welcome!")) - .responder() -} - -fn main() { - App::new() - .resource("/async", |r| r.route().a(index)) - .resource("/", |r| r.route().a(index2)) - .finish(); -} -``` +{{< include-example example="async-handlers" file="main.rs" section="main" >}} Or the response body can be generated asynchronously. In this case, body must implement the stream trait `Stream`, i.e: -```rust -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(); -} -``` +{{< include-example example="async-handlers" file="stream.rs" section="main" >}} Both methods can be combined. (i.e Async response with streaming body) @@ -246,23 +102,7 @@ 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 -use actix_web::*; -use bytes::Bytes; -use futures::stream::once; -use futures::future::{Future, result}; - -fn index(req: &HttpRequest) -> Result>, Error> { - if is_error() { - Err(error::ErrorBadRequest("bad request")) - } else { - Ok(Box::new( - result(Ok(HttpResponse::Ok() - .content_type("text/html") - .body(format!("Hello!")))))) - } -} -``` +{{< include-example example="async-handlers" file="async_stream.rs" section="main" >}} ## Different return types (Either) @@ -272,21 +112,4 @@ you can error check and return errors, return async responses, or any result tha For this case, the [*Either*](../../actix-web/actix_web/enum.Either.html) type can be used. `Either` allows combining two different responder types into a single type. -```rust -use futures::future::{Future, result}; -use actix_web::{Either, Error, HttpResponse}; - -type RegisterResult = Either>>; - -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()) - } -} -``` +{{< include-example example="either" file="main.rs" section="main" >}} diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 444f971..328991a 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -9,4 +9,10 @@ members = [ "request-routing", "server", "url-dispatch", + "responder-trait", + "either" +] +exclude = [ + "request-handlers", + "async-handlers", ] diff --git a/examples/async-handlers/Cargo.toml b/examples/async-handlers/Cargo.toml new file mode 100644 index 0000000..fef635a --- /dev/null +++ b/examples/async-handlers/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "async-handlers" +version = "0.1.0" +edition = "2018" + +[dependencies] +actix-web = "0.7" +futures = "0.1" +bytes = "0.4" diff --git a/examples/async-handlers/src/async_stream.rs b/examples/async-handlers/src/async_stream.rs new file mode 100644 index 0000000..2641e21 --- /dev/null +++ b/examples/async-handlers/src/async_stream.rs @@ -0,0 +1,24 @@ +fn is_error() -> bool { + true +} + +//
+use actix_web::{error, App, Error, HttpRequest, HttpResponse}; +use futures::future::{result, Future}; + +fn index( + _req: &HttpRequest, +) -> Result>, Error> { + if is_error() { + Err(error::ErrorBadRequest("bad request")) + } else { + Ok(Box::new(result(Ok(HttpResponse::Ok() + .content_type("text/html") + .body(format!("Hello!")))))) + } +} +//
+ +pub fn main() { + App::new().resource("/", |r| r.route().f(index)).finish(); +} diff --git a/examples/async-handlers/src/main.rs b/examples/async-handlers/src/main.rs new file mode 100644 index 0000000..b8c5f8f --- /dev/null +++ b/examples/async-handlers/src/main.rs @@ -0,0 +1,25 @@ +mod async_stream; +mod stream; +//
+use actix_web::{App, AsyncResponder, Error, HttpRequest, HttpResponse}; +use futures::future::{result, Future}; + +fn index(_req: &HttpRequest) -> Box> { + result(Ok(HttpResponse::Ok() + .content_type("text/html") + .body(format!("Hello!")))) + .responder() +} + +fn index2(_req: &HttpRequest) -> Box> { + result(Ok("Welcome!")).responder() +} + +fn main() { + App::new() + .resource("/async", |r| r.route().a(index)) + .resource("/", |r| r.route().a(index2)) + // .resource("/", |r| r.route().f(async_stream::index)) + .finish(); +} +//
diff --git a/examples/async-handlers/src/stream.rs b/examples/async-handlers/src/stream.rs new file mode 100644 index 0000000..da4c8a0 --- /dev/null +++ b/examples/async-handlers/src/stream.rs @@ -0,0 +1,17 @@ +//
+use actix_web::{App, Body, HttpRequest, HttpResponse}; +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))) +} + +pub fn main() { + App::new().resource("/async", |r| r.f(index)).finish(); +} +//
diff --git a/examples/either/Cargo.toml b/examples/either/Cargo.toml new file mode 100644 index 0000000..dfaf7bc --- /dev/null +++ b/examples/either/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "either" +version = "0.1.0" +edition = "2018" + +[dependencies] +actix-web = "1.0" +futures = "0.1" diff --git a/examples/either/src/main.rs b/examples/either/src/main.rs new file mode 100644 index 0000000..453239d --- /dev/null +++ b/examples/either/src/main.rs @@ -0,0 +1,29 @@ +//
+use actix_web::{web, App, Either, Error, HttpRequest, HttpResponse}; +use futures::future::{ok, Future}; + +type RegisterResult = + Either>>; + +fn index(_req: HttpRequest) -> RegisterResult { + if is_a_variant() { + // <- choose variant A + Either::A(HttpResponse::BadRequest().body("Bad data")) + } else { + Either::B( + // <- variant B + Box::new(ok(HttpResponse::Ok() + .content_type("text/html") + .body(format!("Hello!")))), + ) + } +} + +fn main() { + App::new().route("/", web::get().to(index)); +} +//
+ +fn is_a_variant() -> bool { + true +} diff --git a/examples/request-handlers/Cargo.toml b/examples/request-handlers/Cargo.toml new file mode 100644 index 0000000..1fb4d7d --- /dev/null +++ b/examples/request-handlers/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "request-handlers" +version = "0.1.0" +edition = "2018" + +[dependencies] +actix-web = "0.7" +actix = "0.7" diff --git a/examples/request-handlers/src/handlers_arc.rs b/examples/request-handlers/src/handlers_arc.rs new file mode 100644 index 0000000..9858355 --- /dev/null +++ b/examples/request-handlers/src/handlers_arc.rs @@ -0,0 +1,34 @@ +// +use actix_web::{dev::Handler, server, App, HttpRequest, HttpResponse}; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Arc; + +struct MyHandler(Arc); + +impl Handler for MyHandler { + type Result = HttpResponse; + + /// Handle request + fn handle(&self, _req: &HttpRequest) -> Self::Result { + self.0.fetch_add(1, Ordering::Relaxed); + HttpResponse::Ok().into() + } +} + +pub 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"); + let _ = sys.run(); +} +// diff --git a/examples/request-handlers/src/main.rs b/examples/request-handlers/src/main.rs new file mode 100644 index 0000000..84d7aca --- /dev/null +++ b/examples/request-handlers/src/main.rs @@ -0,0 +1,25 @@ +mod handlers_arc; +//
+use actix_web::{dev::Handler, server, App, HttpRequest, HttpResponse}; +use std::cell::Cell; + +struct MyHandler(Cell); + +impl Handler for MyHandler { + type Result = HttpResponse; + + /// Handle request + fn handle(&self, _req: &HttpRequest) -> Self::Result { + let i = self.0.get(); + self.0.set(i + 1); + HttpResponse::Ok().into() + } +} + +fn main() { + server::new(|| App::new().resource("/", |r| r.h(MyHandler(Cell::new(0))))) //use r.h() to bind handler, not the r.f() + .bind("127.0.0.1:8088") + .unwrap() + .run(); +} +//
diff --git a/examples/responder-trait/Cargo.toml b/examples/responder-trait/Cargo.toml new file mode 100644 index 0000000..1b921cc --- /dev/null +++ b/examples/responder-trait/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "responder-trait" +version = "0.1.0" +edition = "2018" + +[dependencies] +actix-web = "1.0" +serde = "1.0" +serde_json = "1.0" diff --git a/examples/responder-trait/src/main.rs b/examples/responder-trait/src/main.rs new file mode 100644 index 0000000..e635151 --- /dev/null +++ b/examples/responder-trait/src/main.rs @@ -0,0 +1,37 @@ +//
+use actix_web::{web, App, Error, HttpRequest, HttpResponse, HttpServer, Responder}; +use serde::Serialize; +use serde_json; + +#[derive(Serialize)] +struct MyObj { + name: &'static str, +} + +// Responder +impl Responder for MyObj { + type Error = Error; + type Future = Result; + + fn respond_to(self, _req: &HttpRequest) -> Self::Future { + let body = serde_json::to_string(&self)?; + + // Create response and set content type + Ok(HttpResponse::Ok() + .content_type("application/json") + .body(body)) + } +} + +fn index(_req: HttpRequest) -> impl Responder { + MyObj { name: "user" } +} + +fn main() { + HttpServer::new(|| App::new().route("/", web::get().to(index))) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); +} +//
From cb31379c103c27e3719bfe1db40223f6621154a4 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Sat, 15 Jun 2019 17:00:15 -0400 Subject: [PATCH 14/68] renames file to be more discoverable. --- examples/server/src/ka_tp.rs | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 examples/server/src/ka_tp.rs diff --git a/examples/server/src/ka_tp.rs b/examples/server/src/ka_tp.rs deleted file mode 100644 index a9a9a7b..0000000 --- a/examples/server/src/ka_tp.rs +++ /dev/null @@ -1,10 +0,0 @@ -// -use actix_web::{http, HttpRequest, HttpResponse}; - -pub fn index(req: HttpRequest) -> HttpResponse { - HttpResponse::Ok() - .connection_type(http::ConnectionType::Close) // <- Close connection - .force_close() // <- Alternative method - .finish() -} -// From 5bd4218b942eaf0a74d926dbaada337ee504ef25 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Sat, 15 Jun 2019 17:01:17 -0400 Subject: [PATCH 15/68] comments out keep_alive section to pass builds. --- examples/server/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/server/src/main.rs b/examples/server/src/main.rs index ef236f4..95995d7 100644 --- a/examples/server/src/main.rs +++ b/examples/server/src/main.rs @@ -1,5 +1,5 @@ -mod keep_alive; -mod keep_alive_tp; +// mod keep_alive; +// mod keep_alive_tp; mod signals; mod ssl; mod workers; From a313315a92c358e882b5224498d3200c9eee5cae Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Sun, 16 Jun 2019 20:19:25 -0400 Subject: [PATCH 16/68] begin url-dispatch chapter. --- examples/url-dispatch/Cargo.toml | 1 + examples/url-dispatch/src/main.rs | 14 +++----------- examples/url-dispatch/src/path2.rs | 6 +++--- 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/examples/url-dispatch/Cargo.toml b/examples/url-dispatch/Cargo.toml index 0602c8e..7cabeff 100644 --- a/examples/url-dispatch/Cargo.toml +++ b/examples/url-dispatch/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "url-dispatch" version = "0.7.0" +edition = "2018" workspace = "../" [dependencies] diff --git a/examples/url-dispatch/src/main.rs b/examples/url-dispatch/src/main.rs index 38b76a2..f6d5391 100644 --- a/examples/url-dispatch/src/main.rs +++ b/examples/url-dispatch/src/main.rs @@ -1,10 +1,3 @@ -extern crate actix; -extern crate actix_web; -extern crate futures; -extern crate openssl; -#[macro_use] -extern crate serde; - mod cfg; mod dhandler; mod minfo; @@ -17,12 +10,11 @@ mod pred; mod pred2; mod resource; mod scope; -mod scope; mod url_ext; mod urls; //
-use actix_web::{http::Method, App, HttpRequest, HttpResponse}; +use actix_web::{web, App, HttpRequest, HttpResponse}; fn index(req: HttpRequest) -> HttpResponse { unimplemented!() @@ -30,8 +22,8 @@ fn index(req: HttpRequest) -> HttpResponse { fn main() { App::new() - .route("/user/{name}", Method::GET, index) - .route("/user/{name}", Method::POST, index) + .route("/user/{name}", web::get().to(index)) + .route("/user/{name}", web::get().to(index)) .finish(); } //
diff --git a/examples/url-dispatch/src/path2.rs b/examples/url-dispatch/src/path2.rs index 6f2aea6..b433e1f 100644 --- a/examples/url-dispatch/src/path2.rs +++ b/examples/url-dispatch/src/path2.rs @@ -1,6 +1,6 @@ // -extern crate serde_derive; -use actix_web::{http::Method, App, Path, Result}; +use actix_web::{http::Method, web, App, Result}; +use serde::Deserialize; #[derive(Deserialize)] struct Info { @@ -8,7 +8,7 @@ struct Info { } // extract path info using serde -fn index(info: Path) -> Result { +fn index(info: web::Path) -> Result { Ok(format!("Welcome {}!", info.username)) } From f922e8fb964150f594a3c6891d0c68ddc3180bdd Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Sun, 16 Jun 2019 23:17:17 -0400 Subject: [PATCH 17/68] First pass at Extractors. --- content/docs/extractors.md | 194 ++-------------------- examples/Cargo.toml | 1 + examples/extractors/Cargo.toml | 11 ++ examples/extractors/src/custom_handler.rs | 18 ++ examples/extractors/src/form.rs | 20 +++ examples/extractors/src/json_one.rs | 18 ++ examples/extractors/src/json_two.rs | 34 ++++ examples/extractors/src/main.rs | 48 ++++++ examples/extractors/src/multiple.rs | 20 +++ examples/extractors/src/path_one.rs | 17 ++ examples/extractors/src/path_two.rs | 22 +++ examples/extractors/src/query.rs | 18 ++ 12 files changed, 238 insertions(+), 183 deletions(-) create mode 100644 examples/extractors/Cargo.toml create mode 100644 examples/extractors/src/custom_handler.rs create mode 100644 examples/extractors/src/form.rs create mode 100644 examples/extractors/src/json_one.rs create mode 100644 examples/extractors/src/json_two.rs create mode 100644 examples/extractors/src/main.rs create mode 100644 examples/extractors/src/multiple.rs create mode 100644 examples/extractors/src/path_one.rs create mode 100644 examples/extractors/src/path_two.rs create mode 100644 examples/extractors/src/query.rs diff --git a/content/docs/extractors.md b/content/docs/extractors.md index 684d84d..f6668f6 100644 --- a/content/docs/extractors.md +++ b/content/docs/extractors.md @@ -19,25 +19,8 @@ or a custom Handler type. An Extractor can be passed to a handler function as a function parameter *or* accessed within the function by calling the ExtractorType::<...>::extract(req) function. -```rust -// Option 1: passed as a parameter to a handler function -fn index((params, info): (Path<(String, String,)>, Json)) -> HttpResponse { - ... -} - - -// Option 2: accessed by calling extract() on the Extractor - -use actix_web::FromRequest; - -fn index(req: &HttpRequest) -> HttpResponse { - let params = Path::<(String, String)>::extract(req); - let info = Json::::extract(req); - - ... -} -``` +{{< include-example example="extractors" file="main.rs" section="main" >}} ## Within Custom Handler Types @@ -47,25 +30,7 @@ calling the ExtractorType::<...>::extract(&req) function. An Extractor Handler type must follow the ``handle`` function signature specified by the Handler trait it implements. -```rust - -struct MyHandler(String); - -impl Handler for MyHandler { - type Result = HttpResponse; - - /// Handle request - fn handle(&self, req: &HttpRequest) -> Self::Result { - let params = Path::<(String, String)>::extract(req); - let info = Json::::extract(req); - - ... - - HttpResponse::Ok().into() - } -} - -``` +{{< include-example example="extractors" file="custom_handler.rs" section="custom-handler" >}} # Path @@ -78,51 +43,13 @@ two segments could be deserialized, `userid` and `friend`. These segments could be extracted into a `tuple`, i.e. `Path<(u32, String)>` or any structure that implements the `Deserialize` trait from the *serde* crate. -```rust -use actix_web::{App, Path, Result, http}; - -/// extract path info from "/users/{userid}/{friend}" url -/// {userid} - - deserializes to a u32 -/// {friend} - deserializes to a String -fn index(info: Path<(u32, String)>) -> Result { - Ok(format!("Welcome {}! {}", info.1, info.0)) -} - -fn main() { - let app = App::new().resource( - "/users/{userid}/{friend}", // <- define path parameters - |r| r.method(http::Method::GET).with(index)); // <- use `with` extractor -} -``` - -Remember! A handler function that uses extractors has to be registered using the -[*Route::with()*](../../actix-web/actix_web/dev/struct.Route.html#method.with) method. +{{< include-example example="extractors" file="path_one.rs" section="path-one" >}} It is also possible to extract path information to a specific type that implements the `Deserialize` trait from *serde*. Here is an equivalent example that uses *serde* instead of a *tuple* type. -```rust -#[macro_use] extern crate serde_derive; -use actix_web::{App, Path, Result, http}; - -#[derive(Deserialize)] -struct Info { - userid: u32, - friend: String, -} - -/// extract path info using serde -fn index(info: Path) -> Result { - Ok(format!("Welcome {}!", info.friend)) -} - -fn main() { - let app = App::new().resource( - "/users/{userid}/{friend}", // <- define path parameters - |r| r.method(http::Method::GET).with(index)); // <- use `with` extractor -} -``` +{{< include-example example="extractors" file="path_two.rs" section="path-two" >}} # Query @@ -130,26 +57,7 @@ Same can be done with the request's query. The [*Query*](../../actix-web/actix_web/struct.Query.html) type provides extraction functionality. Underneath it uses *serde_urlencoded* crate. -```rust -#[macro_use] extern crate serde_derive; -use actix_web::{App, Query, http}; - -#[derive(Deserialize)] -struct Info { - username: String, -} - -// this handler get called only if the request's query contains `username` field -fn index(info: Query) -> String { - format!("Welcome {}!", info.username) -} - -fn main() { - let app = App::new().resource( - "/index.html", - |r| r.method(http::Method::GET).with(index)); // <- use `with` extractor -} -``` +{{< include-example example="extractors" file="query.rs" section="query" >}} # Json @@ -157,26 +65,7 @@ fn main() { a request body into a struct. To extract typed information from a request's body, the type `T` must implement the `Deserialize` trait from *serde*. -```rust -#[macro_use] extern crate serde_derive; -use actix_web::{App, Json, Result, http}; - -#[derive(Deserialize)] -struct Info { - username: String, -} - -/// deserialize `Info` from request's body -fn index(info: Json) -> Result { - 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 -} -``` +{{< include-example example="extractors" file="json_one.rs" section="json-one" >}} Some extractors provide a way to configure the extraction process. Json extractor [*JsonConfig*](../../actix-web/actix_web/dev/struct.JsonConfig.html) type for configuration. @@ -186,34 +75,7 @@ payload as well as a custom error handler function. The following example limits the size of the payload to 4kb and uses a custom error handler. -```rust -#[macro_use] extern crate serde_derive; -use actix_web::{App, Json, HttpResponse, Result, http, error}; - -#[derive(Deserialize)] -struct Info { - username: String, -} - -/// deserialize `Info` from request's body, max payload size is 4kb -fn index(info: Json) -> Result { - Ok(format!("Welcome {}!", info.username)) -} - -fn main() { - let app = App::new().resource( - "/index.html", |r| { - r.method(http::Method::POST) - .with_config(index, |cfg| { - cfg.limit(4096) // <- change json extractor configuration - cfg.error_handler(|err, req| { // <- create custom error response - error::InternalError::from_response( - err, HttpResponse::Conflict().finish()).into() - }) - }); - }); -} -``` +{{< include-example example="extractors" file="json_two.rs" section="json-two" >}} # Form @@ -224,23 +86,7 @@ the `Deserialize` trait from the *serde* crate. [*FormConfig*](../../actix-web/actix_web/dev/struct.FormConfig.html) allows configuring the extraction process. -```rust -#[macro_use] extern crate serde_derive; -use actix_web::{App, Form, Result}; - -#[derive(Deserialize)] -struct FormData { - username: String, -} - -/// extract form data using serde -/// this handler gets called only if the content type is *x-www-form-urlencoded* -/// and the content of the request could be deserialized to a `FormData` struct -fn index(form: Form) -> Result { - Ok(format!("Welcome {}!", form.username)) -} -# fn main() {} -``` +{{< include-example example="extractors" file="form.rs" section="form" >}} # Multiple extractors @@ -249,32 +95,14 @@ whose elements implement `FromRequest`. For example we can use a path extractor and a query extractor at the same time. -```rust -#[macro_use] extern crate serde_derive; -use actix_web::{App, Query, Path, http}; - -#[derive(Deserialize)] -struct Info { - username: String, -} - -fn index((path, query): (Path<(u32, String)>, Query)) -> String { - format!("Welcome {}!", query.username) -} - -fn main() { - let app = App::new().resource( - "/users/{userid}/{friend}", // <- define path parameters - |r| r.method(http::Method::GET).with(index)); // <- use `with` extractor -} -``` +{{< include-example example="extractors" file="multiple.rs" section="multi" >}} # Other Actix also provides several other extractors: -* [*State*](../../actix-web/actix_web/struct.State.html) - If you need - access to an application state. This is similar to a `HttpRequest::state()`. +* [*Data*](../../actix-web/actix_web/web/struct.Data.html) - If you need + access to an application state. This is similar to a `HttpRequest::app_data()`. * *HttpRequest* - *HttpRequest* itself is an extractor which returns self, in case you need access to the request. * *String* - You can convert a request's payload to a *String*. diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 328991a..711aaf6 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -15,4 +15,5 @@ members = [ exclude = [ "request-handlers", "async-handlers", + "extractors", ] diff --git a/examples/extractors/Cargo.toml b/examples/extractors/Cargo.toml new file mode 100644 index 0000000..f135edb --- /dev/null +++ b/examples/extractors/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "extractors" +version = "0.1.0" +authors = ["Cameron Dershem "] +edition = "2018" + +[dependencies] +actix-web = "1.0" +serde = "1.0" +futures = "0.1" +serde_json = "1.0" diff --git a/examples/extractors/src/custom_handler.rs b/examples/extractors/src/custom_handler.rs new file mode 100644 index 0000000..93596d9 --- /dev/null +++ b/examples/extractors/src/custom_handler.rs @@ -0,0 +1,18 @@ +use actix_web::{web, HttpRequest, HttpResponse}; + +struct MyHandler {} +struct MyInfo {} + +// +impl Handler for MyHandler { + type Result = HttpResponse; + + /// Handle request + fn handle(&self, req: &HttpRequest) -> Self::Result { + let params = web::Path::<(String, String)>::extract(req); + let info = web::Json::::extract(req); + + HttpResponse::Ok().into() + } +} +// diff --git a/examples/extractors/src/form.rs b/examples/extractors/src/form.rs new file mode 100644 index 0000000..1af09d4 --- /dev/null +++ b/examples/extractors/src/form.rs @@ -0,0 +1,20 @@ +//
+use actix_web::{web, App, Result}; +use serde::Deserialize; + +#[derive(Deserialize)] +struct FormData { + username: String, +} + +/// extract form data using serde +/// this handler gets called only if the content type is *x-www-form-urlencoded* +/// and the content of the request could be deserialized to a `FormData` struct +fn index(form: web::Form) -> Result { + Ok(format!("Welcome {}!", form.username)) +} +// + +pub fn main() { + App::new().route("", web::post().to(index)); +} diff --git a/examples/extractors/src/json_one.rs b/examples/extractors/src/json_one.rs new file mode 100644 index 0000000..d54459b --- /dev/null +++ b/examples/extractors/src/json_one.rs @@ -0,0 +1,18 @@ +// +use actix_web::{web, App, Result}; +use serde::Deserialize; + +#[derive(Deserialize)] +struct Info { + username: String, +} + +/// deserialize `Info` from request's body +fn index(info: web::Json) -> Result { + Ok(format!("Welcome {}!", info.username)) +} + +pub fn main() { + App::new().route("/", web::get().to(index)); +} +// diff --git a/examples/extractors/src/json_two.rs b/examples/extractors/src/json_two.rs new file mode 100644 index 0000000..c6464ac --- /dev/null +++ b/examples/extractors/src/json_two.rs @@ -0,0 +1,34 @@ +// +use actix_web::{error, web, App, FromRequest, HttpResponse, Responder}; +use serde::Deserialize; + +#[derive(Deserialize)] +struct Info { + username: String, +} + +/// deserialize `Info` from request's body, max payload size is 4kb +fn index(info: web::Json) -> impl Responder { + format!("Welcome {}!", info.username) +} + +pub fn main() { + App::new().service( + web::resource("/") + .data( + // change json extractor configuration + web::Json::::configure(|cfg| { + cfg.limit(4096).error_handler(|err, _req| { + // <- create custom error response + error::InternalError::from_response( + err, + HttpResponse::Conflict().finish(), + ) + .into() + }) + }), + ) + .route(web::post().to(index)), + ); +} +// diff --git a/examples/extractors/src/main.rs b/examples/extractors/src/main.rs new file mode 100644 index 0000000..917f532 --- /dev/null +++ b/examples/extractors/src/main.rs @@ -0,0 +1,48 @@ +use actix_web::{web, App, FromRequest, HttpRequest, HttpServer, Responder}; +use futures::future::Future; +use serde::Deserialize; + +// mod custom_handler; +mod form; +mod json_one; +mod json_two; +mod multiple; +mod path_one; +mod path_two; +mod query; + +#[derive(Deserialize, Debug)] +struct MyInfo { + username: String, + id: u32, +} + +//
+// Option 1: passed as a parameter to a handler function +fn index(path: web::Path<(String, String)>, json: web::Json) -> impl Responder { + format!("{} {} {} {}", path.0, path.1, json.id, json.username) +} + +// Option 2: accessed by calling extract() on the Extractor +fn extract(req: HttpRequest) -> impl Responder { + let params = web::Path::<(String, String)>::extract(&req).unwrap(); + + let info = web::Json::::extract(&req) + .wait() + .expect("Err with reading json."); + + format!("{} {} {} {}", params.0, params.1, info.username, info.id) +} +//
+ +fn main() { + HttpServer::new(|| { + App::new() + .route("/{name}/{id}", web::post().to(index)) + .route("/{name}/{id}/extract", web::post().to(extract)) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); +} diff --git a/examples/extractors/src/multiple.rs b/examples/extractors/src/multiple.rs new file mode 100644 index 0000000..1d861d4 --- /dev/null +++ b/examples/extractors/src/multiple.rs @@ -0,0 +1,20 @@ +// +use actix_web::{web, App}; +use serde::Deserialize; + +#[derive(Deserialize)] +struct Info { + username: String, +} + +fn index((_path, query): (web::Path<(u32, String)>, web::Query)) -> String { + format!("Welcome {}!", query.username) +} + +pub fn main() { + App::new().route( + "/users/{userid}/{friend}", // <- define path parameters + web::get().to(index), + ); +} +// diff --git a/examples/extractors/src/path_one.rs b/examples/extractors/src/path_one.rs new file mode 100644 index 0000000..eb46b9b --- /dev/null +++ b/examples/extractors/src/path_one.rs @@ -0,0 +1,17 @@ +// +use actix_web::{web, App, Result}; + +/// extract path info from "/users/{userid}/{friend}" url +/// {userid} - - deserializes to a u32 +/// {friend} - deserializes to a String +fn index(info: web::Path<(u32, String)>) -> Result { + Ok(format!("Welcome {}! {}", info.1, info.0)) +} + +pub fn main() { + App::new().route( + "/users/{userid}/{friend}", // <- define path parameters + web::get().to(index), + ); +} +// diff --git a/examples/extractors/src/path_two.rs b/examples/extractors/src/path_two.rs new file mode 100644 index 0000000..7919173 --- /dev/null +++ b/examples/extractors/src/path_two.rs @@ -0,0 +1,22 @@ +// +use actix_web::{web, App, Result}; +use serde::Deserialize; + +#[derive(Deserialize)] +struct Info { + userid: u32, + friend: String, +} + +/// extract path info using serde +fn index(info: web::Path) -> Result { + Ok(format!("Welcome {}!", info.friend)) +} + +pub fn main() { + App::new().route( + "/users/{userid}/{friend}", // <- define path parameters + web::get().to(index), + ); +} +// diff --git a/examples/extractors/src/query.rs b/examples/extractors/src/query.rs new file mode 100644 index 0000000..ff1883b --- /dev/null +++ b/examples/extractors/src/query.rs @@ -0,0 +1,18 @@ +// +use actix_web::{web, App}; +use serde::Deserialize; + +#[derive(Deserialize)] +struct Info { + username: String, +} + +// this handler get called only if the request's query contains `username` field +fn index(info: web::Query) -> String { + format!("Welcome {}!", info.username) +} + +pub fn main() { + App::new().route("/", web::get().to(index)); +} +// From 3f95205696b5d2e79d10626b8b593ac48c0628e0 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Sun, 16 Jun 2019 23:37:14 -0400 Subject: [PATCH 18/68] Front page examples return 'impl Responder' --- examples/easy-form-handling/src/main.rs | 9 +++------ examples/main-example/src/main.rs | 6 +++--- examples/powerful-extractors/src/main.rs | 6 +++--- examples/request-routing/src/main.rs | 10 +++++----- layouts/index.html | 23 ++++++++++------------- 5 files changed, 24 insertions(+), 30 deletions(-) diff --git a/examples/easy-form-handling/src/main.rs b/examples/easy-form-handling/src/main.rs index 168b394..da0a115 100644 --- a/examples/easy-form-handling/src/main.rs +++ b/examples/easy-form-handling/src/main.rs @@ -1,5 +1,5 @@ // -use actix_web::{web, App, HttpResponse, HttpServer}; +use actix_web::{web, App, HttpResponse, HttpServer, Responder}; use serde::Deserialize; #[derive(Deserialize)] @@ -14,11 +14,8 @@ fn index() -> HttpResponse { .body(include_str!("../static/form.html")) } -fn register(params: web::Form) -> actix_web::Result { - Ok(HttpResponse::Ok().body(format!( - "Hello {} from {}!", - params.username, params.country - ))) +fn register(params: web::Form) -> impl Responder { + format!("Hello {} from {}!", params.username, params.country) } fn main() { diff --git a/examples/main-example/src/main.rs b/examples/main-example/src/main.rs index e09d82d..bc8649d 100644 --- a/examples/main-example/src/main.rs +++ b/examples/main-example/src/main.rs @@ -1,9 +1,9 @@ // -use actix_web::{web, App, HttpRequest, HttpResponse, HttpServer}; +use actix_web::{web, App, HttpRequest, HttpServer, Responder}; -fn greet(req: HttpRequest) -> HttpResponse { +fn greet(req: HttpRequest) -> impl Responder { let name = req.match_info().get("name").unwrap_or("World"); - HttpResponse::Ok().body(format!("Hello {}!", &name)) + format!("Hello {}!", &name) } fn main() { diff --git a/examples/powerful-extractors/src/main.rs b/examples/powerful-extractors/src/main.rs index befb7a8..e6b11f8 100644 --- a/examples/powerful-extractors/src/main.rs +++ b/examples/powerful-extractors/src/main.rs @@ -1,4 +1,4 @@ -use actix_web::{web, App, HttpResponse, HttpServer}; +use actix_web::{web, App, HttpResponse, HttpServer, Responder}; use serde::{Deserialize, Serialize}; #[derive(Deserialize, Serialize)] @@ -20,9 +20,9 @@ fn store_event_in_db(timestamp: f64, kind: String, tags: Vec) -> Event { } } -fn capture_event(evt: web::Json) -> actix_web::Result { +fn capture_event(evt: web::Json) -> impl Responder { let new_event = store_event_in_db(evt.timestamp, evt.kind.clone(), evt.tags.clone()); - Ok(HttpResponse::Ok().json(new_event)) + format!("got event {}", new_event.id.unwrap()) } fn index() -> HttpResponse { diff --git a/examples/request-routing/src/main.rs b/examples/request-routing/src/main.rs index fdb7f45..8a20019 100644 --- a/examples/request-routing/src/main.rs +++ b/examples/request-routing/src/main.rs @@ -1,12 +1,12 @@ // -use actix_web::{web, App, HttpRequest, HttpResponse, HttpServer}; +use actix_web::{web, App, HttpRequest, HttpServer, Responder}; -fn index(_req: HttpRequest) -> HttpResponse { - HttpResponse::Ok().body("Hello from the index page.") +fn index(_req: HttpRequest) -> impl Responder { + "Hello from the index page." } -fn hello(path: web::Path) -> HttpResponse { - HttpResponse::Ok().body(format!("Hello {}!", &path)) +fn hello(path: web::Path) -> impl Responder { + format!("Hello {}!", &path) } fn main() { diff --git a/layouts/index.html b/layouts/index.html index 8ae3988..e262e4d 100644 --- a/layouts/index.html +++ b/layouts/index.html @@ -41,9 +41,9 @@
{{ highlight `use actix_web::{web, App, HttpRequest, HttpResponse, HttpServer}; -fn greet(req: HttpRequest) -> HttpResponse { +fn greet(req: HttpRequest) -> impl Responder { let name = req.match_info().get("name").unwrap_or("World"); - HttpResponse::Ok().body(format!("Hello {}!", &name)) + format!("Hello {}!", &name) } fn main() { @@ -98,11 +98,11 @@ struct Event { kind: String, tags: Vec, } -fn capture_event(evt: web::Json) -> actix_web::Result { +fn capture_event(evt: web::Json) -> impl Responder { let new_event = store_event_in_db(evt.timestamp, evt.kind.clone(), evt.tags.clone()); - Ok(HttpResponse::Ok().json(new_event)) + format!("got event {}", new_event.id.unwrap()) }` "rust" "" }}
@@ -118,11 +118,8 @@ struct Register { country: String, } -fn register(params: web::Form) -> actix_web::Result { - Ok(HttpResponse::Ok().body(format!( - "Hello {} from {}!", - params.username, params.country - ))) +fn register(params: web::Form) -> impl Responder { + format!("Hello {} from {}!", params.username, params.country) }` "rust" "" }}
@@ -132,12 +129,12 @@ fn register(params: web::Form) -> actix_web::Result { URLs and invoke individual handlers. For extra flexibility, scopes can be used.

- {{ highlight `fn index(_req: HttpRequest) -> HttpResponse { - HttpResponse::Ok().body("Hello from the index page!") + {{ highlight `fn index(_req: HttpRequest) -> impl Responder { + "Hello from the index page!" } -fn hello(path: web::Path) -> HttpResponse { - HttpResponse::Ok().body(format!("Hello {}!", &path)) +fn hello(path: web::Path) -> impl Responder { + format!("Hello {}!", &path) } fn main() { From 312031a085b98aa6b5ca4722303107342440079a Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Mon, 17 Jun 2019 00:44:38 -0400 Subject: [PATCH 19/68] Updates 'autoreloading' section --- content/docs/autoreload.md | 28 +--------------------------- examples/Cargo.toml | 1 + examples/autoreload/Cargo.toml | 9 +++++++++ examples/autoreload/src/main.rs | 21 +++++++++++++++++++++ 4 files changed, 32 insertions(+), 27 deletions(-) create mode 100644 examples/autoreload/Cargo.toml create mode 100644 examples/autoreload/src/main.rs diff --git a/content/docs/autoreload.md b/content/docs/autoreload.md index 47e2cd6..f1f0902 100644 --- a/content/docs/autoreload.md +++ b/content/docs/autoreload.md @@ -40,33 +40,7 @@ listenfd = "0.3" Then modify your server code to only invoke `bind` as a fallback: -```rust -extern crate actix_web; -extern crate listenfd; - -use listenfd::ListenFd; -use actix_web::{server, App, HttpRequest, Responder}; - -fn index(_req: &HttpRequest) -> impl Responder { - "Hello World!" -} - -fn main() { - let mut listenfd = ListenFd::from_env(); - let mut server = server::new(|| { - App::new() - .resource("/", |r| r.f(index)) - }); - - server = if let Some(l) = listenfd.take_tcp_listener(0).unwrap() { - server.listen(l) - } else { - server.bind("127.0.0.1:3000").unwrap() - }; - - server.run(); -} -``` +{{< include-example example="autoreload" file="main.rs" section="autoreload" >}} ## Running the Server diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 711aaf6..9ee6417 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -16,4 +16,5 @@ exclude = [ "request-handlers", "async-handlers", "extractors", + "autoreload", ] diff --git a/examples/autoreload/Cargo.toml b/examples/autoreload/Cargo.toml new file mode 100644 index 0000000..95c9996 --- /dev/null +++ b/examples/autoreload/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "autoreload" +version = "0.1.0" +authors = ["Cameron Dershem "] +edition = "2018" + +[dependencies] +actix-web = "1.0" +listenfd = "0.3" diff --git a/examples/autoreload/src/main.rs b/examples/autoreload/src/main.rs new file mode 100644 index 0000000..42ed302 --- /dev/null +++ b/examples/autoreload/src/main.rs @@ -0,0 +1,21 @@ +// +use actix_web::{web, App, HttpRequest, HttpServer, Responder}; +use listenfd::ListenFd; + +fn index(_req: HttpRequest) -> impl Responder { + "Hello World!" +} + +fn main() { + let mut listenfd = ListenFd::from_env(); + let mut server = HttpServer::new(|| App::new().route("/", web::get().to(index))); + + server = if let Some(l) = listenfd.take_tcp_listener(0).unwrap() { + server.listen(l).unwrap() + } else { + server.bind("127.0.0.1:3000").unwrap() + }; + + server.run().unwrap(); +} +// From 0c268d18c1b2081407e647a28b5f966c96ef50bc Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Mon, 17 Jun 2019 02:08:42 -0400 Subject: [PATCH 20/68] Quick pass at url-dispatch --- examples/url-dispatch/src/cfg.rs | 21 ++++++++++----------- examples/url-dispatch/src/dhandler.rs | 21 ++++++++++++--------- examples/url-dispatch/src/main.rs | 5 ++--- examples/url-dispatch/src/minfo.rs | 12 +++++------- examples/url-dispatch/src/norm.rs | 11 +++++------ examples/url-dispatch/src/norm2.rs | 12 ++++++------ examples/url-dispatch/src/path.rs | 8 ++++---- examples/url-dispatch/src/path2.rs | 6 +++--- examples/url-dispatch/src/pbuf.rs | 10 ++++------ examples/url-dispatch/src/pred.rs | 17 +++++++++-------- examples/url-dispatch/src/pred2.rs | 15 +++++++-------- examples/url-dispatch/src/resource.rs | 13 ++++++------- examples/url-dispatch/src/scope.rs | 7 ++++--- examples/url-dispatch/src/url_ext.rs | 11 +++++------ examples/url-dispatch/src/urls.rs | 19 +++++++++++-------- 15 files changed, 93 insertions(+), 95 deletions(-) diff --git a/examples/url-dispatch/src/cfg.rs b/examples/url-dispatch/src/cfg.rs index 80f63d8..23c9490 100644 --- a/examples/url-dispatch/src/cfg.rs +++ b/examples/url-dispatch/src/cfg.rs @@ -1,15 +1,14 @@ // -use actix_web::{pred, App, HttpResponse}; +use actix_web::{guard, web, App, HttpResponse}; -fn main() { - App::new() - .resource("/path", |resource| { - resource - .route() - .filter(pred::Get()) - .filter(pred::Header("content-type", "text/plain")) - .f(|req| HttpResponse::Ok()) - }) - .finish(); +pub fn main() { + App::new().service( + web::resource("/").route( + web::route() + .guard(guard::Get()) + .guard(guard::Header("content-type", "text/plain")) + .to(|| HttpResponse::Ok()), + ), + ); } // diff --git a/examples/url-dispatch/src/dhandler.rs b/examples/url-dispatch/src/dhandler.rs index 7678d9b..46a9a75 100644 --- a/examples/url-dispatch/src/dhandler.rs +++ b/examples/url-dispatch/src/dhandler.rs @@ -1,14 +1,17 @@ -// -use actix_web::{http::Method, pred, App, HttpResponse}; +use actix_web::{guard, web, App, HttpRequest, HttpResponse, Responder}; +fn index(_req: HttpRequest) -> impl Responder { + "Welcome!" +} + +// 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(); + .service(web::resource("/").route(web::get().to(index))) + .default_service( + web::route() + .guard(guard::Not(guard::Get())) + .to(|| HttpResponse::MethodNotAllowed()), + ); } // diff --git a/examples/url-dispatch/src/main.rs b/examples/url-dispatch/src/main.rs index f6d5391..b1c30a2 100644 --- a/examples/url-dispatch/src/main.rs +++ b/examples/url-dispatch/src/main.rs @@ -16,14 +16,13 @@ mod urls; //
use actix_web::{web, App, HttpRequest, HttpResponse}; -fn index(req: HttpRequest) -> HttpResponse { +fn index(_req: HttpRequest) -> HttpResponse { unimplemented!() } fn main() { App::new() .route("/user/{name}", web::get().to(index)) - .route("/user/{name}", web::get().to(index)) - .finish(); + .route("/user/{name}", web::get().to(index)); } //
diff --git a/examples/url-dispatch/src/minfo.rs b/examples/url-dispatch/src/minfo.rs index 2c05a57..f26ac0a 100644 --- a/examples/url-dispatch/src/minfo.rs +++ b/examples/url-dispatch/src/minfo.rs @@ -1,15 +1,13 @@ // -use actix_web::{App, HttpRequest, Result}; +use actix_web::{web, App, HttpRequest, Result}; -fn index(req: &HttpRequest) -> Result { - let v1: u8 = req.match_info().query("v1")?; - let v2: u8 = req.match_info().query("v2")?; +fn index(req: HttpRequest) -> Result { + let v1: u8 = req.match_info().query("v1").parse().unwrap(); + let v2: u8 = req.match_info().query("v2").parse().unwrap(); Ok(format!("Values {} {}", v1, v2)) } fn main() { - App::new() - .resource(r"/a/{v1}/{v2}/", |r| r.f(index)) - .finish(); + App::new().route(r"/a/{v1}/{v2}/", web::get().to(index)); } // diff --git a/examples/url-dispatch/src/norm.rs b/examples/url-dispatch/src/norm.rs index fcdbd50..a1c8d4a 100644 --- a/examples/url-dispatch/src/norm.rs +++ b/examples/url-dispatch/src/norm.rs @@ -1,15 +1,14 @@ // -use actix_web::{http::NormalizePath, App}; +use actix_web::{middleware, web, App, HttpResponse}; fn main() { - let app = App::new() - .resource("/resource/", |r| r.f(index)) - .default_resource(|r| r.h(NormalizePath::default())) - .finish(); + App::new() + .wrap(middleware::NormalizePath) + .route("/", web::get().to(|| HttpResponse::Ok())); } // use actix_web::HttpRequest; -fn index(req: &HttpRequest) -> String { +fn index(_req: HttpRequest) -> String { unimplemented!() } diff --git a/examples/url-dispatch/src/norm2.rs b/examples/url-dispatch/src/norm2.rs index 7a4fb91..cadfd35 100644 --- a/examples/url-dispatch/src/norm2.rs +++ b/examples/url-dispatch/src/norm2.rs @@ -1,16 +1,16 @@ // -use actix_web::{http::Method, http::NormalizePath, App}; +use actix_web::{http::Method, middleware, web, App}; fn main() { - let app = App::new() - .resource("/resource/", |r| r.f(index)) - .default_resource(|r| r.method(Method::GET).h(NormalizePath::default())) - .finish(); + App::new() + .wrap(middleware::NormalizePath) + .route("/resource/", web::get().to(index)) + .default_service(web::route().method(Method::GET)); } // use actix_web::HttpRequest; -fn index(req: &HttpRequest) -> String { +fn index(_req: HttpRequest) -> String { unimplemented!() } diff --git a/examples/url-dispatch/src/path.rs b/examples/url-dispatch/src/path.rs index 7724c1e..bc726c4 100644 --- a/examples/url-dispatch/src/path.rs +++ b/examples/url-dispatch/src/path.rs @@ -1,15 +1,15 @@ // -use actix_web::{http::Method, App, Path, Result}; +use actix_web::{web, App, Result}; // extract path info using serde -fn index(info: Path<(String, u32)>) -> Result { +fn index(info: web::Path<(String, u32)>) -> Result { Ok(format!("Welcome {}! id: {}", info.0, info.1)) } fn main() { - let app = App::new().resource( + App::new().route( "/{username}/{id}/index.html", // <- define path parameters - |r| r.method(Method::GET).with(index), + web::get().to(index), ); } // diff --git a/examples/url-dispatch/src/path2.rs b/examples/url-dispatch/src/path2.rs index b433e1f..2524342 100644 --- a/examples/url-dispatch/src/path2.rs +++ b/examples/url-dispatch/src/path2.rs @@ -1,5 +1,5 @@ // -use actix_web::{http::Method, web, App, Result}; +use actix_web::{web, App, Result}; use serde::Deserialize; #[derive(Deserialize)] @@ -13,9 +13,9 @@ fn index(info: web::Path) -> Result { } fn main() { - let app = App::new().resource( + App::new().route( "/{username}/index.html", // <- define path parameters - |r| r.method(Method::GET).with(index), + web::get().to(index), ); } // diff --git a/examples/url-dispatch/src/pbuf.rs b/examples/url-dispatch/src/pbuf.rs index b18ae35..855d2e9 100644 --- a/examples/url-dispatch/src/pbuf.rs +++ b/examples/url-dispatch/src/pbuf.rs @@ -1,15 +1,13 @@ // -use actix_web::{http::Method, App, HttpRequest, Result}; +use actix_web::{web, App, HttpRequest, Result}; use std::path::PathBuf; -fn index(req: &HttpRequest) -> Result { - let path: PathBuf = req.match_info().query("tail")?; +fn index(req: HttpRequest) -> Result { + let path: PathBuf = req.match_info().query("tail").parse().unwrap(); Ok(format!("Path {:?}", path)) } fn main() { - App::new() - .resource(r"/a/{tail:.*}", |r| r.method(Method::GET).f(index)) - .finish(); + App::new().route(r"/a/{tail:.*}", web::get().to(index)); } // diff --git a/examples/url-dispatch/src/pred.rs b/examples/url-dispatch/src/pred.rs index 2fda5a5..8c75a2c 100644 --- a/examples/url-dispatch/src/pred.rs +++ b/examples/url-dispatch/src/pred.rs @@ -1,19 +1,20 @@ // -use actix_web::{http, server::Request, pred::Predicate, App, HttpResponse}; +use actix_web::{dev::RequestHead, guard::Guard, http, web, App, HttpResponse}; struct ContentTypeHeader; -impl Predicate for ContentTypeHeader { - fn check(&self, req: &Request, state: &S) -> bool { +impl Guard for ContentTypeHeader { + fn check(&self, req: &RequestHead) -> bool { req.headers().contains_key(http::header::CONTENT_TYPE) } } fn main() { - App::new().resource("/index.html", |r| { - r.route() - .filter(ContentTypeHeader) - .f(|_| HttpResponse::Ok()) - }); + App::new().route( + "", + web::route() + .guard(ContentTypeHeader) + .to(|| HttpResponse::Ok()), + ); } // diff --git a/examples/url-dispatch/src/pred2.rs b/examples/url-dispatch/src/pred2.rs index 6a9449a..e56d6c2 100644 --- a/examples/url-dispatch/src/pred2.rs +++ b/examples/url-dispatch/src/pred2.rs @@ -1,13 +1,12 @@ // -use actix_web::{pred, App, HttpResponse}; +use actix_web::{guard, web, App, HttpResponse}; fn main() { - App::new() - .resource("/index.html", |r| { - r.route() - .filter(pred::Not(pred::Get())) - .f(|req| HttpResponse::MethodNotAllowed()) - }) - .finish(); + App::new().route( + "/", + web::route() + .guard(guard::Not(guard::Get())) + .to(|| HttpResponse::MethodNotAllowed()), + ); } // diff --git a/examples/url-dispatch/src/resource.rs b/examples/url-dispatch/src/resource.rs index aebfebd..1dd5639 100644 --- a/examples/url-dispatch/src/resource.rs +++ b/examples/url-dispatch/src/resource.rs @@ -1,16 +1,15 @@ // -use actix_web::{http::Method, App, HttpRequest, HttpResponse}; +use actix_web::{http::Method, web, App, HttpRequest, HttpResponse}; -fn index(req: &HttpRequest) -> HttpResponse { +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(); + .service(web::resource("/prefix").route(web::get().to(index))) + .service( + web::resource("/user/{name}").route(web::get().to(|| HttpResponse::Ok())), + ); } // diff --git a/examples/url-dispatch/src/scope.rs b/examples/url-dispatch/src/scope.rs index 6180b07..5bd4906 100644 --- a/examples/url-dispatch/src/scope.rs +++ b/examples/url-dispatch/src/scope.rs @@ -1,4 +1,4 @@ -use actix_web::{App, HttpRequest, HttpResponse}; +use actix_web::{web, App, HttpRequest, HttpResponse}; // fn show_users(_req: HttpRequest) -> HttpResponse { @@ -7,7 +7,8 @@ fn show_users(_req: HttpRequest) -> HttpResponse { #[rustfmt::skip] fn main() { - App::new().service( - web::scope("/users") .route("/show", web::to(show_users))) + App::new() + .service(web::scope("/users") + .route("/show", web::get().to(show_users))); } // diff --git a/examples/url-dispatch/src/url_ext.rs b/examples/url-dispatch/src/url_ext.rs index f02f14f..6327192 100644 --- a/examples/url-dispatch/src/url_ext.rs +++ b/examples/url-dispatch/src/url_ext.rs @@ -1,16 +1,15 @@ // -use actix_web::{App, Error, HttpRequest, HttpResponse}; +use actix_web::{web, App, Error, HttpRequest, HttpResponse}; -fn index(req: &HttpRequest) -> Result { +fn index(req: HttpRequest) -> Result { 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(); + App::new() + .service(web::resource("/index.html").route(web::get().to(index))) + .external_resource("youtube", "https://youtube.com/watch/{video_id}"); } // diff --git a/examples/url-dispatch/src/urls.rs b/examples/url-dispatch/src/urls.rs index 6e67a3a..814cc9f 100644 --- a/examples/url-dispatch/src/urls.rs +++ b/examples/url-dispatch/src/urls.rs @@ -1,5 +1,7 @@ // -use actix_web::{http::header, http::Method, App, HttpRequest, HttpResponse, Result}; +use actix_web::{ + guard, http::header, http::Method, web, App, HttpRequest, HttpResponse, Result, +}; fn index(req: HttpRequest) -> Result { let url = req.url_for("foo", &["1", "2", "3"])?; // <- generate url for "foo" resource @@ -9,12 +11,13 @@ fn index(req: HttpRequest) -> Result { } 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(); + App::new() + .service( + web::resource("/test/{a}/{b}/{c}") + .name("foo") // <- set resource name, then it could be used in `url_for` + .guard(guard::Get()) + .to(|| HttpResponse::Ok()), + ) + .route("/test/", web::get().to(index)); } // From 71e6f076a4a838e7dcc3827769a2417295979d35 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Mon, 17 Jun 2019 04:12:11 -0400 Subject: [PATCH 21/68] First pass at url-dispatch chapter. --- content/docs/url-dispatch.md | 74 ++++++++++++--------------- examples/url-dispatch/src/cfg.rs | 2 +- examples/url-dispatch/src/main.rs | 2 +- examples/url-dispatch/src/minfo.rs | 11 ++-- examples/url-dispatch/src/path2.rs | 2 +- examples/url-dispatch/src/resource.rs | 2 +- examples/url-dispatch/src/url_ext.rs | 16 +++--- examples/url-dispatch/src/urls.rs | 2 +- 8 files changed, 54 insertions(+), 57 deletions(-) diff --git a/content/docs/url-dispatch.md b/content/docs/url-dispatch.md index cef0595..8edce57 100644 --- a/content/docs/url-dispatch.md +++ b/content/docs/url-dispatch.md @@ -6,7 +6,7 @@ weight: 190 # URL Dispatch -URL dispatch provides a simple way for mapping URLs to `Handler` code using a simple pattern +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. @@ -75,23 +75,21 @@ If a resource can not match any route, a "NOT FOUND" response is returned. [*Route*](../../actix-web/actix_web/dev/struct.Route.html) object. Route can be configured with a builder-like pattern. Following configuration methods are available: -* [*Route::filter()*](../../actix-web/actix_web/dev/struct.Route.html#method.filter) - registers a new predicate. Any number of predicates can be registered for each route. -* [*Route::f()*](../../actix-web/actix_web/dev/struct.Route.html#method.f) registers +* [*Route::guard()*](../../actix-web/actix_web/dev/struct.Route.html#method.guard) + registers a new guard. Any number of guards can be registered for each route. +* [*Route::method()*](../../actix-web/actix_web/dev/struct.Route.html#method.method) + registers a method guard. Any number of guards can be registered for each route. +* [*Route::to()*](../../actix-web/actix_web/dev/struct.Route.html#method.to) 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) -> R + 'static` -* [*Route::h()*](../../actix-web/actix_web/dev/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/actix_web/dev/struct.Route.html#method.a) registers + `Fn(HttpRequest) -> R + 'static` +* [*Route::to_async()*](../../actix-web/actix_web/dev/struct.Route.html#method.to_async) 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) -> Future + 'static` + `Fn(HttpRequest) -> Future + 'static` # Route matching @@ -104,14 +102,15 @@ the request's path against the pattern declared. This checking happens in the or 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 +When a route configuration is declared, it may contain route guard arguments. All route +guards associated with a route declaration must be `true` for the route configuration to +be used for a given request during a check. If any guard in the set of route guard 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. +the route is invoked. If no route matches after all route patterns are exhausted, a +*NOT FOUND* response get returned. # Resource pattern syntax @@ -278,10 +277,6 @@ All values representing matched path segments are available in 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.: - {{< include-example example="url-dispatch" file="minfo.rs" section="minfo" >}} For this example for path '/a/1/2/', values v1 and v2 will resolve to "1" and "2". @@ -304,9 +299,6 @@ safe to interpolate within, or use as a suffix of, a path without additional che {{< include-example example="url-dispatch" file="pbuf.rs" section="pbuf" >}} -List of `FromParam` implementations can be found in -[api docs](../../actix-web/actix_web/dev/trait.FromParam.html#foreign-impls) - ## Path information extractor Actix provides functionality for type safe path information extraction. @@ -383,8 +375,8 @@ It is possible to register path normalization only for *GET* requests only: ## 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 +The `web::scope()` method allows to set a specific application scope. +This scope 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. @@ -394,30 +386,30 @@ For example: {{< include-example example="url-dispatch" file="scope.rs" section="scope" >}} In the above example, the *show_users* route will have an effective route pattern of -*/users/show* instead of */show* because the application's prefix argument will be prepended +*/users/show* instead of */show* because the application's scope 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 +# Custom route guard -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 +You can think of a guard as a simple function that accepts a *request* object reference +and returns *true* or *false*. Formally, a guard is any object that implements the +[`Guard`](../actix_web/guard/trait.Guard.html) trait. Actix provides several predicates, you can check -[functions section](../../actix-web/actix_web/pred/index.html#functions) of api docs. +[functions section](../../actix-web/actix_web/guard/index.html#functions) of api docs. -Here is a simple predicate that check that a request contains a specific *header*: +Here is a simple guard that check that a request contains a specific *header*: {{< include-example example="url-dispatch" file="pred.rs" section="pred" >}} 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()`. +Guards have access to the application's state via `HttpRequest::data()`. Also predicates can store extra information in [request extensions](../../actix-web/actix_web/struct.HttpRequest.html#method.extensions). -## Modifying predicate values +## Modifying guard 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 @@ -425,26 +417,26 @@ except "GET": {{< include-example example="url-dispatch" file="pred2.rs" section="pred" >}} -The `Any` predicate accepts a list of predicates and matches if any of the supplied -predicates match. i.e: +The `Any` guard accepts a list of guards and matches if any of the supplied +guards match. i.e: ```rust -pred::Any(pred::Get()).or(pred::Post()) +guard::Any(guard::Get()).or(guard::Post()) ``` -The `All` predicate accepts a list of predicates and matches if all of the supplied -predicates match. i.e: +The `All` guard accepts a list of guard and matches if all of the supplied +guards match. i.e: ```rust -pred::All(pred::Get()).and(pred::Header("content-type", "plain/text")) +guard::All(guard::Get()).and(guard::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()`. +It is possible to override the *NOT FOUND* response with `App::default_service()`. This method accepts a *configuration function* same as normal resource configuration -with `App::resource()` method. +with `App::service()` method. {{< include-example example="url-dispatch" file="dhandler.rs" section="default" >}} diff --git a/examples/url-dispatch/src/cfg.rs b/examples/url-dispatch/src/cfg.rs index 23c9490..de4de25 100644 --- a/examples/url-dispatch/src/cfg.rs +++ b/examples/url-dispatch/src/cfg.rs @@ -3,7 +3,7 @@ use actix_web::{guard, web, App, HttpResponse}; pub fn main() { App::new().service( - web::resource("/").route( + web::resource("/path").route( web::route() .guard(guard::Get()) .guard(guard::Header("content-type", "text/plain")) diff --git a/examples/url-dispatch/src/main.rs b/examples/url-dispatch/src/main.rs index b1c30a2..c2e4ae0 100644 --- a/examples/url-dispatch/src/main.rs +++ b/examples/url-dispatch/src/main.rs @@ -23,6 +23,6 @@ fn index(_req: HttpRequest) -> HttpResponse { fn main() { App::new() .route("/user/{name}", web::get().to(index)) - .route("/user/{name}", web::get().to(index)); + .route("/user/{name}", web::post().to(index)); } //
diff --git a/examples/url-dispatch/src/minfo.rs b/examples/url-dispatch/src/minfo.rs index f26ac0a..3ce4a6c 100644 --- a/examples/url-dispatch/src/minfo.rs +++ b/examples/url-dispatch/src/minfo.rs @@ -1,13 +1,16 @@ // -use actix_web::{web, App, HttpRequest, Result}; +use actix_web::{web, App, HttpRequest, HttpServer, Result}; fn index(req: HttpRequest) -> Result { - let v1: u8 = req.match_info().query("v1").parse().unwrap(); + let v1: u8 = req.match_info().get("v1").unwrap().parse().unwrap(); let v2: u8 = req.match_info().query("v2").parse().unwrap(); - Ok(format!("Values {} {}", v1, v2)) + let (v3, v4): (u8, u8) = req.match_info().load().unwrap(); + Ok(format!("Values {} {} {} {}", v1, v2, v3, v4)) } fn main() { - App::new().route(r"/a/{v1}/{v2}/", web::get().to(index)); + App::new() + .route("/a/{v1}/{v2}/", web::get().to(index)) + .route("", web::get().to(|| actix_web::HttpResponse::Ok())); } // diff --git a/examples/url-dispatch/src/path2.rs b/examples/url-dispatch/src/path2.rs index 2524342..53d4532 100644 --- a/examples/url-dispatch/src/path2.rs +++ b/examples/url-dispatch/src/path2.rs @@ -12,7 +12,7 @@ fn index(info: web::Path) -> Result { Ok(format!("Welcome {}!", info.username)) } -fn main() { +pub fn main() { App::new().route( "/{username}/index.html", // <- define path parameters web::get().to(index), diff --git a/examples/url-dispatch/src/resource.rs b/examples/url-dispatch/src/resource.rs index 1dd5639..f2d98db 100644 --- a/examples/url-dispatch/src/resource.rs +++ b/examples/url-dispatch/src/resource.rs @@ -7,7 +7,7 @@ fn index(_req: HttpRequest) -> HttpResponse { fn main() { App::new() - .service(web::resource("/prefix").route(web::get().to(index))) + .service(web::resource("/prefix").to(index)) .service( web::resource("/user/{name}").route(web::get().to(|| HttpResponse::Ok())), ); diff --git a/examples/url-dispatch/src/url_ext.rs b/examples/url-dispatch/src/url_ext.rs index 6327192..eaa2503 100644 --- a/examples/url-dispatch/src/url_ext.rs +++ b/examples/url-dispatch/src/url_ext.rs @@ -1,15 +1,17 @@ // -use actix_web::{web, App, Error, HttpRequest, HttpResponse}; +use actix_web::{web, App, Error, HttpRequest, HttpResponse, Responder}; -fn index(req: HttpRequest) -> Result { - let url = req.url_for("youtube", &["oHg5SJYRHA0"])?; +fn index(req: HttpRequest) -> impl Responder { + let url = req.url_for("youtube", &["oHg5SJYRHA0"]).unwrap(); assert_eq!(url.as_str(), "https://youtube.com/watch/oHg5SJYRHA0"); - Ok(HttpResponse::Ok().into()) + + url.into_string() } -fn main() { +pub fn main() { App::new() - .service(web::resource("/index.html").route(web::get().to(index))) - .external_resource("youtube", "https://youtube.com/watch/{video_id}"); + .route("/index.html", web::get().to(index)) + .external_resource("youtube", "https://youtube.com/watch/{video_id}") + .route("/", actix_web::web::get().to(index)); } // diff --git a/examples/url-dispatch/src/urls.rs b/examples/url-dispatch/src/urls.rs index 814cc9f..e1ab4dc 100644 --- a/examples/url-dispatch/src/urls.rs +++ b/examples/url-dispatch/src/urls.rs @@ -10,7 +10,7 @@ fn index(req: HttpRequest) -> Result { .finish()) } -fn main() { +pub fn main() { App::new() .service( web::resource("/test/{a}/{b}/{c}") From f07c78a5ca5490e9cb9aa969776ae01ecd208424 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Mon, 17 Jun 2019 13:46:21 -0400 Subject: [PATCH 22/68] First pass at errors section. --- content/docs/errors.md | 112 ++------------------------ examples/Cargo.toml | 1 + examples/errors/Cargo.toml | 8 ++ examples/errors/src/helpers.rs | 14 ++++ examples/errors/src/main.rs | 21 +++++ examples/errors/src/override_error.rs | 30 +++++++ examples/errors/src/recommend_one.rs | 20 +++++ examples/errors/src/recommend_two.rs | 25 ++++++ 8 files changed, 124 insertions(+), 107 deletions(-) create mode 100644 examples/errors/Cargo.toml create mode 100644 examples/errors/src/helpers.rs create mode 100644 examples/errors/src/main.rs create mode 100644 examples/errors/src/override_error.rs create mode 100644 examples/errors/src/recommend_one.rs create mode 100644 examples/errors/src/recommend_two.rs diff --git a/content/docs/errors.md b/content/docs/errors.md index f8683c4..ace3a4c 100644 --- a/content/docs/errors.md +++ b/content/docs/errors.md @@ -52,22 +52,7 @@ foreign implementations for `ResponseError`. Here's an example implementation for `ResponseError`: -```rust -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"}) -} -``` +{{< include-example example="errors" file="main.rs" section="response-error" >}} `ResponseError` has a default implementation for `error_response()` that will render a *500* (internal server error), and that's what will happen when the @@ -75,37 +60,7 @@ render a *500* (internal server error), and that's what will happen when the Override `error_response()` to produce more useful results: -```rust -#[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) -} -``` +{{< include-example example="errors" file="override_error.rs" section="override" >}} # Error helpers @@ -114,21 +69,7 @@ specific HTTP error codes from other errors. Here we convert `MyError`, which doesn't implement the `ResponseError` trait, to a *400* (bad request) using `map_err`: -```rust -# extern crate actix_web; -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.name))?) -} -``` +{{< include-example example="errors" file="helpers.rs" section="helpers" >}} See the [API documentation for actix-web's `error` module][errorhelpers] for a full list of available error helpers. @@ -165,27 +106,7 @@ An example of the former is that I might use failure to specify a `UserError` enum which encapsulates a `ValidationError` to return whenever a user sends bad input: -```rust -#[macro_use] extern crate failure; -use actix_web::{HttpResponse, http, error}; - -#[derive(Fail, Debug)] -enum UserError { - #[fail(display="Validation error on field: {}", field)] - ValidationError { - field: String, - } -} - -impl error::ResponseError for UserError { - fn error_response(&self) -> HttpResponse { - match *self { - UserError::ValidationError { .. } => HttpResponse::new( - http::StatusCode::BAD_REQUEST), - } - } -} -``` +{{< include-example example="errors" file="recommend_one.rs" section="recommend-one" >}} This will behave exactly as intended because the error message defined with `display` is written with the explicit intent to be read by a user. @@ -201,30 +122,7 @@ consumption. Here's an example that maps an internal error to a user-facing `InternalError` with a custom message: -```rust -#[macro_use] extern crate failure; -use actix_web::{App, HttpRequest, HttpResponse, http, error, fs}; - -#[derive(Fail, Debug)] -enum UserError { - #[fail(display="An internal error occurred. Please try again later.")] - InternalError, -} - -impl error::ResponseError for UserError { - fn error_response(&self) -> HttpResponse { - match *self { - UserError::InternalError => HttpResponse::new( - http::StatusCode::INTERNAL_SERVER_ERROR), - } - } -} - -fn index(_: &HttpRequest) -> Result<&'static str, UserError> { - fs::NamedFile::open("static/index.html").map_err(|_e| UserError::InternalError)?; - Ok("success!") -} -``` +{{< include-example example="errors" file="recommend_two.rs" section="recommend-two" >}} By dividing errors into those which are user facing and those which are not, we can ensure that we don't accidentally expose users to errors thrown by diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 9ee6417..4a6c8ae 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -17,4 +17,5 @@ exclude = [ "async-handlers", "extractors", "autoreload", + "errors" ] diff --git a/examples/errors/Cargo.toml b/examples/errors/Cargo.toml new file mode 100644 index 0000000..1314e8f --- /dev/null +++ b/examples/errors/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "errors" +version = "0.1.0" +edition = "2018" + +[dependencies] +actix-web = "1.0" +failure = "0.1" diff --git a/examples/errors/src/helpers.rs b/examples/errors/src/helpers.rs new file mode 100644 index 0000000..9fcd86a --- /dev/null +++ b/examples/errors/src/helpers.rs @@ -0,0 +1,14 @@ +// +use actix_web::{error, HttpRequest, Result}; + +#[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.name))?) +} +// diff --git a/examples/errors/src/main.rs b/examples/errors/src/main.rs new file mode 100644 index 0000000..63e09b9 --- /dev/null +++ b/examples/errors/src/main.rs @@ -0,0 +1,21 @@ +mod helpers; +mod override_error; +mod recommend_one; +// +use actix_web::{error, HttpRequest}; +use failure::Fail; + +#[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() {} diff --git a/examples/errors/src/override_error.rs b/examples/errors/src/override_error.rs new file mode 100644 index 0000000..a5eaea3 --- /dev/null +++ b/examples/errors/src/override_error.rs @@ -0,0 +1,30 @@ +// +use actix_web::{error, http, HttpRequest, HttpResponse}; +use failure::Fail; + +#[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) +} +// diff --git a/examples/errors/src/recommend_one.rs b/examples/errors/src/recommend_one.rs new file mode 100644 index 0000000..51b6131 --- /dev/null +++ b/examples/errors/src/recommend_one.rs @@ -0,0 +1,20 @@ +// +use actix_web::{error, http, HttpResponse}; +use failure::Fail; + +#[derive(Fail, Debug)] +enum UserError { + #[fail(display = "Validation error on field: {}", field)] + ValidationError { field: String }, +} + +impl error::ResponseError for UserError { + fn error_response(&self) -> HttpResponse { + match *self { + UserError::ValidationError { .. } => { + HttpResponse::new(http::StatusCode::BAD_REQUEST) + } + } + } +} +// diff --git a/examples/errors/src/recommend_two.rs b/examples/errors/src/recommend_two.rs new file mode 100644 index 0000000..80e5f1f --- /dev/null +++ b/examples/errors/src/recommend_two.rs @@ -0,0 +1,25 @@ +// +use actix_web::{error, fs, http, App, HttpRequest, HttpResponse}; +use failure::Fail; + +#[derive(Fail, Debug)] +enum UserError { + #[fail(display = "An internal error occurred. Please try again later.")] + InternalError, +} + +impl error::ResponseError for UserError { + fn error_response(&self) -> HttpResponse { + match *self { + UserError::InternalError => { + HttpResponse::new(http::StatusCode::INTERNAL_SERVER_ERROR) + } + } + } +} + +fn index(_req: HttpRequest) -> Result<&'static str, UserError> { + fs::NamedFile::open("static/index.html").map_err(|_e| UserError::InternalError)?; + Ok("success!") +} +// From 507842bf1cd44e6c1d953bf63babd2be9bf8af98 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Mon, 17 Jun 2019 14:34:23 -0400 Subject: [PATCH 23/68] First pass at Requests Chapter. --- content/docs/request.md | 138 ++-------------------------- examples/Cargo.toml | 3 +- examples/requests/Cargo.toml | 12 +++ examples/requests/src/json_two.rs | 21 +++++ examples/requests/src/main.rs | 23 +++++ examples/requests/src/manual.rs | 43 +++++++++ examples/requests/src/multipart.rs | 25 +++++ examples/requests/src/streaming.rs | 15 +++ examples/requests/src/urlencoded.rs | 22 +++++ 9 files changed, 173 insertions(+), 129 deletions(-) create mode 100644 examples/requests/Cargo.toml create mode 100644 examples/requests/src/json_two.rs create mode 100644 examples/requests/src/main.rs create mode 100644 examples/requests/src/manual.rs create mode 100644 examples/requests/src/multipart.rs create mode 100644 examples/requests/src/streaming.rs create mode 100644 examples/requests/src/urlencoded.rs diff --git a/content/docs/request.md b/content/docs/request.md index 1f2e9f8..35e3f79 100644 --- a/content/docs/request.md +++ b/content/docs/request.md @@ -9,9 +9,13 @@ weight: 200 Actix automatically *decompresses* payloads. The following codecs are supported: * Brotli +* Chunked +* Compress * Gzip * Deflate * Identity +* Trailers +* EncodingExt If request headers contain a `Content-Encoding` header, the request payload is decompressed according to the header value. Multiple codecs are not supported, @@ -22,80 +26,18 @@ i.e: `Content-Encoding: br, gzip`. 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` as a parameter, then, you use the `.with()` method for registering +that accepts `Json` as a parameter, then, you use the `.to()` 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 -#[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) -> Result { - 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 *HttpRequest::json()*. This method returns a -[*JsonBody*](../../actix-web/actix_web/dev/struct.JsonBody.html) object which resolves into -the deserialized value. - -```rust -#[derive(Debug, Serialize, Deserialize)] -struct MyObj { - name: String, - number: i32, -} - -fn index(req: &HttpRequest) -> Box> { - req.json().from_err() - .and_then(|val: MyObj| { - println!("model: {:?}", val); - Ok(HttpResponse::Ok().json(val)) // <- send response - }) - .responder() -} -``` +{{< include-example example="requests" file="main.rs" section="json-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 -extern crate serde_json; -use futures::{Future, Stream}; - -#[derive(Serialize, Deserialize)] -struct MyObj {name: String, number: i32} - -fn index(req: &HttpRequest) -> Box> { - // `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| { - let obj = serde_json::from_slice::(&body)?; - Ok(HttpResponse::Ok().json(obj)) - }) - .responder() -} -``` +{{< include-example example="requests" file="manual.rs" section="json-manual" >}} > A complete example for both options is available in > [examples directory](https://github.com/actix/examples/tree/master/json/). @@ -117,31 +59,7 @@ for the current request. The following demonstrates multipart stream handling for a simple form: -```rust -use actix_web::*; - -fn index(req: &HttpRequest) -> Box> { - // get multipart and iterate over multipart items - req.multipart() - .and_then(|item| { - match item { - multipart::MultipartItem::Field(field) => { - println!("==== FIELD ==== {:?} {:?}", - field.headers(), - field.content_type()); - Either::A( - field.map(|chunk| { - println!("-- CHUNK: \n{}", - std::str::from_utf8(&chunk).unwrap());}) - .fold((), |_, _| result(Ok(())))) - }, - multipart::MultipartItem::Nested(mp) => { - Either::B(result(Ok(()))) - } - } - }) -} -``` +{{< include-example example="requests" file="multipart.rs" section="multipart" >}} > A full example is available in the > [examples directory](https://github.com/actix/examples/tree/master/multipart/). @@ -161,27 +79,7 @@ The *UrlEncoded* future can resolve into an error in several cases: * content-length is greater than 256k * payload terminates with error. -```rust -#[macro_use] extern crate serde_derive; -use actix_web::*; -use futures::future::{Future, ok}; - -#[derive(Deserialize)] -struct FormData { - username: String, -} - -fn index(req: &HttpRequest) -> Box> { - req.urlencoded::() // <- get UrlEncoded future - .from_err() - .and_then(|data| { // <- deserialized instance - println!("USERNAME: {:?}", data.username); - ok(HttpResponse::Ok().into()) - }) - .responder() -} -# fn main() {} -``` +{{< include-example example="requests" file="urlencoded.rs" section="urlencoded" >}} # Streaming request @@ -190,20 +88,4 @@ body payload. In the following example, we read and print the request payload chunk by chunk: -```rust -use actix_web::*; -use futures::{Future, Stream}; - - -fn index(req: &HttpRequest) -> Box> { - req - .payload() - .from_err() - .fold((), |_, chunk| { - println!("Chunk: {:?}", chunk); - result::<_, error::PayloadError>(Ok(())) - }) - .map(|_| HttpResponse::Ok().finish()) - .responder() -} -``` +{{< include-example example="requests" file="streaming.rs" section="streaming" >}} diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 4a6c8ae..05f095a 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -17,5 +17,6 @@ exclude = [ "async-handlers", "extractors", "autoreload", - "errors" + "errors", + "requests", ] diff --git a/examples/requests/Cargo.toml b/examples/requests/Cargo.toml new file mode 100644 index 0000000..49a8984 --- /dev/null +++ b/examples/requests/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "requests" +version = "0.1.0" +authors = ["Cameron Dershem "] +edition = "2018" + +[dependencies] +serde = "1.0" +serde_json = "1.0" +actix-web = "1.0" +futures = "0.1" +bytes = "0.4" diff --git a/examples/requests/src/json_two.rs b/examples/requests/src/json_two.rs new file mode 100644 index 0000000..659bd96 --- /dev/null +++ b/examples/requests/src/json_two.rs @@ -0,0 +1,21 @@ +// // +// use actix_web::{error::Error, HttpRequest, HttpResponse}; +// use futures::Future; +// use serde::{Deserialize, Serialize}; + +// #[derive(Debug, Serialize, Deserialize)] +// struct MyObj { +// name: String, +// number: i32, +// } + +// fn index(req: HttpRequest) -> Box> { +// req.json() +// .from_err() +// .and_then(|val: MyObj| { +// println!("model: {:?}", val); +// Ok(HttpResponse::Ok().json(val)) // <- send response +// }) +// .responder() +// } +// // diff --git a/examples/requests/src/main.rs b/examples/requests/src/main.rs new file mode 100644 index 0000000..9b3ad62 --- /dev/null +++ b/examples/requests/src/main.rs @@ -0,0 +1,23 @@ +mod json_two; +mod manual; +mod multipart; +mod streaming; +mod urlencoded; +// +use actix_web::{web, App, Result}; +use serde::Deserialize; + +#[derive(Deserialize)] +struct Info { + username: String, +} + +/// extract `Info` using serde +fn index(info: web::Json) -> Result { + Ok(format!("Welcome {}!", info.username)) +} + +fn main() { + App::new().route("/index.html", web::post().to(index)); +} +// diff --git a/examples/requests/src/manual.rs b/examples/requests/src/manual.rs new file mode 100644 index 0000000..846f704 --- /dev/null +++ b/examples/requests/src/manual.rs @@ -0,0 +1,43 @@ +// +use actix_web::{error, web, Error, HttpResponse}; +use bytes::BytesMut; +use futures::{Future, Stream}; +use serde::{Deserialize, Serialize}; +use serde_json; + +#[derive(Serialize, Deserialize)] +struct MyObj { + name: String, + number: i32, +} + +const MAX_SIZE: usize = 262_144; // max payload size is 256k + +fn index_manual( + payload: web::Payload, +) -> impl Future { + // payload is a stream of Bytes objects + payload + // `Future::from_err` acts like `?` in that it coerces the error type from + // the future into the final error type + .from_err() + // `fold` will asynchronously read each chunk of the request body and + // call supplied closure, then it resolves to result of closure + .fold(BytesMut::new(), move |mut body, chunk| { + // limit max size of in-memory payload + if (body.len() + chunk.len()) > MAX_SIZE { + Err(error::ErrorBadRequest("overflow")) + } else { + body.extend_from_slice(&chunk); + Ok(body) + } + }) + // `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 serde-json + let obj = serde_json::from_slice::(&body)?; + Ok(HttpResponse::Ok().json(obj)) // <- send response + }) +} +// diff --git a/examples/requests/src/multipart.rs b/examples/requests/src/multipart.rs new file mode 100644 index 0000000..0fa74d9 --- /dev/null +++ b/examples/requests/src/multipart.rs @@ -0,0 +1,25 @@ +// +// use actix_web::{error, Error, HttpRequest, HttpResponse}; +// use futures::Future; + +// fn index(req: HttpRequest) -> Box> { +// // get multipart and iterate over multipart items +// req.multipart().and_then(|item| match item { +// multipart::MultipartItem::Field(field) => { +// println!( +// "==== FIELD ==== {:?} {:?}", +// field.headers(), +// field.content_type() +// ); +// Either::A( +// field +// .map(|chunk| { +// println!("-- CHUNK: \n{}", std::str::from_utf8(&chunk).unwrap()); +// }) +// .fold((), |_, _| result(Ok(()))), +// ) +// } +// multipart::MultipartItem::Nested(mp) => Either::B(result(Ok(()))), +// }) +// } +// diff --git a/examples/requests/src/streaming.rs b/examples/requests/src/streaming.rs new file mode 100644 index 0000000..191d32a --- /dev/null +++ b/examples/requests/src/streaming.rs @@ -0,0 +1,15 @@ +// +// use actix_web::{error, web, Error, HttpResponse}; +// use futures::{future::result, Future, Stream}; + +// fn index(payload: web::Payload) -> Box> { +// payload +// .from_err() +// .fold((), |_, chunk| { +// println!("Chunk: {:?}", chunk); +// result::<_, error::PayloadError>(Ok(())) +// }) +// .map(|_| HttpResponse::Ok().finish()) +// .responder() +// } +// diff --git a/examples/requests/src/urlencoded.rs b/examples/requests/src/urlencoded.rs new file mode 100644 index 0000000..5439d0d --- /dev/null +++ b/examples/requests/src/urlencoded.rs @@ -0,0 +1,22 @@ +// +// use actix_web::{Error, HttpRequest, HttpResponse}; +// use futures::future::{ok, Future}; +// use serde::Deserialize; + +// #[derive(Deserialize)] +// struct FormData { +// username: String, +// } + +// fn index(req: &HttpRequest) -> Box> { +// req.urlencoded::() // <- get UrlEncoded future +// .from_err() +// .and_then(|data| { +// // <- deserialized instance +// println!("USERNAME: {:?}", data.username); +// ok(HttpResponse::Ok().into()) +// }) +// .responder() +// } +// +fn main() {} From ea1600c417b046332b0b491ec785eab594e32786 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Mon, 17 Jun 2019 15:15:33 -0400 Subject: [PATCH 24/68] First pass at Responses section. --- content/docs/response.md | 107 +++---------------------- examples/Cargo.toml | 1 + examples/responses/Cargo.toml | 10 +++ examples/responses/src/auto.rs | 16 ++++ examples/responses/src/brotli.rs | 13 +++ examples/responses/src/chunked.rs | 14 ++++ examples/responses/src/identity.rs | 12 +++ examples/responses/src/identity_two.rs | 18 +++++ examples/responses/src/json_resp.rs | 19 +++++ examples/responses/src/main.rs | 21 +++++ 10 files changed, 135 insertions(+), 96 deletions(-) create mode 100644 examples/responses/Cargo.toml create mode 100644 examples/responses/src/auto.rs create mode 100644 examples/responses/src/brotli.rs create mode 100644 examples/responses/src/chunked.rs create mode 100644 examples/responses/src/identity.rs create mode 100644 examples/responses/src/identity_two.rs create mode 100644 examples/responses/src/json_resp.rs create mode 100644 examples/responses/src/main.rs diff --git a/content/docs/response.md b/content/docs/response.md index 369b869..b890eb9 100644 --- a/content/docs/response.md +++ b/content/docs/response.md @@ -17,17 +17,7 @@ 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 -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") -} -``` +{{< include-example example="responses" file="main.rs" section="builder" >}} # Content encoding @@ -38,80 +28,34 @@ Actix automatically *compresses* payloads. The following codecs are supported: * Deflate * Identity -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. +Response payload is compressed based on the *encoding* parameter from the +`middleware::BodyEncoding` trait. 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 -use actix_web::{HttpRequest, HttpResponse, http::ContentEncoding}; - -fn index(req: HttpRequest) -> HttpResponse { - HttpResponse::Ok() - .content_encoding(ContentEncoding::Br) - .body("data") -} -``` +{{< include-example example="responses" file="brotli.rs" section="brotli" >}} In this case we explicitly disable content compression by setting content encoding to a `Identity` value: -```rust -use actix_web::{HttpRequest, HttpResponse, http::ContentEncoding}; - -fn index(req: HttpRequest) -> HttpResponse { - HttpResponse::Ok() - // v- disable compression - .content_encoding(ContentEncoding::Identity) - .body("data") -} -``` +{{< include-example example="responses" file="identity.rs" section="identity" >}} When dealing with an already compressed body (for example when serving assets), set the content encoding to `Identity` to avoid compressing the already compressed data and set the `content-encoding` header manually: -```rust -use actix_web::{HttpRequest, HttpResponse, http::ContentEncoding}; - -static HELLO_WORLD: &[u8] = &[ - 0x1f,0x8b,0x08,0x00,0xa2,0x30,0x10,0x5c, - 0x00,0x03,0xcb,0x48,0xcd,0xc9,0xc9,0x57, - 0x28,0xcf,0x2f,0xca,0x49,0xe1,0x02,0x00, - 0x2d,0x3b,0x08,0xaf,0x0c,0x00,0x00,0x00 -]; - -pub fn index(req: HttpRequest) -> HttpResponse { - HttpResponse::Ok() - .content_encoding(ContentEncoding::Identity) - .header("content-encoding", "gzip") - .body(HELLO_WORLD) -} -``` +{{< include-example example="responses" file="identity_two.rs" section="identity-two" >}} 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 -use actix_web::{App, HttpRequest, HttpResponse, http::ContentEncoding}; - -fn index(req: HttpRequest) -> HttpResponse { - HttpResponse::Ok() - .body("data") -} - -fn main() { - let app = App::new() - // v- disable compression for all routes - .default_encoding(ContentEncoding::Identity) - .resource("/index.html", |r| r.with(index)); -} -``` +{{< include-example example="responses" file="auto.rs" section="auto" >}} # JSON Response @@ -119,26 +63,7 @@ The `Json` type allows to respond with well-formed JSON data: simply return a va type Json 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> { - 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(); -} -``` +{{< include-example example="responses" file="json_resp.rs" section="json-resp" >}} # Chunked transfer encoding @@ -149,14 +74,4 @@ is enabled automatically. > Enabling chunked encoding for *HTTP/2.0* responses is forbidden. -```rust -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")))))) -} -``` +{{< include-example example="responses" file="chunked.rs" section="chunked" >}} diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 05f095a..6b54cd8 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -19,4 +19,5 @@ exclude = [ "autoreload", "errors", "requests", + "responses", ] diff --git a/examples/responses/Cargo.toml b/examples/responses/Cargo.toml new file mode 100644 index 0000000..53b9236 --- /dev/null +++ b/examples/responses/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "responses" +version = "0.1.0" +edition = "2018" + +[dependencies] +actix-web = "1.0" +serde = "1.0" +futures = "0.1" +bytes = "0.4" diff --git a/examples/responses/src/auto.rs b/examples/responses/src/auto.rs new file mode 100644 index 0000000..598513a --- /dev/null +++ b/examples/responses/src/auto.rs @@ -0,0 +1,16 @@ +// +use actix_web::{ + http::ContentEncoding, middleware, web, App, HttpRequest, HttpResponse, +}; + +fn index(req: HttpRequest) -> HttpResponse { + HttpResponse::Ok().body("data") +} + +fn main() { + let app = App::new() + // v- disable compression for all routes + .wrap(middleware::Compress::new(ContentEncoding::Identity)) + .route("/", web::get().to(index)); +} +// diff --git a/examples/responses/src/brotli.rs b/examples/responses/src/brotli.rs new file mode 100644 index 0000000..e107ad7 --- /dev/null +++ b/examples/responses/src/brotli.rs @@ -0,0 +1,13 @@ +// +use actix_web::{ + http::ContentEncoding, middleware::BodyEncoding, HttpRequest, HttpResponse, +}; + +fn index_br(req: HttpRequest) -> HttpResponse { + HttpResponse::Ok() + .encoding(ContentEncoding::Br) + .body("data") +} +// + +fn main() {} diff --git a/examples/responses/src/chunked.rs b/examples/responses/src/chunked.rs new file mode 100644 index 0000000..0cd6d76 --- /dev/null +++ b/examples/responses/src/chunked.rs @@ -0,0 +1,14 @@ +// +// use actix_web::{web, HttpRequest, HttpResponse}; +// 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() {} diff --git a/examples/responses/src/identity.rs b/examples/responses/src/identity.rs new file mode 100644 index 0000000..89bd52e --- /dev/null +++ b/examples/responses/src/identity.rs @@ -0,0 +1,12 @@ +// +use actix_web::{ + http::ContentEncoding, middleware::BodyEncoding, HttpRequest, HttpResponse, +}; + +fn index(req: HttpRequest) -> HttpResponse { + HttpResponse::Ok() + // v- disable compression + .encoding(ContentEncoding::Identity) + .body("data") +} +// diff --git a/examples/responses/src/identity_two.rs b/examples/responses/src/identity_two.rs new file mode 100644 index 0000000..63371fa --- /dev/null +++ b/examples/responses/src/identity_two.rs @@ -0,0 +1,18 @@ +// +use actix_web::{ + http::ContentEncoding, middleware::BodyEncoding, HttpRequest, HttpResponse, +}; + +static HELLO_WORLD: &[u8] = &[ + 0x1f, 0x8b, 0x08, 0x00, 0xa2, 0x30, 0x10, 0x5c, 0x00, 0x03, 0xcb, 0x48, 0xcd, 0xc9, + 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1, 0x02, 0x00, 0x2d, 0x3b, 0x08, 0xaf, + 0x0c, 0x00, 0x00, 0x00, +]; + +pub fn index(_req: HttpRequest) -> HttpResponse { + HttpResponse::Ok() + .encoding(ContentEncoding::Identity) + .header("content-encoding", "gzip") + .body(HELLO_WORLD) +} +// diff --git a/examples/responses/src/json_resp.rs b/examples/responses/src/json_resp.rs new file mode 100644 index 0000000..c2344c0 --- /dev/null +++ b/examples/responses/src/json_resp.rs @@ -0,0 +1,19 @@ +// +use actix_web::{web, App, HttpRequest, Result}; +use serde::Serialize; + +#[derive(Serialize)] +struct MyObj { + name: String, +} + +fn index(req: HttpRequest) -> Result> { + Ok(web::Json(MyObj { + name: req.match_info().query("name").to_string(), + })) +} + +fn main() { + App::new().route(r"/a/{name}", web::get().to(index)); +} +// diff --git a/examples/responses/src/main.rs b/examples/responses/src/main.rs new file mode 100644 index 0000000..4c9f209 --- /dev/null +++ b/examples/responses/src/main.rs @@ -0,0 +1,21 @@ +mod auto; +mod brotli; +mod chunked; +mod identity; +mod identity_two; +mod json_resp; +// +use actix_web::{ + http::ContentEncoding, middleware::BodyEncoding, HttpRequest, HttpResponse, +}; + +fn index(_req: HttpRequest) -> HttpResponse { + HttpResponse::Ok() + .encoding(ContentEncoding::Br) + .content_type("plain/text") + .header("X-Hdr", "sample") + .body("data") +} +// + +fn main() {} From 083522ef19ad0b2ffaa0fb93590089ca0e198869 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Mon, 17 Jun 2019 15:39:58 -0400 Subject: [PATCH 25/68] first pass at Testing. --- content/docs/testing.md | 189 +--------------------- examples/Cargo.toml | 1 + examples/testing/Cargo.toml | 10 ++ examples/testing/src/integration_one.rs | 22 +++ examples/testing/src/integration_three.rs | 21 +++ examples/testing/src/integration_two.rs | 21 +++ examples/testing/src/main.rs | 29 ++++ examples/testing/src/stream_response.rs | 50 ++++++ examples/testing/src/websockets.rs | 30 ++++ 9 files changed, 192 insertions(+), 181 deletions(-) create mode 100644 examples/testing/Cargo.toml create mode 100644 examples/testing/src/integration_one.rs create mode 100644 examples/testing/src/integration_three.rs create mode 100644 examples/testing/src/integration_two.rs create mode 100644 examples/testing/src/main.rs create mode 100644 examples/testing/src/stream_response.rs create mode 100644 examples/testing/src/websockets.rs diff --git a/content/docs/testing.md b/content/docs/testing.md index 2db98df..5f7b59d 100644 --- a/content/docs/testing.md +++ b/content/docs/testing.md @@ -14,33 +14,10 @@ integration tests. For unit testing, actix provides a request builder type and a simple handler runner. [*TestRequest*](../../actix-web/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()`. +You can generate a `HttpRequest` instance with `to_http_request()`, or you can +run your handler with `block_on()`. -```rust -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); -} -``` +{{< include-example example="testing" file="main.rs" section="unit-tests" >}} # Integration tests @@ -58,146 +35,26 @@ for this function is a *test application* instance. > Check the [api documentation](../../actix-web/actix_web/test/struct.TestApp.html) > for more information. -```rust -use actix_web::{HttpRequest, HttpMessage}; -use actix_web::test::TestServer; -use std::str; - -fn index(req: &HttpRequest) -> &'static str { - "Hello world!" -} - -fn main() { - // start new test server - let mut srv = TestServer::new(|app| app.handler(index)); - - let request = srv.get().finish().unwrap(); - let response = srv.execute(request.send()).unwrap(); - assert!(response.status().is_success()); - - let bytes = srv.execute(response.body()).unwrap(); - let body = str::from_utf8(&bytes).unwrap(); - assert_eq!(body, "Hello world!"); -} -``` +{{< include-example example="testing" file="integration_one.rs" section="integration-one" >}} 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 -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); - - let request = srv.client( - http::Method::GET, "/test").finish().unwrap(); - let response = srv.execute(request.send()).unwrap(); - - assert!(response.status().is_success()); -} -``` +{{< include-example example="testing" file="integration_two.rs" section="integration-two" >}} 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 -#[test] -fn test() { - let srv = TestServer::build_with_state(|| { - // 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} - }) - - // register server handlers and start test server - .start(|app| { - app.resource( - "/{username}/index.html", |r| r.with( - |p: Path| format!("Welcome {}!", p.username))); - }); - - // now we can run our test code -); -``` - +{{< include-example example="testing" file="integration_three.rs" section="integration-three" >}} # Stream response tests If you need to test stream it would be enough to convert a [*ClientResponse*](../../actix-web/actix_web/client/struct.ClientResponse.html) to future and execute it. For example of testing [*Server Sent Events*](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events). -```rust -extern crate bytes; -extern crate futures; -extern crate actix_web; - -use bytes::Bytes; -use futures::stream::poll_fn; -use futures::{Async, Poll, Stream}; - -use actix_web::{Error, HttpMessage, HttpRequest, HttpResponse}; -use actix_web::http::{ContentEncoding, StatusCode}; -use actix_web::test::TestServer; - - -fn sse(_req: &HttpRequest) -> HttpResponse { - let mut counter = 5usize; - // yields `data: N` where N in [5; 1] - let server_events = poll_fn(move || -> Poll, Error> { - if counter == 0 { - return Ok(Async::Ready(None)); - } - let payload = format!("data: {}\n\n", counter); - counter -= 1; - Ok(Async::Ready(Some(Bytes::from(payload)))) - }); - - HttpResponse::build(StatusCode::OK) - .content_encoding(ContentEncoding::Identity) - .content_type("text/event-stream") - .streaming(server_events) -} - - -fn main() { - // start new test server - let mut srv = TestServer::new(|app| app.handler(sse)); - - // request stream - let request = srv.get().finish().unwrap(); - let response = srv.execute(request.send()).unwrap(); - assert!(response.status().is_success()); - - // convert ClientResponse to future, start read body and wait first chunk - let mut stream = response.payload(); - loop { - match srv.execute(stream.into_future()) { - Ok((Some(bytes), remain)) => { - println!("{:?}", bytes); - stream = remain - } - Ok((None, _)) => break, - Err(_) => panic!(), - } - } -} -``` +{{< include-example example="testing" file="stream_response.rs" section="stream-response" >}} # WebSocket server tests @@ -209,34 +66,4 @@ result of the future computation. The following example demonstrates how to test a websocket handler: -```rust -use actix::{Actor, StreamHandler}; -use actix_web::*; -use futures::Stream; - -struct Ws; // <- WebSocket actor - -impl Actor for Ws { - type Context = ws::WebsocketContext; -} - -impl StreamHandler 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( - |app| app.handler(|req| ws::start(req, Ws))); - - let (reader, mut writer) = srv.ws().unwrap(); - writer.text("text"); - - let (item, reader) = srv.execute(reader.into_future()).unwrap(); - assert_eq!(item, Some(ws::Message::Text("text".to_owned()))); -} -``` +{{< include-example example="testing" file="websockets.rs" section="web-socket" >}} diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 6b54cd8..94df1cc 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -20,4 +20,5 @@ exclude = [ "errors", "requests", "responses", + "testing", ] diff --git a/examples/testing/Cargo.toml b/examples/testing/Cargo.toml new file mode 100644 index 0000000..d9b43d6 --- /dev/null +++ b/examples/testing/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "testing" +version = "0.1.0" +authors = ["Cameron Dershem "] +edition = "2018" + +[dependencies] +actix-web = "1.0" +futures = "0.1" +bytes = "0.4" diff --git a/examples/testing/src/integration_one.rs b/examples/testing/src/integration_one.rs new file mode 100644 index 0000000..5507d7d --- /dev/null +++ b/examples/testing/src/integration_one.rs @@ -0,0 +1,22 @@ +// +// use actix_web::test::TestServer; +// use actix_web::HttpRequest; +// use std::str; + +// fn index(req: HttpRequest) -> &'static str { +// "Hello world!" +// } + +// fn main() { +// // start new test server +// let mut srv = TestServer::new(|app| app.handler(index)); + +// let request = srv.get().finish().unwrap(); +// let response = srv.execute(request.send()).unwrap(); +// assert!(response.status().is_success()); + +// let bytes = srv.execute(response.body()).unwrap(); +// let body = str::from_utf8(&bytes).unwrap(); +// assert_eq!(body, "Hello world!"); +// } +// diff --git a/examples/testing/src/integration_three.rs b/examples/testing/src/integration_three.rs new file mode 100644 index 0000000..1373b32 --- /dev/null +++ b/examples/testing/src/integration_three.rs @@ -0,0 +1,21 @@ +// +// #[test] +// fn test() { +// let srv = TestServer::build_with_state(|| { +// // 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} +// }) + +// // register server handlers and start test server +// .start(|app| { +// app.resource( +// "/{username}/index.html", |r| r.with( +// |p: Path| format!("Welcome {}!", p.username))); +// }); +// // now we can run our test code +// ); +// diff --git a/examples/testing/src/integration_two.rs b/examples/testing/src/integration_two.rs new file mode 100644 index 0000000..b5920f7 --- /dev/null +++ b/examples/testing/src/integration_two.rs @@ -0,0 +1,21 @@ +// +// 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); + +// let request = srv.client(http::Method::GET, "/test").finish().unwrap(); +// let response = srv.execute(request.send()).unwrap(); + +// assert!(response.status().is_success()); +// } +// diff --git a/examples/testing/src/main.rs b/examples/testing/src/main.rs new file mode 100644 index 0000000..82b8bc4 --- /dev/null +++ b/examples/testing/src/main.rs @@ -0,0 +1,29 @@ +mod integration_one; +mod integration_three; +mod integration_two; +mod stream_response; +mod websockets; +// +use actix_web::{http, test, HttpRequest, HttpResponse}; + +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 req = + test::TestRequest::with_header("content-type", "text/plain").to_http_request(); + + let resp = test::block_on(index(req)).unwrap(); + assert_eq!(resp.status(), http::StatusCode::OK); + + let req = test::TestRequest::default().to_http_request(); + let resp = test::block_on(index(req)).unwrap(); + assert_eq!(resp.status(), http::StatusCode::BAD_REQUEST); +} +// diff --git a/examples/testing/src/stream_response.rs b/examples/testing/src/stream_response.rs new file mode 100644 index 0000000..9fea603 --- /dev/null +++ b/examples/testing/src/stream_response.rs @@ -0,0 +1,50 @@ +// +// use bytes::Bytes; +// use futures::stream::poll_fn; +// use futures::{Async, Poll, Stream}; + +// use actix_web::http::{ContentEncoding, StatusCode}; +// use actix_web::test::TestServer; +// use actix_web::{Error, HttpRequest, HttpResponse}; + +// fn sse(_req: &HttpRequest) -> HttpResponse { +// let mut counter = 5usize; +// // yields `data: N` where N in [5; 1] +// let server_events = poll_fn(move || -> Poll, Error> { +// if counter == 0 { +// return Ok(Async::Ready(None)); +// } +// let payload = format!("data: {}\n\n", counter); +// counter -= 1; +// Ok(Async::Ready(Some(Bytes::from(payload)))) +// }); + +// HttpResponse::build(StatusCode::OK) +// .content_encoding(ContentEncoding::Identity) +// .content_type("text/event-stream") +// .streaming(server_events) +// } + +// fn main() { +// // start new test server +// let mut srv = TestServer::new(|app| app.handler(sse)); + +// // request stream +// let request = srv.get().finish().unwrap(); +// let response = srv.execute(request.send()).unwrap(); +// assert!(response.status().is_success()); + +// // convert ClientResponse to future, start read body and wait first chunk +// let mut stream = response.payload(); +// loop { +// match srv.execute(stream.into_future()) { +// Ok((Some(bytes), remain)) => { +// println!("{:?}", bytes); +// stream = remain +// } +// Ok((None, _)) => break, +// Err(_) => panic!(), +// } +// } +// } +// diff --git a/examples/testing/src/websockets.rs b/examples/testing/src/websockets.rs new file mode 100644 index 0000000..8034116 --- /dev/null +++ b/examples/testing/src/websockets.rs @@ -0,0 +1,30 @@ +// +use actix::{Actor, StreamHandler}; +use actix_web::*; +use futures::Stream; + +struct Ws; // <- WebSocket actor + +impl Actor for Ws { + type Context = ws::WebsocketContext; +} + +impl StreamHandler 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(|app| app.handler(|req| ws::start(req, Ws))); + + let (reader, mut writer) = srv.ws().unwrap(); + writer.text("text"); + + let (item, reader) = srv.execute(reader.into_future()).unwrap(); + assert_eq!(item, Some(ws::Message::Text("text".to_owned()))); +} +// From 9a16b6db938ec02a7dad188475fb2a2c650de398 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Mon, 17 Jun 2019 16:57:57 -0400 Subject: [PATCH 26/68] First pass at Middlewares. --- content/docs/middleware.md | 138 ++------------------- examples/Cargo.toml | 1 + examples/middleware/Cargo.toml | 11 ++ examples/middleware/src/default_headers.rs | 16 +++ examples/middleware/src/errorhandler.rs | 25 ++++ examples/middleware/src/logger.rs | 14 +++ examples/middleware/src/main.rs | 72 +++++++++++ examples/middleware/src/user_sessions.rs | 37 ++++++ 8 files changed, 189 insertions(+), 125 deletions(-) create mode 100644 examples/middleware/Cargo.toml create mode 100644 examples/middleware/src/default_headers.rs create mode 100644 examples/middleware/src/errorhandler.rs create mode 100644 examples/middleware/src/logger.rs create mode 100644 examples/middleware/src/main.rs create mode 100644 examples/middleware/src/user_sessions.rs diff --git a/content/docs/middleware.md b/content/docs/middleware.md index c024289..0a1c853 100644 --- a/content/docs/middleware.md +++ b/content/docs/middleware.md @@ -21,48 +21,14 @@ Typically, middleware is involved in the following actions: 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/actix_web/middleware/trait.Middleware.html). -Each method in this trait has a default implementation. Each method can return +[*Service trait*](../../actix-web/actix_web/dev/trait.Service.html) and +[*Transform trait*](../../actix-web/actix_web/dev/trait.Transform.html). +Each method in the traits 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: +The following demonstrates creating a simple middleware: -```rust -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 Middleware 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: &HttpRequest) -> Result { - Ok(Started::Done) - } - - /// Method is called when handler returns response, - /// but before sending http message to peer. - fn response(&self, req: &HttpRequest, mut resp: HttpResponse) - -> Result - { - 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() - // Register middleware, this method can be called multiple times - .middleware(Headers) - .resource("/", |r| r.f(|_| HttpResponse::Ok())); -} -``` +{{< include-example example="middleware" file="main.rs" section="main" >}} > Actix provides several useful middlewares, such as *logging*, *user sessions*, etc. @@ -85,21 +51,7 @@ Default `Logger` can be created with `default` method, it uses the default forma %a %t "%r" %s %b "%{Referer}i" "%{User-Agent}i" %T ``` -```rust -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(); -} -``` +{{< include-example example="middleware" file="logger.rs" section="logger" >}} The following is an example of the default logging format: @@ -140,37 +92,23 @@ To set default response headers, the `DefaultHeaders` middleware can be used. Th *DefaultHeaders* middleware does not set the header if response headers already contain a specified header. -```rust -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(); -} -``` +{{< include-example example="middleware" file="default_headers.rs" section="default-headers" >}} ## User sessions Actix provides a general solution for session management. The -[**SessionStorage**](../../actix-web/actix_web/middleware/session/struct.SessionStorage.html) middleware can be +[**actix-session**](https://docs.rs/actix-session/0.1.1/actix_session/) 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/actix_web/middleware/session/struct.CookieSessionBackend.html) +[**CookieSession**](../../actix-web/actix_web/middleware/session/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 cookie may have a security policy of *signed* or *private*. Each has a respective `CookieSession` 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. @@ -178,41 +116,13 @@ The constructors take a key as an argument. This is the private key for cookie s In general, you create a `SessionStorage` middleware and initialize it with specific backend implementation, -such as a `CookieSessionBackend`. To access session data, +such as a `CookieSession`. To access session data, [*HttpRequest::session()*](../../actix-web/actix_web/middleware/session/trait.RequestSession.html#tymethod.session) must be used. This method returns a [*Session*](../../actix-web/actix_web/middleware/session/struct.Session.html) object, which allows us to get or set session data. -```rust -use actix_web::{server, App, HttpRequest, Result}; -use actix_web::middleware::session::{RequestSession, SessionStorage, CookieSessionBackend}; - -fn index(req: &HttpRequest) -> Result<&'static str> { - // access session data - if let Some(count) = req.session().get::("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( - CookieSessionBackend::signed(&[0; 32]) - .secure(false) - ))) - .bind("127.0.0.1:59880").unwrap() - .start(); - let _ = sys.run(); -} -``` +{{< include-example example="middleware" file="user_sessions.rs" section="user-session" >}} # Error handlers @@ -223,26 +133,4 @@ for a specific status code. You can modify an existing response or create a comp one. The error handler can return a response immediately or return a future that resolves into a response. -```rust -use actix_web::{ - App, HttpRequest, HttpResponse, Result, - http, middleware::Response, middleware::ErrorHandlers}; - -fn render_500(_: &HttpRequest, resp: HttpResponse) -> Result { - 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(); -} -``` +{{< include-example example="middleware" file="errorhandler.rs" section="error-handler" >}} diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 94df1cc..ae1746f 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -21,4 +21,5 @@ exclude = [ "requests", "responses", "testing", + "middleware", ] diff --git a/examples/middleware/Cargo.toml b/examples/middleware/Cargo.toml new file mode 100644 index 0000000..dceb867 --- /dev/null +++ b/examples/middleware/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "middleware" +version = "0.1.0" +edition = "2018" + +[dependencies] +actix-web = "1.0" +actix-service = "0.4" +actix-session = "0.1" +futures = "0.1" +env_logger = "0.6" diff --git a/examples/middleware/src/default_headers.rs b/examples/middleware/src/default_headers.rs new file mode 100644 index 0000000..a81e7a1 --- /dev/null +++ b/examples/middleware/src/default_headers.rs @@ -0,0 +1,16 @@ +// +use actix_web::{http, middleware, web, App, HttpResponse}; + +fn main() { + App::new() + .wrap(middleware::DefaultHeaders::new().header("X-Version", "0.2")) + .service( + web::resource("/test") + .route(web::get().to(|| HttpResponse::Ok())) + .route( + web::method(http::Method::HEAD) + .to(|| HttpResponse::MethodNotAllowed()), + ), + ); +} +// diff --git a/examples/middleware/src/errorhandler.rs b/examples/middleware/src/errorhandler.rs new file mode 100644 index 0000000..dd3b440 --- /dev/null +++ b/examples/middleware/src/errorhandler.rs @@ -0,0 +1,25 @@ +// +use actix_web::middleware::errhandlers::{ErrorHandlerResponse, ErrorHandlers}; +use actix_web::{dev, http, web, App, HttpResponse, Result}; + +fn render_500(mut res: dev::ServiceResponse) -> Result> { + res.response_mut().headers_mut().insert( + http::header::CONTENT_TYPE, + http::HeaderValue::from_static("Error"), + ); + Ok(ErrorHandlerResponse::Response(res)) +} + +fn main() { + App::new() + .wrap( + ErrorHandlers::new() + .handler(http::StatusCode::INTERNAL_SERVER_ERROR, render_500), + ) + .service( + web::resource("/test") + .route(web::get().to(|| HttpResponse::Ok())) + .route(web::head().to(|| HttpResponse::MethodNotAllowed())), + ); +} +// diff --git a/examples/middleware/src/logger.rs b/examples/middleware/src/logger.rs new file mode 100644 index 0000000..e660723 --- /dev/null +++ b/examples/middleware/src/logger.rs @@ -0,0 +1,14 @@ +// +use actix_web::middleware::Logger; +use actix_web::App; +use env_logger; + +fn main() { + std::env::set_var("RUST_LOG", "actix_web=info"); + env_logger::init(); + + App::new() + .wrap(Logger::default()) + .wrap(Logger::new("%a %{User-Agent}i")); +} +// diff --git a/examples/middleware/src/main.rs b/examples/middleware/src/main.rs new file mode 100644 index 0000000..4d4168f --- /dev/null +++ b/examples/middleware/src/main.rs @@ -0,0 +1,72 @@ +mod default_headers; +mod errorhandler; +mod logger; +mod user_sessions; +//
+use actix_service::{Service, Transform}; +use actix_web::{dev::ServiceRequest, dev::ServiceResponse, web, App, Error}; +use futures::future::{ok, FutureResult}; +use futures::{Future, Poll}; + +// There are two steps in middleware processing. +// 1. Middleware initialization, middleware factory gets called with +// next service in chain as parameter. +// 2. Middleware's call method gets called with normal request. +pub struct SayHi; + +// Middleware factory is `Transform` trait from actix-service crate +// `S` - type of the next service +// `B` - type of response's body +impl Transform for SayHi +where + S: Service, Error = Error>, + S::Future: 'static, + B: 'static, +{ + type Request = ServiceRequest; + type Response = ServiceResponse; + type Error = Error; + type InitError = (); + type Transform = SayHiMiddleware; + type Future = FutureResult; + + fn new_transform(&self, service: S) -> Self::Future { + ok(SayHiMiddleware { service }) + } +} + +pub struct SayHiMiddleware { + service: S, +} + +impl Service for SayHiMiddleware +where + S: Service, Error = Error>, + S::Future: 'static, + B: 'static, +{ + type Request = ServiceRequest; + type Response = ServiceResponse; + type Error = Error; + type Future = Box>; + + fn poll_ready(&mut self) -> Poll<(), Self::Error> { + self.service.poll_ready() + } + + fn call(&mut self, req: ServiceRequest) -> Self::Future { + println!("Hi from start. You requested: {}", req.path()); + + Box::new(self.service.call(req).and_then(|res| { + println!("Hi from response"); + Ok(res) + })) + } +} +//
+fn main() { + App::new().wrap(SayHi).service( + web::resource("/") + .to(|| "Hello, middleware! Check the console where the server is run."), + ); +} diff --git a/examples/middleware/src/user_sessions.rs b/examples/middleware/src/user_sessions.rs new file mode 100644 index 0000000..42fafff --- /dev/null +++ b/examples/middleware/src/user_sessions.rs @@ -0,0 +1,37 @@ +// +use actix_session::{CookieSession, Session}; +use actix_web::{middleware::Logger, web, App, HttpRequest, HttpServer, Result}; + +/// simple index handler with session +fn index(session: Session, req: HttpRequest) -> Result<&'static str> { + println!("{:?}", req); + + // RequestSession trait is used for session access + let mut counter = 1; + if let Some(count) = session.get::("counter")? { + println!("SESSION value: {}", count); + counter = count + 1; + session.set("counter", counter)?; + } else { + session.set("counter", counter)?; + } + + Ok("welcome!") +} + +fn main() -> std::io::Result<()> { + std::env::set_var("RUST_LOG", "actix_web=info"); + env_logger::init(); + + HttpServer::new(|| { + App::new() + // enable logger + .wrap(Logger::default()) + // cookie session middleware + .wrap(CookieSession::signed(&[0; 32]).secure(false)) + .service(web::resource("/").to(index)) + }) + .bind("127.0.0.1:8080")? + .run() +} +// From 769c9af8f94807f809dcdd6962d2382a0fe6783b Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Mon, 17 Jun 2019 17:35:47 -0400 Subject: [PATCH 27/68] First pass at Static Files. --- content/docs/static-files.md | 104 ++---------------- examples/Cargo.toml | 1 + examples/static-files/Cargo.toml | 10 ++ examples/static-files/src/configuration.rs | 27 +++++ .../static-files/src/configuration_two.rs | 26 +++++ examples/static-files/src/directory.rs | 8 ++ examples/static-files/src/main.rs | 17 +++ 7 files changed, 99 insertions(+), 94 deletions(-) create mode 100644 examples/static-files/Cargo.toml create mode 100644 examples/static-files/src/configuration.rs create mode 100644 examples/static-files/src/configuration_two.rs create mode 100644 examples/static-files/src/directory.rs create mode 100644 examples/static-files/src/main.rs diff --git a/content/docs/static-files.md b/content/docs/static-files.md index 6f3d385..abfc003 100644 --- a/content/docs/static-files.md +++ b/content/docs/static-files.md @@ -9,53 +9,24 @@ weight: 230 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 { - 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(); -} -``` +{{< include-example example="static-files" file="main.rs" section="individual-file" >}} # Directory -To serve files from specific directories and sub-directories, `StaticFiles` can be used. -`StaticFiles` must be registered with an `App::handler()` method, otherwise +To serve files from specific directories and sub-directories, `Files` can be used. +`Files` must be registered with an `App::service()` method, otherwise it will be unable to serve sub-paths. -```rust -extern crate actix_web; -use actix_web::{App, fs}; +{{< include-example example="static-files" file="directory.rs" section="directory" >}} -fn main() { - App::new() - .handler( - "/static", - fs::StaticFiles::new(".") - .unwrap() - .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/actix_web/fs/struct.StaticFiles.html#method.show_files_listing) +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 +[*Files::show_files_listing()*](https://docs.rs/actix-files/0.1.2/actix_files/struct.Files.html) 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/actix_web/fs/struct.StaticFiles.html#method.index_file) +[*Files::index_file()*](https://docs.rs/actix-files/0.1.2/actix_files/struct.Files.html#method.index_file) method to configure this redirect. # Configuration @@ -71,63 +42,8 @@ for serving files: All of the above methods are optional and provided with the best defaults. But it is possible to customize any of them by implementing the trait onto own struct. -```rust -extern crate mime; -extern crate actix_web; -use actix_web::{App, HttpRequest, Result, http::Method}; -use actix_web::fs::{StaticFileConfig, NamedFile}; -use actix_web::http::header::DispositionType; - -use std::path::PathBuf; - -#[derive(Default)] -struct MyConfig; - -impl StaticFileConfig for MyConfig { - fn content_disposition_map(typ: mime::Name) -> DispositionType { - DispositionType::Attachment - } -} - -fn index(req: &HttpRequest) -> Result> { - let path: PathBuf = req.match_info().query("tail")?; - Ok(NamedFile::open_with_config(path, MyConfig)?) -} - -fn main() { - App::new() - .resource(r"/a/{tail:.*}", |r| r.method(Method::GET).f(index)) - .finish(); -} -``` +{{< include-example example="static-files" file="configuration.rs" section="config-one" >}} The Configuration cal also be applied to directory service: -```rust -extern crate actix_web; - -use actix_web::{App}; -use actix_web::fs::{StaticFileConfig, StaticFiles}; - -#[derive(Default)] -struct MyConfig; - -impl StaticFileConfig for MyConfig { - fn is_use_etag() -> bool { - false - } - - fn is_use_last_modifier() -> bool { - false - } -} - -fn main() { - App::new() - .handler( - "/static", - StaticFiles::with_config(".", MyConfig).unwrap() - .show_files_listing() - ).finish(); -} -``` +{{< include-example example="static-files" file="configuration_two.rs" section="config-two" >}} diff --git a/examples/Cargo.toml b/examples/Cargo.toml index ae1746f..981e7a6 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -22,4 +22,5 @@ exclude = [ "responses", "testing", "middleware", + "static-files", ] diff --git a/examples/static-files/Cargo.toml b/examples/static-files/Cargo.toml new file mode 100644 index 0000000..242abb0 --- /dev/null +++ b/examples/static-files/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "static-files" +version = "0.1.0" +authors = ["Cameron Dershem "] +edition = "2018" + +[dependencies] +actix-web = "1.0" +actix-files = "0.1" +mime = "*" diff --git a/examples/static-files/src/configuration.rs b/examples/static-files/src/configuration.rs new file mode 100644 index 0000000..b608e0c --- /dev/null +++ b/examples/static-files/src/configuration.rs @@ -0,0 +1,27 @@ +// +// extern crate actix_web; +// extern crate mime; +// use actix_files::{FileConfig, NamedFile}; +// use actix_web::http::header::DispositionType; +// use actix_web::{http::Method, App, HttpRequest, Result}; + +// use std::path::PathBuf; + +// #[derive(Default)] +// struct MyConfig; + +// impl FileConfig for MyConfig { +// fn content_disposition_map(typ: mime::Name) -> DispositionType { +// DispositionType::Attachment +// } +// } + +// fn index(req: &HttpRequest) -> Result> { +// let path: PathBuf = req.match_info().query("tail")?; +// Ok(NamedFile::open_with_config(path, MyConfig)?) +// } + +// fn main() { +// App::new().resource(r"/a/{tail:.*}", |r| r.method(Method::GET).f(index)); +// } +// diff --git a/examples/static-files/src/configuration_two.rs b/examples/static-files/src/configuration_two.rs new file mode 100644 index 0000000..c9c0850 --- /dev/null +++ b/examples/static-files/src/configuration_two.rs @@ -0,0 +1,26 @@ +// +// use actix_files::{FileConfig, Files}; +// use actix_web::App; + +// #[derive(Default)] +// struct MyConfig; + +// impl FileConfig for MyConfig { +// fn is_use_etag() -> bool { +// false +// } + +// fn is_use_last_modifier() -> bool { +// false +// } +// } + +// fn main() { +// App::new().service( +// "/static", +// Files::with_config(".", MyConfig) +// .unwrap() +// .show_files_listing(), +// ); +// } +// diff --git a/examples/static-files/src/directory.rs b/examples/static-files/src/directory.rs new file mode 100644 index 0000000..b547650 --- /dev/null +++ b/examples/static-files/src/directory.rs @@ -0,0 +1,8 @@ +// +use actix_files as fs; +use actix_web::App; + +fn main() { + App::new().service(fs::Files::new("/static", ".").show_files_listing()); +} +// diff --git a/examples/static-files/src/main.rs b/examples/static-files/src/main.rs new file mode 100644 index 0000000..4d1840a --- /dev/null +++ b/examples/static-files/src/main.rs @@ -0,0 +1,17 @@ +mod configuration; +mod configuration_two; +mod directory; +// +use actix_files::NamedFile; +use actix_web::{web, App, HttpRequest, Result}; +use std::path::PathBuf; + +fn index(req: HttpRequest) -> Result { + let path: PathBuf = req.match_info().query("tail").parse().unwrap(); + Ok(NamedFile::open(path)?) +} + +fn main() { + App::new().route("/", web::get().to(index)); +} +// From 262f835485005b319027d3097a9d62bdcd4de34c Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Mon, 17 Jun 2019 18:07:57 -0400 Subject: [PATCH 28/68] Moves websocket example to crate. --- content/docs/websockets.md | 31 +------------------------------ examples/Cargo.toml | 1 + examples/websockets/Cargo.toml | 9 +++++++++ examples/websockets/src/main.rs | 29 +++++++++++++++++++++++++++++ 4 files changed, 40 insertions(+), 30 deletions(-) create mode 100644 examples/websockets/Cargo.toml create mode 100644 examples/websockets/src/main.rs diff --git a/content/docs/websockets.md b/content/docs/websockets.md index b284a36..c0335cd 100644 --- a/content/docs/websockets.md +++ b/content/docs/websockets.md @@ -12,36 +12,7 @@ with an http actor. The following is an example of a simple websocket echo server: -```rust -use actix::*; -use actix_web::*; - -/// Define http actor -struct Ws; - -impl Actor for Ws { - type Context = ws::WebsocketContext; -} - -/// Handler for ws::Message message -impl StreamHandler 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))) - .finish(); -} -``` +{{< include-example example="websockets" file="main.rs" section="websockets" >}} > A simple websocket echo server example is available in the > [examples directory](https://github.com/actix/examples/tree/master/websocket/). diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 981e7a6..72e0df5 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -23,4 +23,5 @@ exclude = [ "testing", "middleware", "static-files", + "websockets", ] diff --git a/examples/websockets/Cargo.toml b/examples/websockets/Cargo.toml new file mode 100644 index 0000000..a4f99be --- /dev/null +++ b/examples/websockets/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "websockets" +version = "0.1.0" +authors = ["Cameron Dershem "] +edition = "2018" + +[dependencies] +actix = "0.7" +actix-web = "1.0" diff --git a/examples/websockets/src/main.rs b/examples/websockets/src/main.rs new file mode 100644 index 0000000..6cec49d --- /dev/null +++ b/examples/websockets/src/main.rs @@ -0,0 +1,29 @@ +// +// use actix::*; +// use actix_web::*; + +// /// Define http actor +// struct Ws; + +// impl Actor for Ws { +// type Context = ws::WebsocketContext; +// } + +// /// Handler for ws::Message message +// impl StreamHandler 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))) +// .finish(); +// } +// From 5387f012695c53a05a5d04b7638ce2296499fd16 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Mon, 17 Jun 2019 18:31:10 -0400 Subject: [PATCH 29/68] First pass at Http2 section. --- content/docs/http2.md | 24 +++--------------------- examples/Cargo.toml | 1 + examples/http20/Cargo.toml | 9 +++++++++ examples/http20/src/main.rs | 21 +++++++++++++++++++++ 4 files changed, 34 insertions(+), 21 deletions(-) create mode 100644 examples/http20/Cargo.toml create mode 100644 examples/http20/src/main.rs diff --git a/content/docs/http2.md b/content/docs/http2.md index 85ab4a5..51951fb 100644 --- a/content/docs/http2.md +++ b/content/docs/http2.md @@ -14,32 +14,14 @@ weight: 250 > Currently, only `rust-openssl` has support. `alpn` negotiation requires enabling the feature. When enabled, `HttpServer` provides the -[serve_tls](../../actix-web/actix_web/server/struct.HttpServer.html#method.serve_tls) method. +[bind_ssl](../../actix-web/actix_web/server/struct.HttpServer.html#method.serve_tls) method. ```toml [dependencies] -actix-web = { version = "{{< actix-version "actix-web" >}}", features = ["alpn"] } +actix-web = { version = "{{< actix-version "actix-web" >}}", features = ["ssl"] } openssl = { version = "0.10", features = ["v110"] } ``` - -```rust -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(); -} -``` +{{< include-example example="http20" file="main.rs" section="main" >}} 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. diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 72e0df5..8abe786 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -24,4 +24,5 @@ exclude = [ "middleware", "static-files", "websockets", + "http20", ] diff --git a/examples/http20/Cargo.toml b/examples/http20/Cargo.toml new file mode 100644 index 0000000..2bf1dd4 --- /dev/null +++ b/examples/http20/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "http20" +version = "0.1.0" +authors = ["Cameron Dershem "] +edition = "2018" + +[dependencies] +actix-web = { version = "1.0", features = ["ssl"] } +openssl = { version = "0.10", features = ["v110"] } diff --git a/examples/http20/src/main.rs b/examples/http20/src/main.rs new file mode 100644 index 0000000..6395581 --- /dev/null +++ b/examples/http20/src/main.rs @@ -0,0 +1,21 @@ +//
+use actix_web::{web, App, HttpRequest, HttpServer, Responder}; +use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod}; + +fn index(_req: HttpRequest) -> impl Responder { + "Hello." +} + +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().route("/", web::get().to(index))) + .bind_ssl("127.0.0.1:8088", builder) + .unwrap(); +} +//
From 917156db2c9896917e007fa5095cb847c1a92522 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Mon, 17 Jun 2019 18:40:29 -0400 Subject: [PATCH 30/68] Removes author from Cargo.toml --- examples/autoreload/Cargo.toml | 1 - examples/extractors/Cargo.toml | 1 - examples/http20/Cargo.toml | 1 - examples/requests/Cargo.toml | 1 - examples/static-files/Cargo.toml | 1 - examples/testing/Cargo.toml | 1 - examples/websockets/Cargo.toml | 1 - 7 files changed, 7 deletions(-) diff --git a/examples/autoreload/Cargo.toml b/examples/autoreload/Cargo.toml index 95c9996..56839a5 100644 --- a/examples/autoreload/Cargo.toml +++ b/examples/autoreload/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "autoreload" version = "0.1.0" -authors = ["Cameron Dershem "] edition = "2018" [dependencies] diff --git a/examples/extractors/Cargo.toml b/examples/extractors/Cargo.toml index f135edb..fa3bd0d 100644 --- a/examples/extractors/Cargo.toml +++ b/examples/extractors/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "extractors" version = "0.1.0" -authors = ["Cameron Dershem "] edition = "2018" [dependencies] diff --git a/examples/http20/Cargo.toml b/examples/http20/Cargo.toml index 2bf1dd4..7796cce 100644 --- a/examples/http20/Cargo.toml +++ b/examples/http20/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "http20" version = "0.1.0" -authors = ["Cameron Dershem "] edition = "2018" [dependencies] diff --git a/examples/requests/Cargo.toml b/examples/requests/Cargo.toml index 49a8984..f197737 100644 --- a/examples/requests/Cargo.toml +++ b/examples/requests/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "requests" version = "0.1.0" -authors = ["Cameron Dershem "] edition = "2018" [dependencies] diff --git a/examples/static-files/Cargo.toml b/examples/static-files/Cargo.toml index 242abb0..57e5972 100644 --- a/examples/static-files/Cargo.toml +++ b/examples/static-files/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "static-files" version = "0.1.0" -authors = ["Cameron Dershem "] edition = "2018" [dependencies] diff --git a/examples/testing/Cargo.toml b/examples/testing/Cargo.toml index d9b43d6..a5660e8 100644 --- a/examples/testing/Cargo.toml +++ b/examples/testing/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "testing" version = "0.1.0" -authors = ["Cameron Dershem "] edition = "2018" [dependencies] diff --git a/examples/websockets/Cargo.toml b/examples/websockets/Cargo.toml index a4f99be..aba0dc4 100644 --- a/examples/websockets/Cargo.toml +++ b/examples/websockets/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "websockets" version = "0.1.0" -authors = ["Cameron Dershem "] edition = "2018" [dependencies] From 559f54d22bd60cd8e7a163a032a4c503719ff049 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Tue, 18 Jun 2019 02:21:24 -0400 Subject: [PATCH 31/68] First pass at databases. --- content/docs/databases.md | 96 ++---------------------------- examples/Cargo.toml | 2 + examples/og_databases/Cargo.toml | 7 +++ examples/og_databases/src/main.rs | 98 +++++++++++++++++++++++++++++++ 4 files changed, 112 insertions(+), 91 deletions(-) create mode 100644 examples/og_databases/Cargo.toml create mode 100644 examples/og_databases/src/main.rs diff --git a/content/docs/databases.md b/content/docs/databases.md index 63218fe..c4dcb11 100644 --- a/content/docs/databases.md +++ b/content/docs/databases.md @@ -16,114 +16,28 @@ Let's create a simple database api that can insert a new user row into a SQLite We must define a sync actor and a connection that this actor will use. The same approach can be used for other databases. -```rust -use actix::prelude::*; - -struct DbExecutor(SqliteConnection); - -impl Actor for DbExecutor { - type Context = SyncContext; -} -``` +{{< include-example example="databases" file="main.rs" section="actor" >}} This is the definition of our actor. Now, we must define the *create user* message and response. -```rust -struct CreateUser { - name: String, -} - -impl Message for CreateUser { - type Result = Result; -} -``` +{{< include-example example="og_databases" file="main.rs" section="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 -impl Handler for DbExecutor { - type Result = Result; - - 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::(&self.0) - .expect("Error loading person"); - - Ok(items.pop().unwrap()) - } -} -``` +{{< include-example example="og_databases" file="main.rs" section="handler" >}} 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 -/// This is state where we will store *DbExecutor* address. -struct State { - db: Addr, -} - -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(); -} -``` +{{< include-example example="og_databases" file="main.rs" section="main" >}} 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 -/// Async handler -fn index(req: &HttpRequest) -> Box> { - 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() -} -``` +{{< include-example example="og_databases" file="main.rs" section="index" >}} > A full example is available in the > [examples directory](https://github.com/actix/examples/tree/master/diesel/). diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 8abe786..d83abf1 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -25,4 +25,6 @@ exclude = [ "static-files", "websockets", "http20", + "databases", + "og_databases", ] diff --git a/examples/og_databases/Cargo.toml b/examples/og_databases/Cargo.toml new file mode 100644 index 0000000..1a53463 --- /dev/null +++ b/examples/og_databases/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "og_databases" +version = "0.1.0" +authors = ["Cameron Dershem "] +edition = "2018" + +[dependencies] diff --git a/examples/og_databases/src/main.rs b/examples/og_databases/src/main.rs new file mode 100644 index 0000000..c78d064 --- /dev/null +++ b/examples/og_databases/src/main.rs @@ -0,0 +1,98 @@ +// +// use actix::prelude::*; + +// struct DbExecutor(SqliteConnection); + +// impl Actor for DbExecutor { +// type Context = SyncContext; +// } +// + +// +// struct CreateUser { +// name: String, +// } + +// impl Message for CreateUser { +// type Result = Result; +// } +// + +// +// impl Handler for DbExecutor { +// type Result = Result; + +// 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::(&self.0) +// .expect("Error loading person"); + +// Ok(items.pop().unwrap()) +// } +// } +// + +//
+// /// This is state where we will store *DbExecutor* address. +// struct State { +// db: Addr, +// } + +// 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(); +// } +//
+ +// +// /// Async handler +// fn index(req: &HttpRequest) -> Box> { +// 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() +// } +// From 650c66b64a2dbdb982d99643ba005387efec4600 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Tue, 18 Jun 2019 02:25:55 -0400 Subject: [PATCH 32/68] Fixes typo in databases --- content/docs/databases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/databases.md b/content/docs/databases.md index c4dcb11..e7df061 100644 --- a/content/docs/databases.md +++ b/content/docs/databases.md @@ -16,7 +16,7 @@ Let's create a simple database api that can insert a new user row into a SQLite We must define a sync actor and a connection that this actor will use. The same approach can be used for other databases. -{{< include-example example="databases" file="main.rs" section="actor" >}} +{{< include-example example="og_databases" file="main.rs" section="actor" >}} This is the definition of our actor. Now, we must define the *create user* message and response. From 5ca7b6dc83c61d78eea0fc0ecf357b9f93a01029 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Tue, 18 Jun 2019 02:42:43 -0400 Subject: [PATCH 33/68] First pass at Sentry. --- content/docs/sentry.md | 37 +++---------------------------------- examples/Cargo.toml | 1 + examples/sentry/Cargo.toml | 10 ++++++++++ examples/sentry/src/main.rs | 36 ++++++++++++++++++++++++++++++++++++ 4 files changed, 50 insertions(+), 34 deletions(-) create mode 100644 examples/sentry/Cargo.toml create mode 100644 examples/sentry/src/main.rs diff --git a/content/docs/sentry.md b/content/docs/sentry.md index a93c2d4..99f4384 100644 --- a/content/docs/sentry.md +++ b/content/docs/sentry.md @@ -20,47 +20,16 @@ initialized and configured and the [sentry-actix middleware](https://crates.io/c needs to be added. Additionally it makes sense to also register the panic handler to be informed about hard panics. -```rust -extern crate sentry; -extern crate sentry_actix; - -use sentry_actix::SentryMiddleware; - -use std::env; - -fn main() { - sentry::init("SENTRY_DSN_GOES_HERE"); - env::set_var("RUST_BACKTRACE", "1"); - sentry::integrations::panic::register_panic_handler(); - - let mut app = App::with_state(state) - .middleware(SentryMiddleware::new()) - // ... -} -``` +{{< include-example example="sentry" file="main.rs" section="middleware" >}} # Reusing the Hub If you use this integration the default sentry hub (`Hub::current()`) is typically the wrong one. To get the request specific one you need to use the `ActixWebHubExt` trait: -```rust -use sentry::{Hub, Level}; -use sentry_actix::ActixWebHubExt; - -let hub = Hub::from_request(req); -hub.capture_message("Something is not well", Level::Warning); -``` +{{< include-example example="sentry" file="main.rs" section="hub" >}} The hub can also be made current for the duration of a call. Then `Hub::current()` works correctly until the end of the `run` block. -```rust -use sentry::{Hub, Level}; -use sentry_actix::ActixWebHubExt; - -let hub = Hub::from_request(req); -Hub::run(hub, || { - sentry::capture_message("Something is not well", Level::Warning); -}); -``` +{{< include-example example="sentry" file="main.rs" section="hub2" >}} diff --git a/examples/Cargo.toml b/examples/Cargo.toml index d83abf1..75fe191 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -27,4 +27,5 @@ exclude = [ "http20", "databases", "og_databases", + "sentry", ] diff --git a/examples/sentry/Cargo.toml b/examples/sentry/Cargo.toml new file mode 100644 index 0000000..0044be4 --- /dev/null +++ b/examples/sentry/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "sentry" +version = "0.1.0" +authors = ["Cameron Dershem "] +edition = "2018" + +[dependencies] +actix-web = "1.0" +sentry-actix = "0.15" +sentry = "0.15" diff --git a/examples/sentry/src/main.rs b/examples/sentry/src/main.rs new file mode 100644 index 0000000..9246394 --- /dev/null +++ b/examples/sentry/src/main.rs @@ -0,0 +1,36 @@ +// +// use actix_web::{web, App, HttpResponse}; +// use sentry; +// use sentry_actix::SentryMiddleware; + +// use std::env; + +// fn main() { +// sentry::init("SENTRY_DSN_GOES_HERE"); +// env::set_var("RUST_BACKTRACE", "1"); +// sentry::integrations::panic::register_panic_handler(); + +// let mut app = App::new() +// // .data(state) +// .wrap(SentryMiddleware::new()) +// .route("/", web::get().to(|| HttpResponse::Ok())); +// } +// + +// +// use sentry::{Hub, Level}; +// use sentry_actix::ActixWebHubExt; + +// let hub = Hub::from_request(req); +// hub.capture_message("Something is not well", Level::Warning); +// // + +// // +// use sentry::{Hub, Level}; +// use sentry_actix::ActixWebHubExt; + +// let hub = Hub::from_request(req); +// Hub::run(hub, || { +// sentry::capture_message("Something is not well", Level::Warning); +// }); +// From d762e83e74cd8dc103daa78b3f5d31a5abf590c8 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Tue, 18 Jun 2019 02:52:45 -0400 Subject: [PATCH 34/68] Comments out non working sentry code. --- examples/sentry/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/sentry/src/main.rs b/examples/sentry/src/main.rs index 9246394..a4de156 100644 --- a/examples/sentry/src/main.rs +++ b/examples/sentry/src/main.rs @@ -23,9 +23,9 @@ // let hub = Hub::from_request(req); // hub.capture_message("Something is not well", Level::Warning); -// // +// -// // +// // use sentry::{Hub, Level}; // use sentry_actix::ActixWebHubExt; From 471d21b61844b2b5a1d02d641ec21c1033b7ad0e Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Tue, 18 Jun 2019 16:44:43 -0400 Subject: [PATCH 35/68] updates Getting Started. --- content/docs/getting-started.md | 13 ++++++------- examples/getting-started/Cargo.toml | 1 + examples/getting-started/src/main.rs | 5 ++--- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/content/docs/getting-started.md b/content/docs/getting-started.md index e42bb29..042a1ac 100644 --- a/content/docs/getting-started.md +++ b/content/docs/getting-started.md @@ -27,18 +27,17 @@ actix-web = "{{< actix-version "actix-web" >}}" In order to implement a web server, we first need to create a request handler. -A request handler is a function that accepts an `HttpRequest` instance as its only parameter -and returns a type that can be converted into `HttpResponse`: - -Filename: `src/main.rs` +A request handler is a function that accepts any type that can be extracted from a +request (ie, `impl FromRequest`) as its only parameter and returns a type that +can be converted into an `HttpResponse` (ie, `impl Responder`): {{< include-example example="getting-started" section="setup" >}} -Next, create an `Application` instance and register the request handler with -the application's `resource` on a particular *HTTP method* and *path* and +Next, create an `App` instance and register the request handler with +the application's `route` on a particular *HTTP method* and *path* and after that, the application instance can be used with `HttpServer` to listen for incoming connections. The server accepts a function that should return an -`HttpResponse`. +application factory. {{< include-example example="getting-started" section="main" >}} diff --git a/examples/getting-started/Cargo.toml b/examples/getting-started/Cargo.toml index ee5e823..ad77af7 100644 --- a/examples/getting-started/Cargo.toml +++ b/examples/getting-started/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "getting-started" version = "0.7.0" +edition = "2018" workspace = "../" [dependencies] diff --git a/examples/getting-started/src/main.rs b/examples/getting-started/src/main.rs index f81f472..f3f4186 100644 --- a/examples/getting-started/src/main.rs +++ b/examples/getting-started/src/main.rs @@ -1,8 +1,7 @@ // -extern crate actix_web; -use actix_web::{web, App, HttpRequest, HttpResponse, HttpServer}; +use actix_web::{web, App, HttpRequest, HttpResponse, HttpServer, Responder}; -fn index(_req: HttpRequest) -> HttpResponse { +fn index(_req: HttpRequest) -> impl Responder { HttpResponse::Ok().body("Hello world!") } // From 303ec266925471f96c22c1ed28e17e84bf7bb2e5 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Tue, 18 Jun 2019 16:52:51 -0400 Subject: [PATCH 36/68] removes websocket and multipart mention. --- content/docs/application.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/docs/application.md b/content/docs/application.md index c77f3e6..177c615 100644 --- a/content/docs/application.md +++ b/content/docs/application.md @@ -7,8 +7,8 @@ weight: 140 # Writing an 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. +It provides routing, middlewares, pre-processing of requests, post-processing of +responses, etc. All actix web servers are built around the `App` instance. It is used for registering routes for resources and middlewares. It also stores application From 1e8cdcd324865373a528fbd23e8d63bf4ce02ef8 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Tue, 18 Jun 2019 17:13:54 -0400 Subject: [PATCH 37/68] Removes author from Cargo.toml --- examples/og_databases/Cargo.toml | 1 - examples/sentry/Cargo.toml | 1 - 2 files changed, 2 deletions(-) diff --git a/examples/og_databases/Cargo.toml b/examples/og_databases/Cargo.toml index 1a53463..01c4d82 100644 --- a/examples/og_databases/Cargo.toml +++ b/examples/og_databases/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "og_databases" version = "0.1.0" -authors = ["Cameron Dershem "] edition = "2018" [dependencies] diff --git a/examples/sentry/Cargo.toml b/examples/sentry/Cargo.toml index 0044be4..7b74660 100644 --- a/examples/sentry/Cargo.toml +++ b/examples/sentry/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "sentry" version = "0.1.0" -authors = ["Cameron Dershem "] edition = "2018" [dependencies] From e20f6d9d56c0e5a3ed35531e72989cfcce9cc5e8 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Tue, 18 Jun 2019 17:17:43 -0400 Subject: [PATCH 38/68] Updates http2 chapter after testing. --- content/docs/http2.md | 2 +- examples/Cargo.toml | 2 +- examples/{http20 => http2}/Cargo.toml | 2 +- examples/{http20 => http2}/src/main.rs | 4 ++++ 4 files changed, 7 insertions(+), 3 deletions(-) rename examples/{http20 => http2}/Cargo.toml (91%) rename examples/{http20 => http2}/src/main.rs (74%) diff --git a/content/docs/http2.md b/content/docs/http2.md index 51951fb..2d7dfe1 100644 --- a/content/docs/http2.md +++ b/content/docs/http2.md @@ -21,7 +21,7 @@ weight: 250 actix-web = { version = "{{< actix-version "actix-web" >}}", features = ["ssl"] } openssl = { version = "0.10", features = ["v110"] } ``` -{{< include-example example="http20" file="main.rs" section="main" >}} +{{< include-example example="http2" file="main.rs" section="main" >}} 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. diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 75fe191..e0cd8ca 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -24,7 +24,7 @@ exclude = [ "middleware", "static-files", "websockets", - "http20", + "http2", "databases", "og_databases", "sentry", diff --git a/examples/http20/Cargo.toml b/examples/http2/Cargo.toml similarity index 91% rename from examples/http20/Cargo.toml rename to examples/http2/Cargo.toml index 7796cce..9d376ce 100644 --- a/examples/http20/Cargo.toml +++ b/examples/http2/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "http20" +name = "http2" version = "0.1.0" edition = "2018" diff --git a/examples/http20/src/main.rs b/examples/http2/src/main.rs similarity index 74% rename from examples/http20/src/main.rs rename to examples/http2/src/main.rs index 6395581..a985211 100644 --- a/examples/http20/src/main.rs +++ b/examples/http2/src/main.rs @@ -8,6 +8,8 @@ fn index(_req: HttpRequest) -> impl Responder { fn main() { // load ssl keys + // to create a self-signed temporary cert for testing: + // `openssl req -x509 -newkey rsa:4096 -nodes -keyout key.pem -out cert.pem -days 365 -subj '/CN=localhost'` let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); builder .set_private_key_file("key.pem", SslFiletype::PEM) @@ -16,6 +18,8 @@ fn main() { HttpServer::new(|| App::new().route("/", web::get().to(index))) .bind_ssl("127.0.0.1:8088", builder) + .unwrap() + .run() .unwrap(); } // From d42c8ee4a20f5c6b85cf981a3c7cf98475514d3e Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Tue, 18 Jun 2019 17:29:54 -0400 Subject: [PATCH 39/68] Updated SSL section with notes to create certs. --- examples/server/src/ssl.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/server/src/ssl.rs b/examples/server/src/ssl.rs index 08f9ce1..4efb8de 100644 --- a/examples/server/src/ssl.rs +++ b/examples/server/src/ssl.rs @@ -8,6 +8,8 @@ fn index(_req: HttpRequest) -> impl Responder { pub fn main() { // load ssl keys + // to create a self-signed temporary cert for testing: + // `openssl req -x509 -newkey rsa:4096 -nodes -keyout key.pem -out cert.pem -days 365 -subj '/CN=localhost'` let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); builder From 0937cd8fdfa805baa07f72f8e5f47a38c94e69fc Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Tue, 18 Jun 2019 17:42:17 -0400 Subject: [PATCH 40/68] links to docs.rs instead of internal copy of api docs. --- layouts/docs/baseof.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/layouts/docs/baseof.html b/layouts/docs/baseof.html index fe301b3..626433b 100644 --- a/layouts/docs/baseof.html +++ b/layouts/docs/baseof.html @@ -79,7 +79,7 @@ From 96d8bec2a8a40f91f4fb1b40921c142bac43b9e5 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Tue, 18 Jun 2019 17:52:24 -0400 Subject: [PATCH 41/68] fixes missing Comma. --- examples/Cargo.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/Cargo.toml b/examples/Cargo.toml index e0cd8ca..52454ac 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -10,7 +10,7 @@ members = [ "server", "url-dispatch", "responder-trait", - "either" + "either", ] exclude = [ "request-handlers", @@ -25,7 +25,6 @@ exclude = [ "static-files", "websockets", "http2", - "databases", "og_databases", "sentry", ] From a3cb721ed36ea8df938493c103b760789e5eb1fe Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Tue, 18 Jun 2019 19:21:06 -0400 Subject: [PATCH 42/68] Removes websockets from feature rich mention. --- examples/application/Cargo.toml | 2 +- layouts/index.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/application/Cargo.toml b/examples/application/Cargo.toml index 62e6064..0316c80 100644 --- a/examples/application/Cargo.toml +++ b/examples/application/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "application" -version = "0.7.0" +version = "1.0.0" edition = "2018" workspace = "../" diff --git a/layouts/index.html b/layouts/index.html index e262e4d..9cf4c3a 100644 --- a/layouts/index.html +++ b/layouts/index.html @@ -22,7 +22,7 @@ Feature Rich -

Actix provides a lot of features out of box. WebSockets, HTTP/2, pipelining etc.

+

Actix provides a lot of features out of box. HTTP/2, logging, etc.

From 4f9bd8b72495dc8f85851ca5af87a404665a304f Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Wed, 19 Jun 2019 00:20:50 -0400 Subject: [PATCH 43/68] moves individual examples to pub mods to force building and have less dead_code --- content/docs/application.md | 9 ++- examples/Cargo.toml | 12 ++-- examples/application/src/app.rs | 11 ++++ examples/application/src/combine.rs | 25 +++++++++ examples/application/src/main.rs | 47 ++++++---------- examples/application/src/state.rs | 64 +++++----------------- examples/errors/src/helpers.rs | 6 +- examples/errors/src/main.rs | 15 +++-- examples/errors/src/override_error.rs | 17 +++++- examples/errors/src/recommend_one.rs | 10 ++++ examples/errors/src/recommend_two.rs | 6 +- examples/extractors/src/main.rs | 16 +++--- examples/extractors/src/path_two.rs | 2 +- examples/middleware/src/default_headers.rs | 2 +- examples/middleware/src/errorhandler.rs | 2 +- examples/middleware/src/logger.rs | 2 +- examples/middleware/src/main.rs | 8 +-- examples/middleware/src/user_sessions.rs | 2 +- examples/requests/src/json_two.rs | 2 +- examples/requests/src/main.rs | 10 ++-- examples/requests/src/manual.rs | 8 ++- examples/requests/src/multipart.rs | 2 +- examples/requests/src/streaming.rs | 2 +- examples/requests/src/urlencoded.rs | 2 +- examples/responses/src/auto.rs | 6 +- examples/responses/src/brotli.rs | 7 ++- examples/responses/src/chunked.rs | 2 +- examples/responses/src/identity.rs | 7 ++- examples/responses/src/identity_two.rs | 5 ++ examples/responses/src/json_resp.rs | 2 +- examples/responses/src/main.rs | 17 +++--- examples/server/src/keep_alive.rs | 2 +- examples/server/src/keep_alive_tp.rs | 2 +- examples/server/src/main.rs | 10 ++-- examples/static-files/src/directory.rs | 2 +- examples/static-files/src/main.rs | 6 +- examples/url-dispatch/src/dhandler.rs | 2 +- examples/url-dispatch/src/main.rs | 28 +++++----- examples/url-dispatch/src/minfo.rs | 4 +- examples/url-dispatch/src/norm.rs | 6 +- examples/url-dispatch/src/norm2.rs | 2 +- examples/url-dispatch/src/path.rs | 2 +- examples/url-dispatch/src/pbuf.rs | 2 +- examples/url-dispatch/src/pred.rs | 2 +- examples/url-dispatch/src/pred2.rs | 2 +- examples/url-dispatch/src/resource.rs | 4 +- examples/url-dispatch/src/scope.rs | 7 +-- examples/url-dispatch/src/url_ext.rs | 2 +- examples/url-dispatch/src/urls.rs | 4 +- 49 files changed, 226 insertions(+), 191 deletions(-) create mode 100644 examples/application/src/app.rs create mode 100644 examples/application/src/combine.rs diff --git a/content/docs/application.md b/content/docs/application.md index 177c615..68f2aad 100644 --- a/content/docs/application.md +++ b/content/docs/application.md @@ -23,7 +23,7 @@ The prefix should consist of value path segments. > any request with the paths `/app`, `/app/`, or `/app/test` would match; > however, the path `/application` would not match. -{{< include-example example="application" section="make_app" >}} +{{< include-example example="application" file="app.rs" section="setup" >}} 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. @@ -33,7 +33,7 @@ are created. This resource is available through the `/app/index.html` url. Multiple applications can be served with one server: -{{< include-example example="application" section="run_server" >}} +{{< include-example example="application" file="main.rs" section="run_server" >}} 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 @@ -61,8 +61,7 @@ When the app is initialized it needs to be passed the initial state: > instance. Http server constructs an application instance for each thread, thus application state > must be constructed multiple times. If you want to share state between different threads, a > shared object should be used, e.g. `Arc`. There is also an [Example](https://github.com/actix/examples/blob/master/state/src/main.rs) using `Arc` for this. Application state does not need to be `Send` and `Sync`, -> but the application factory must be `Send` + `Sync`. -> +> but the application factory must be `Send` + `Sync`. To start the previous app, create it into a closure: @@ -76,7 +75,7 @@ Combining multiple applications with different state is possible as well. This limitation can easily be overcome with the [App::boxed](https://docs.rs/actix-web/*/actix_web/struct.App.html#method.boxed) method, which converts an App into a boxed trait object. -{{< include-example example="application" file="state.rs" section="combine" >}} +{{< include-example example="application" file="combine.rs" section="combine" >}} ## Using an Application Scope to Compose Applications diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 52454ac..b5dc000 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -11,20 +11,20 @@ members = [ "url-dispatch", "responder-trait", "either", -] -exclude = [ - "request-handlers", - "async-handlers", "extractors", "autoreload", "errors", "requests", "responses", - "testing", "middleware", "static-files", - "websockets", "http2", +] +exclude = [ + "testing", + "async-handlers", + "websockets", + "request-handlers", "og_databases", "sentry", ] diff --git a/examples/application/src/app.rs b/examples/application/src/app.rs new file mode 100644 index 0000000..375c2a3 --- /dev/null +++ b/examples/application/src/app.rs @@ -0,0 +1,11 @@ +// +use actix_web::{web, App, HttpRequest, Responder}; + +fn index(_req: HttpRequest) -> impl Responder { + "Hello world!" +} + +pub fn main() { + App::new().service(web::scope("/app").route("/index.html", web::get().to(index))); +} +// diff --git a/examples/application/src/combine.rs b/examples/application/src/combine.rs new file mode 100644 index 0000000..1057f68 --- /dev/null +++ b/examples/application/src/combine.rs @@ -0,0 +1,25 @@ +use actix_web::{web, App, HttpResponse, HttpServer}; + +// +struct State1; +struct State2; + +#[rustfmt::skip] +pub fn main() { + HttpServer::new(|| { + App::new() + .data(State1) + .data(State2) + .service( + web::scope("/app1") + .route("/", web::to(|| HttpResponse::Ok()))) + .service( + web::scope("/app2") + .route("/", web::to(|| HttpResponse::Ok()))) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); +} +// diff --git a/examples/application/src/main.rs b/examples/application/src/main.rs index 172c57e..be51f1d 100644 --- a/examples/application/src/main.rs +++ b/examples/application/src/main.rs @@ -1,37 +1,22 @@ -#![allow(unused_variables)] -use actix_web::{web, App, HttpRequest, HttpResponse, HttpServer, Responder}; +use actix_web::{web, App, HttpResponse, HttpServer}; -mod state; -mod vh; +pub mod app; +pub mod combine; +pub mod state; +pub mod vh; #[rustfmt::skip] -fn make_app() { - -// -fn index(_req: HttpRequest) -> impl Responder { - "Hello world!" -} - -let app = App::new() - .service(web::scope("/app").route("/index.html", web::get().to(index))); -// - -} - -#[rustfmt::skip] -fn run_server() { // -let server = HttpServer::new(|| { - App::new() - .service(web::scope("/app1").route("/", web::to(|| HttpResponse::Ok()))) - .service(web::scope("/app2").route("/", web::to(|| HttpResponse::Ok()))) - .route("/", web::to(|| HttpResponse::Ok())) -}); -// -} - fn main() { - make_app(); - run_server(); - state::test(); + HttpServer::new(|| { + App::new() + .service( + web::scope("/app1") + .route("/", web::to(|| HttpResponse::Ok()))) + .service( + web::scope("/app2") + .route("/", web::to(|| HttpResponse::Ok()))) + .route("/", web::to(|| HttpResponse::Ok())) + }); } +// diff --git a/examples/application/src/state.rs b/examples/application/src/state.rs index 19fd96d..9944412 100644 --- a/examples/application/src/state.rs +++ b/examples/application/src/state.rs @@ -1,6 +1,5 @@ -#![allow(dead_code, unused)] // -use actix_web::{web, App, HttpRequest, HttpResponse, HttpServer}; +use actix_web::{web, App, HttpServer}; use std::cell::Cell; // This struct represents state @@ -16,63 +15,28 @@ fn index(data: web::Data) -> String { } // -#[rustfmt::skip] -fn make_app() { // -App::new() - .data( AppState { counter: Cell::new(0) }) - .route("/", web::get().to(index)); -// -} - -#[rustfmt::skip] -fn start_app() { -// -HttpServer::new(|| { +fn _main() { App::new() - .data( AppState { counter: Cell::new(0) }) - .route("/", web::get().to(index)) -}) -.bind("127.0.0.1:8088") -.unwrap() -.run() -.unwrap(); -// + .data(AppState { + counter: Cell::new(0), + }) + .route("/", web::get().to(index)); } +// -use std::thread; - -#[rustfmt::skip] -fn combine() { - thread::spawn(|| { -// -struct State1; -struct State2; - -fn main() { +// +pub fn main() { HttpServer::new(|| { App::new() - .data(State1) - .data(State2) - .service( - web::scope("/app1") - .route("/", web::to(|| HttpResponse::Ok())), - ) - .service( - web::scope("/app2") - .route("/", web::to(|| HttpResponse::Ok())), - ) + .data(AppState { + counter: Cell::new(0), + }) + .route("/", web::get().to(index)) }) .bind("127.0.0.1:8088") .unwrap() .run() .unwrap(); } -// - }); -} - -pub fn test() { - make_app(); - combine(); -} +// diff --git a/examples/errors/src/helpers.rs b/examples/errors/src/helpers.rs index 9fcd86a..bbdb0be 100644 --- a/examples/errors/src/helpers.rs +++ b/examples/errors/src/helpers.rs @@ -1,3 +1,4 @@ +use actix_web::{web, App}; // use actix_web::{error, HttpRequest, Result}; @@ -6,9 +7,12 @@ struct MyError { name: &'static str, } -fn index(req: &HttpRequest) -> Result<&'static str> { +pub 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.name))?) } // +pub fn main() { + App::new().route("/", web::get().to(index)); +} diff --git a/examples/errors/src/main.rs b/examples/errors/src/main.rs index 63e09b9..637cda4 100644 --- a/examples/errors/src/main.rs +++ b/examples/errors/src/main.rs @@ -1,21 +1,24 @@ -mod helpers; -mod override_error; -mod recommend_one; +pub mod helpers; +pub mod override_error; +pub mod recommend_one; +use actix_web::{web, App}; // use actix_web::{error, HttpRequest}; use failure::Fail; #[derive(Fail, Debug)] #[fail(display = "my error")] -struct MyError { +pub 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> { +fn index(_req: HttpRequest) -> Result<&'static str, MyError> { Err(MyError { name: "test" }) } // -fn main() {} +pub fn main() { + App::new().route("/", web::get().to(index)); +} diff --git a/examples/errors/src/override_error.rs b/examples/errors/src/override_error.rs index a5eaea3..98870ac 100644 --- a/examples/errors/src/override_error.rs +++ b/examples/errors/src/override_error.rs @@ -1,3 +1,4 @@ +use actix_web::{web, App}; // use actix_web::{error, http, HttpRequest, HttpResponse}; use failure::Fail; @@ -24,7 +25,21 @@ impl error::ResponseError for MyError { } } -fn index(req: &HttpRequest) -> Result<&'static str, MyError> { +fn index(_req: HttpRequest) -> Result<&'static str, MyError> { Err(MyError::BadClientData) } // +pub fn main() { + App::new() + .route("/", web::get().to(index)) + .route("/e2", web::get().to(error2)) + .route("/e3", web::get().to(error3)); +} + +fn error2(_req: HttpRequest) -> Result<&'static str, MyError> { + Err(MyError::InternalError) +} + +fn error3(_req: HttpRequest) -> Result<&'static str, MyError> { + Err(MyError::Timeout) +} diff --git a/examples/errors/src/recommend_one.rs b/examples/errors/src/recommend_one.rs index 51b6131..c88048e 100644 --- a/examples/errors/src/recommend_one.rs +++ b/examples/errors/src/recommend_one.rs @@ -1,3 +1,4 @@ +use actix_web::{web, App, HttpRequest}; // use actix_web::{error, http, HttpResponse}; use failure::Fail; @@ -18,3 +19,12 @@ impl error::ResponseError for UserError { } } // +pub fn main() { + App::new().route("/", web::get().to(index)); +} + +fn index(_req: HttpRequest) -> Result<&'static str, UserError> { + Err(UserError::ValidationError { + field: "bad stuff".to_string(), + }) +} diff --git a/examples/errors/src/recommend_two.rs b/examples/errors/src/recommend_two.rs index 80e5f1f..e587d32 100644 --- a/examples/errors/src/recommend_two.rs +++ b/examples/errors/src/recommend_two.rs @@ -1,5 +1,6 @@ +use actix_web::App; // -use actix_web::{error, fs, http, App, HttpRequest, HttpResponse}; +use actix_web::{error, fs, http, HttpRequest, HttpResponse}; use failure::Fail; #[derive(Fail, Debug)] @@ -23,3 +24,6 @@ fn index(_req: HttpRequest) -> Result<&'static str, UserError> { Ok("success!") } // +pub fn main() { + App::new().route("/", web::get().to(index)); +} diff --git a/examples/extractors/src/main.rs b/examples/extractors/src/main.rs index 917f532..276b1b6 100644 --- a/examples/extractors/src/main.rs +++ b/examples/extractors/src/main.rs @@ -2,14 +2,14 @@ use actix_web::{web, App, FromRequest, HttpRequest, HttpServer, Responder}; use futures::future::Future; use serde::Deserialize; -// mod custom_handler; -mod form; -mod json_one; -mod json_two; -mod multiple; -mod path_one; -mod path_two; -mod query; +// pub mod custom_handler; +pub mod form; +pub mod json_one; +pub mod json_two; +pub mod multiple; +pub mod path_one; +pub mod path_two; +pub mod query; #[derive(Deserialize, Debug)] struct MyInfo { diff --git a/examples/extractors/src/path_two.rs b/examples/extractors/src/path_two.rs index 7919173..7c5a4c3 100644 --- a/examples/extractors/src/path_two.rs +++ b/examples/extractors/src/path_two.rs @@ -10,7 +10,7 @@ struct Info { /// extract path info using serde fn index(info: web::Path) -> Result { - Ok(format!("Welcome {}!", info.friend)) + Ok(format!("Welcome {}, userid {}!", info.friend, info.userid)) } pub fn main() { diff --git a/examples/middleware/src/default_headers.rs b/examples/middleware/src/default_headers.rs index a81e7a1..cf14468 100644 --- a/examples/middleware/src/default_headers.rs +++ b/examples/middleware/src/default_headers.rs @@ -1,7 +1,7 @@ // use actix_web::{http, middleware, web, App, HttpResponse}; -fn main() { +pub fn main() { App::new() .wrap(middleware::DefaultHeaders::new().header("X-Version", "0.2")) .service( diff --git a/examples/middleware/src/errorhandler.rs b/examples/middleware/src/errorhandler.rs index dd3b440..6d33db5 100644 --- a/examples/middleware/src/errorhandler.rs +++ b/examples/middleware/src/errorhandler.rs @@ -10,7 +10,7 @@ fn render_500(mut res: dev::ServiceResponse) -> Result use actix_service::{Service, Transform}; use actix_web::{dev::ServiceRequest, dev::ServiceResponse, web, App, Error}; diff --git a/examples/middleware/src/user_sessions.rs b/examples/middleware/src/user_sessions.rs index 42fafff..d51c740 100644 --- a/examples/middleware/src/user_sessions.rs +++ b/examples/middleware/src/user_sessions.rs @@ -19,7 +19,7 @@ fn index(session: Session, req: HttpRequest) -> Result<&'static str> { Ok("welcome!") } -fn main() -> std::io::Result<()> { +pub fn main() -> std::io::Result<()> { std::env::set_var("RUST_LOG", "actix_web=info"); env_logger::init(); diff --git a/examples/requests/src/json_two.rs b/examples/requests/src/json_two.rs index 659bd96..5c0bfa8 100644 --- a/examples/requests/src/json_two.rs +++ b/examples/requests/src/json_two.rs @@ -9,7 +9,7 @@ // number: i32, // } -// fn index(req: HttpRequest) -> Box> { +// pub fn index(req: HttpRequest) -> Box> { // req.json() // .from_err() // .and_then(|val: MyObj| { diff --git a/examples/requests/src/main.rs b/examples/requests/src/main.rs index 9b3ad62..b44e0bd 100644 --- a/examples/requests/src/main.rs +++ b/examples/requests/src/main.rs @@ -1,8 +1,8 @@ -mod json_two; -mod manual; -mod multipart; -mod streaming; -mod urlencoded; +pub mod json_two; +pub mod manual; +pub mod multipart; +pub mod streaming; +pub mod urlencoded; // use actix_web::{web, App, Result}; use serde::Deserialize; diff --git a/examples/requests/src/manual.rs b/examples/requests/src/manual.rs index 846f704..a850b0e 100644 --- a/examples/requests/src/manual.rs +++ b/examples/requests/src/manual.rs @@ -1,5 +1,5 @@ // -use actix_web::{error, web, Error, HttpResponse}; +use actix_web::{error, web, App, Error, HttpResponse}; use bytes::BytesMut; use futures::{Future, Stream}; use serde::{Deserialize, Serialize}; @@ -13,7 +13,7 @@ struct MyObj { const MAX_SIZE: usize = 262_144; // max payload size is 256k -fn index_manual( +pub fn index_manual( payload: web::Payload, ) -> impl Future { // payload is a stream of Bytes objects @@ -41,3 +41,7 @@ fn index_manual( }) } // + +pub fn main() { + App::new().route("/", web::post().to_async(index_manual)); +} diff --git a/examples/requests/src/multipart.rs b/examples/requests/src/multipart.rs index 0fa74d9..94199a1 100644 --- a/examples/requests/src/multipart.rs +++ b/examples/requests/src/multipart.rs @@ -2,7 +2,7 @@ // use actix_web::{error, Error, HttpRequest, HttpResponse}; // use futures::Future; -// fn index(req: HttpRequest) -> Box> { +// pub fn index(req: HttpRequest) -> Box> { // // get multipart and iterate over multipart items // req.multipart().and_then(|item| match item { // multipart::MultipartItem::Field(field) => { diff --git a/examples/requests/src/streaming.rs b/examples/requests/src/streaming.rs index 191d32a..6444171 100644 --- a/examples/requests/src/streaming.rs +++ b/examples/requests/src/streaming.rs @@ -2,7 +2,7 @@ // use actix_web::{error, web, Error, HttpResponse}; // use futures::{future::result, Future, Stream}; -// fn index(payload: web::Payload) -> Box> { +// pub fn index(payload: web::Payload) -> Box> { // payload // .from_err() // .fold((), |_, chunk| { diff --git a/examples/requests/src/urlencoded.rs b/examples/requests/src/urlencoded.rs index 5439d0d..5e64efb 100644 --- a/examples/requests/src/urlencoded.rs +++ b/examples/requests/src/urlencoded.rs @@ -19,4 +19,4 @@ // .responder() // } // -fn main() {} +pub fn main() {} diff --git a/examples/responses/src/auto.rs b/examples/responses/src/auto.rs index 598513a..d4b2cb7 100644 --- a/examples/responses/src/auto.rs +++ b/examples/responses/src/auto.rs @@ -3,12 +3,12 @@ use actix_web::{ http::ContentEncoding, middleware, web, App, HttpRequest, HttpResponse, }; -fn index(req: HttpRequest) -> HttpResponse { +fn index(_req: HttpRequest) -> HttpResponse { HttpResponse::Ok().body("data") } -fn main() { - let app = App::new() +pub fn main() { + App::new() // v- disable compression for all routes .wrap(middleware::Compress::new(ContentEncoding::Identity)) .route("/", web::get().to(index)); diff --git a/examples/responses/src/brotli.rs b/examples/responses/src/brotli.rs index e107ad7..79717ff 100644 --- a/examples/responses/src/brotli.rs +++ b/examples/responses/src/brotli.rs @@ -3,11 +3,14 @@ use actix_web::{ http::ContentEncoding, middleware::BodyEncoding, HttpRequest, HttpResponse, }; -fn index_br(req: HttpRequest) -> HttpResponse { +fn index_br(_req: HttpRequest) -> HttpResponse { HttpResponse::Ok() .encoding(ContentEncoding::Br) .body("data") } // -fn main() {} +use actix_web::{web, App}; +pub fn main() { + App::new().route("/", web::get().to(index_br)); +} diff --git a/examples/responses/src/chunked.rs b/examples/responses/src/chunked.rs index 0cd6d76..a2c4a62 100644 --- a/examples/responses/src/chunked.rs +++ b/examples/responses/src/chunked.rs @@ -11,4 +11,4 @@ // )))))) // } // -fn main() {} +pub fn main() {} diff --git a/examples/responses/src/identity.rs b/examples/responses/src/identity.rs index 89bd52e..039d713 100644 --- a/examples/responses/src/identity.rs +++ b/examples/responses/src/identity.rs @@ -3,10 +3,15 @@ use actix_web::{ http::ContentEncoding, middleware::BodyEncoding, HttpRequest, HttpResponse, }; -fn index(req: HttpRequest) -> HttpResponse { +fn index(_req: HttpRequest) -> HttpResponse { HttpResponse::Ok() // v- disable compression .encoding(ContentEncoding::Identity) .body("data") } // + +use actix_web::{web, App}; +pub fn main() { + App::new().route("/", web::get().to(index)); +} diff --git a/examples/responses/src/identity_two.rs b/examples/responses/src/identity_two.rs index 63371fa..0ac8f65 100644 --- a/examples/responses/src/identity_two.rs +++ b/examples/responses/src/identity_two.rs @@ -16,3 +16,8 @@ pub fn index(_req: HttpRequest) -> HttpResponse { .body(HELLO_WORLD) } // + +use actix_web::{web, App}; +pub fn main() { + App::new().route("/", web::get().to(index)); +} diff --git a/examples/responses/src/json_resp.rs b/examples/responses/src/json_resp.rs index c2344c0..96d9591 100644 --- a/examples/responses/src/json_resp.rs +++ b/examples/responses/src/json_resp.rs @@ -13,7 +13,7 @@ fn index(req: HttpRequest) -> Result> { })) } -fn main() { +pub fn main() { App::new().route(r"/a/{name}", web::get().to(index)); } // diff --git a/examples/responses/src/main.rs b/examples/responses/src/main.rs index 4c9f209..943612e 100644 --- a/examples/responses/src/main.rs +++ b/examples/responses/src/main.rs @@ -1,9 +1,9 @@ -mod auto; -mod brotli; -mod chunked; -mod identity; -mod identity_two; -mod json_resp; +pub mod auto; +pub mod brotli; +pub mod chunked; +pub mod identity; +pub mod identity_two; +pub mod json_resp; // use actix_web::{ http::ContentEncoding, middleware::BodyEncoding, HttpRequest, HttpResponse, @@ -18,4 +18,7 @@ fn index(_req: HttpRequest) -> HttpResponse { } // -fn main() {} +use actix_web::{web, App}; +pub fn main() { + App::new().route("/", web::get().to(index)); +} diff --git a/examples/server/src/keep_alive.rs b/examples/server/src/keep_alive.rs index b078961..86aa88f 100644 --- a/examples/server/src/keep_alive.rs +++ b/examples/server/src/keep_alive.rs @@ -1,7 +1,7 @@ // use actix_web::{web, App, HttpResponse, HttpServer}; -fn main() { +pub fn main() { HttpServer::new(|| { App::new().route("/", web::get().to(|| HttpResponse::Ok())) }) diff --git a/examples/server/src/keep_alive_tp.rs b/examples/server/src/keep_alive_tp.rs index aac81cc..252c53c 100644 --- a/examples/server/src/keep_alive_tp.rs +++ b/examples/server/src/keep_alive_tp.rs @@ -1,7 +1,7 @@ // use actix_web::{http, HttpRequest, HttpResponse}; -fn index(req: HttpRequest) -> HttpResponse { +pub fn index(req: HttpRequest) -> HttpResponse { HttpResponse::Ok() .connection_type(http::ConnectionType::Close) // <- Close connection .force_close() // <- Alternative method diff --git a/examples/server/src/main.rs b/examples/server/src/main.rs index 95995d7..735f613 100644 --- a/examples/server/src/main.rs +++ b/examples/server/src/main.rs @@ -1,8 +1,8 @@ -// mod keep_alive; -// mod keep_alive_tp; -mod signals; -mod ssl; -mod workers; +// pub mod keep_alive; +// pub mod keep_alive_tp; +pub mod signals; +pub mod ssl; +pub mod workers; //
use actix_web::{web, App, HttpResponse, HttpServer}; diff --git a/examples/static-files/src/directory.rs b/examples/static-files/src/directory.rs index b547650..3fcbbe4 100644 --- a/examples/static-files/src/directory.rs +++ b/examples/static-files/src/directory.rs @@ -2,7 +2,7 @@ use actix_files as fs; use actix_web::App; -fn main() { +pub fn main() { App::new().service(fs::Files::new("/static", ".").show_files_listing()); } // diff --git a/examples/static-files/src/main.rs b/examples/static-files/src/main.rs index 4d1840a..907afff 100644 --- a/examples/static-files/src/main.rs +++ b/examples/static-files/src/main.rs @@ -1,6 +1,6 @@ -mod configuration; -mod configuration_two; -mod directory; +pub mod configuration; +pub mod configuration_two; +pub mod directory; // use actix_files::NamedFile; use actix_web::{web, App, HttpRequest, Result}; diff --git a/examples/url-dispatch/src/dhandler.rs b/examples/url-dispatch/src/dhandler.rs index 46a9a75..cb7a3db 100644 --- a/examples/url-dispatch/src/dhandler.rs +++ b/examples/url-dispatch/src/dhandler.rs @@ -5,7 +5,7 @@ fn index(_req: HttpRequest) -> impl Responder { } // -fn main() { +pub fn main() { App::new() .service(web::resource("/").route(web::get().to(index))) .default_service( diff --git a/examples/url-dispatch/src/main.rs b/examples/url-dispatch/src/main.rs index c2e4ae0..bea247a 100644 --- a/examples/url-dispatch/src/main.rs +++ b/examples/url-dispatch/src/main.rs @@ -1,17 +1,17 @@ -mod cfg; -mod dhandler; -mod minfo; -mod norm; -mod norm2; -mod path; -mod path2; -mod pbuf; -mod pred; -mod pred2; -mod resource; -mod scope; -mod url_ext; -mod urls; +pub mod cfg; +pub mod dhandler; +pub mod minfo; +pub mod norm; +pub mod norm2; +pub mod path; +pub mod path2; +pub mod pbuf; +pub mod pred; +pub mod pred2; +pub mod resource; +pub mod scope; +pub mod url_ext; +pub mod urls; //
use actix_web::{web, App, HttpRequest, HttpResponse}; diff --git a/examples/url-dispatch/src/minfo.rs b/examples/url-dispatch/src/minfo.rs index 3ce4a6c..2222945 100644 --- a/examples/url-dispatch/src/minfo.rs +++ b/examples/url-dispatch/src/minfo.rs @@ -1,5 +1,5 @@ // -use actix_web::{web, App, HttpRequest, HttpServer, Result}; +use actix_web::{web, App, HttpRequest, Result}; fn index(req: HttpRequest) -> Result { let v1: u8 = req.match_info().get("v1").unwrap().parse().unwrap(); @@ -8,7 +8,7 @@ fn index(req: HttpRequest) -> Result { Ok(format!("Values {} {} {} {}", v1, v2, v3, v4)) } -fn main() { +pub fn main() { App::new() .route("/a/{v1}/{v2}/", web::get().to(index)) .route("", web::get().to(|| actix_web::HttpResponse::Ok())); diff --git a/examples/url-dispatch/src/norm.rs b/examples/url-dispatch/src/norm.rs index a1c8d4a..d396da4 100644 --- a/examples/url-dispatch/src/norm.rs +++ b/examples/url-dispatch/src/norm.rs @@ -1,10 +1,10 @@ // -use actix_web::{middleware, web, App, HttpResponse}; +use actix_web::{middleware, web, App}; -fn main() { +pub fn main() { App::new() .wrap(middleware::NormalizePath) - .route("/", web::get().to(|| HttpResponse::Ok())); + .route("/", web::get().to(index)); } // diff --git a/examples/url-dispatch/src/norm2.rs b/examples/url-dispatch/src/norm2.rs index cadfd35..1efc527 100644 --- a/examples/url-dispatch/src/norm2.rs +++ b/examples/url-dispatch/src/norm2.rs @@ -1,7 +1,7 @@ // use actix_web::{http::Method, middleware, web, App}; -fn main() { +pub fn main() { App::new() .wrap(middleware::NormalizePath) .route("/resource/", web::get().to(index)) diff --git a/examples/url-dispatch/src/path.rs b/examples/url-dispatch/src/path.rs index bc726c4..f3aea1a 100644 --- a/examples/url-dispatch/src/path.rs +++ b/examples/url-dispatch/src/path.rs @@ -6,7 +6,7 @@ fn index(info: web::Path<(String, u32)>) -> Result { Ok(format!("Welcome {}! id: {}", info.0, info.1)) } -fn main() { +pub fn main() { App::new().route( "/{username}/{id}/index.html", // <- define path parameters web::get().to(index), diff --git a/examples/url-dispatch/src/pbuf.rs b/examples/url-dispatch/src/pbuf.rs index 855d2e9..4ca0102 100644 --- a/examples/url-dispatch/src/pbuf.rs +++ b/examples/url-dispatch/src/pbuf.rs @@ -7,7 +7,7 @@ fn index(req: HttpRequest) -> Result { Ok(format!("Path {:?}", path)) } -fn main() { +pub fn main() { App::new().route(r"/a/{tail:.*}", web::get().to(index)); } // diff --git a/examples/url-dispatch/src/pred.rs b/examples/url-dispatch/src/pred.rs index 8c75a2c..2617fa2 100644 --- a/examples/url-dispatch/src/pred.rs +++ b/examples/url-dispatch/src/pred.rs @@ -9,7 +9,7 @@ impl Guard for ContentTypeHeader { } } -fn main() { +pub fn main() { App::new().route( "", web::route() diff --git a/examples/url-dispatch/src/pred2.rs b/examples/url-dispatch/src/pred2.rs index e56d6c2..68d13d7 100644 --- a/examples/url-dispatch/src/pred2.rs +++ b/examples/url-dispatch/src/pred2.rs @@ -1,7 +1,7 @@ // use actix_web::{guard, web, App, HttpResponse}; -fn main() { +pub fn main() { App::new().route( "/", web::route() diff --git a/examples/url-dispatch/src/resource.rs b/examples/url-dispatch/src/resource.rs index f2d98db..a231856 100644 --- a/examples/url-dispatch/src/resource.rs +++ b/examples/url-dispatch/src/resource.rs @@ -1,11 +1,11 @@ // -use actix_web::{http::Method, web, App, HttpRequest, HttpResponse}; +use actix_web::{web, App, HttpRequest, HttpResponse}; fn index(_req: HttpRequest) -> HttpResponse { unimplemented!() } -fn main() { +pub fn main() { App::new() .service(web::resource("/prefix").to(index)) .service( diff --git a/examples/url-dispatch/src/scope.rs b/examples/url-dispatch/src/scope.rs index 5bd4906..01795ef 100644 --- a/examples/url-dispatch/src/scope.rs +++ b/examples/url-dispatch/src/scope.rs @@ -5,10 +5,7 @@ fn show_users(_req: HttpRequest) -> HttpResponse { unimplemented!() } -#[rustfmt::skip] -fn main() { - App::new() - .service(web::scope("/users") - .route("/show", web::get().to(show_users))); +pub fn main() { + App::new().service(web::scope("/users").route("/show", web::get().to(show_users))); } // diff --git a/examples/url-dispatch/src/url_ext.rs b/examples/url-dispatch/src/url_ext.rs index eaa2503..8f1869c 100644 --- a/examples/url-dispatch/src/url_ext.rs +++ b/examples/url-dispatch/src/url_ext.rs @@ -1,5 +1,5 @@ // -use actix_web::{web, App, Error, HttpRequest, HttpResponse, Responder}; +use actix_web::{web, App, HttpRequest, Responder}; fn index(req: HttpRequest) -> impl Responder { let url = req.url_for("youtube", &["oHg5SJYRHA0"]).unwrap(); diff --git a/examples/url-dispatch/src/urls.rs b/examples/url-dispatch/src/urls.rs index e1ab4dc..0ad653a 100644 --- a/examples/url-dispatch/src/urls.rs +++ b/examples/url-dispatch/src/urls.rs @@ -1,7 +1,5 @@ // -use actix_web::{ - guard, http::header, http::Method, web, App, HttpRequest, HttpResponse, Result, -}; +use actix_web::{guard, http::header, web, App, HttpRequest, HttpResponse, Result}; fn index(req: HttpRequest) -> Result { let url = req.url_for("foo", &["1", "2", "3"])?; // <- generate url for "foo" resource From 941bdfa491ee411265eb311c5bcd97ca024097b1 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Wed, 19 Jun 2019 00:38:23 -0400 Subject: [PATCH 44/68] Updates example version numbers to match actix-web version. --- examples/async-handlers/Cargo.toml | 2 +- examples/autoreload/Cargo.toml | 2 +- examples/easy-form-handling/Cargo.toml | 2 +- examples/either/Cargo.toml | 2 +- examples/errors/Cargo.toml | 2 +- examples/extractors/Cargo.toml | 2 +- examples/flexible-responders/Cargo.toml | 2 +- examples/getting-started/Cargo.toml | 2 +- examples/http2/Cargo.toml | 2 +- examples/main-example/Cargo.toml | 2 +- examples/middleware/Cargo.toml | 2 +- examples/og_databases/Cargo.toml | 3 ++- examples/powerful-extractors/Cargo.toml | 2 +- examples/request-handlers/Cargo.toml | 2 +- examples/request-routing/Cargo.toml | 2 +- examples/requests/Cargo.toml | 2 +- examples/responder-trait/Cargo.toml | 2 +- examples/responses/Cargo.toml | 2 +- examples/sentry/Cargo.toml | 4 ++-- examples/server/Cargo.toml | 2 +- examples/static-files/Cargo.toml | 2 +- examples/testing/Cargo.toml | 2 +- examples/url-dispatch/Cargo.toml | 2 +- examples/websockets/Cargo.toml | 2 +- 24 files changed, 26 insertions(+), 25 deletions(-) diff --git a/examples/async-handlers/Cargo.toml b/examples/async-handlers/Cargo.toml index fef635a..9a9e413 100644 --- a/examples/async-handlers/Cargo.toml +++ b/examples/async-handlers/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "async-handlers" -version = "0.1.0" +version = "0.7.0" edition = "2018" [dependencies] diff --git a/examples/autoreload/Cargo.toml b/examples/autoreload/Cargo.toml index 56839a5..55b4b62 100644 --- a/examples/autoreload/Cargo.toml +++ b/examples/autoreload/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "autoreload" -version = "0.1.0" +version = "1.0.0" edition = "2018" [dependencies] diff --git a/examples/easy-form-handling/Cargo.toml b/examples/easy-form-handling/Cargo.toml index 07f6a66..bbf8d22 100644 --- a/examples/easy-form-handling/Cargo.toml +++ b/examples/easy-form-handling/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "easy-form-handling" -version = "0.1.0" +version = "1.0.0" edition = "2018" [dependencies] diff --git a/examples/either/Cargo.toml b/examples/either/Cargo.toml index dfaf7bc..9f8a8f8 100644 --- a/examples/either/Cargo.toml +++ b/examples/either/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "either" -version = "0.1.0" +version = "1.0.0" edition = "2018" [dependencies] diff --git a/examples/errors/Cargo.toml b/examples/errors/Cargo.toml index 1314e8f..cb2e9c0 100644 --- a/examples/errors/Cargo.toml +++ b/examples/errors/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "errors" -version = "0.1.0" +version = "1.0.0" edition = "2018" [dependencies] diff --git a/examples/extractors/Cargo.toml b/examples/extractors/Cargo.toml index fa3bd0d..0e31c27 100644 --- a/examples/extractors/Cargo.toml +++ b/examples/extractors/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "extractors" -version = "0.1.0" +version = "1.0.0" edition = "2018" [dependencies] diff --git a/examples/flexible-responders/Cargo.toml b/examples/flexible-responders/Cargo.toml index ec19e5d..5aec859 100644 --- a/examples/flexible-responders/Cargo.toml +++ b/examples/flexible-responders/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "flexible-responders" -version = "0.1.0" +version = "1.0.0" edition = "2018" [dependencies] diff --git a/examples/getting-started/Cargo.toml b/examples/getting-started/Cargo.toml index ad77af7..1632b62 100644 --- a/examples/getting-started/Cargo.toml +++ b/examples/getting-started/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "getting-started" -version = "0.7.0" +version = "1.0.0" edition = "2018" workspace = "../" diff --git a/examples/http2/Cargo.toml b/examples/http2/Cargo.toml index 9d376ce..5749e20 100644 --- a/examples/http2/Cargo.toml +++ b/examples/http2/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "http2" -version = "0.1.0" +version = "1.0.0" edition = "2018" [dependencies] diff --git a/examples/main-example/Cargo.toml b/examples/main-example/Cargo.toml index b48e677..03e0327 100644 --- a/examples/main-example/Cargo.toml +++ b/examples/main-example/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "main-example" -version = "0.1.0" +version = "1.0.0" edition = "2018" [dependencies] diff --git a/examples/middleware/Cargo.toml b/examples/middleware/Cargo.toml index dceb867..3448545 100644 --- a/examples/middleware/Cargo.toml +++ b/examples/middleware/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "middleware" -version = "0.1.0" +version = "1.0.0" edition = "2018" [dependencies] diff --git a/examples/og_databases/Cargo.toml b/examples/og_databases/Cargo.toml index 01c4d82..cdf2ee3 100644 --- a/examples/og_databases/Cargo.toml +++ b/examples/og_databases/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "og_databases" -version = "0.1.0" +version = "0.7.0" edition = "2018" [dependencies] +actix-web = "0.7" diff --git a/examples/powerful-extractors/Cargo.toml b/examples/powerful-extractors/Cargo.toml index 50fe15e..5f20144 100644 --- a/examples/powerful-extractors/Cargo.toml +++ b/examples/powerful-extractors/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "powerful-extractors" -version = "0.1.0" +version = "1.0.0" edition = "2018" [dependencies] diff --git a/examples/request-handlers/Cargo.toml b/examples/request-handlers/Cargo.toml index 1fb4d7d..da4764a 100644 --- a/examples/request-handlers/Cargo.toml +++ b/examples/request-handlers/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "request-handlers" -version = "0.1.0" +version = "0.7.0" edition = "2018" [dependencies] diff --git a/examples/request-routing/Cargo.toml b/examples/request-routing/Cargo.toml index 126c337..cdef3e6 100644 --- a/examples/request-routing/Cargo.toml +++ b/examples/request-routing/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "request-routing" -version = "0.1.0" +version = "1.0.0" edition = "2018" [dependencies] diff --git a/examples/requests/Cargo.toml b/examples/requests/Cargo.toml index f197737..cc4ba8d 100644 --- a/examples/requests/Cargo.toml +++ b/examples/requests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "requests" -version = "0.1.0" +version = "1.0.0" edition = "2018" [dependencies] diff --git a/examples/responder-trait/Cargo.toml b/examples/responder-trait/Cargo.toml index 1b921cc..565cd46 100644 --- a/examples/responder-trait/Cargo.toml +++ b/examples/responder-trait/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "responder-trait" -version = "0.1.0" +version = "1.0.0" edition = "2018" [dependencies] diff --git a/examples/responses/Cargo.toml b/examples/responses/Cargo.toml index 53b9236..8d5624f 100644 --- a/examples/responses/Cargo.toml +++ b/examples/responses/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "responses" -version = "0.1.0" +version = "1.0.0" edition = "2018" [dependencies] diff --git a/examples/sentry/Cargo.toml b/examples/sentry/Cargo.toml index 7b74660..0c3503b 100644 --- a/examples/sentry/Cargo.toml +++ b/examples/sentry/Cargo.toml @@ -1,9 +1,9 @@ [package] name = "sentry" -version = "0.1.0" +version = "0.7.0" edition = "2018" [dependencies] -actix-web = "1.0" +actix-web = "0.7" sentry-actix = "0.15" sentry = "0.15" diff --git a/examples/server/Cargo.toml b/examples/server/Cargo.toml index d90d6fe..95e9a7c 100644 --- a/examples/server/Cargo.toml +++ b/examples/server/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "server" -version = "0.7.0" +version = "1.0.0" workspace = "../" edition = "2018" diff --git a/examples/static-files/Cargo.toml b/examples/static-files/Cargo.toml index 57e5972..8018328 100644 --- a/examples/static-files/Cargo.toml +++ b/examples/static-files/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "static-files" -version = "0.1.0" +version = "1.0.0" edition = "2018" [dependencies] diff --git a/examples/testing/Cargo.toml b/examples/testing/Cargo.toml index a5660e8..15532db 100644 --- a/examples/testing/Cargo.toml +++ b/examples/testing/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "testing" -version = "0.1.0" +version = "1.0.0" edition = "2018" [dependencies] diff --git a/examples/url-dispatch/Cargo.toml b/examples/url-dispatch/Cargo.toml index 7cabeff..761a7b6 100644 --- a/examples/url-dispatch/Cargo.toml +++ b/examples/url-dispatch/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "url-dispatch" -version = "0.7.0" +version = "1.0.0" edition = "2018" workspace = "../" diff --git a/examples/websockets/Cargo.toml b/examples/websockets/Cargo.toml index aba0dc4..fca0541 100644 --- a/examples/websockets/Cargo.toml +++ b/examples/websockets/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "websockets" -version = "0.1.0" +version = "0.7.0" edition = "2018" [dependencies] From 2011f100a51c175e5accd97deb822a1343d2b4c7 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Wed, 19 Jun 2019 14:53:45 -0400 Subject: [PATCH 45/68] makes intro accurate about acitx-web. --- content/docs/_index.md | 6 +++--- content/docs/installation.md | 2 +- content/docs/whatis.md | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/content/docs/_index.md b/content/docs/_index.md index 87d1e87..a8622d4 100644 --- a/content/docs/_index.md +++ b/content/docs/_index.md @@ -13,12 +13,12 @@ Actix is your door to developing web services with Rust and this documentation is going to guide you. This documentation currently covers mostly the `actix-web` part which is the -high level web framework build on top of the `actix` actor framework and the +high level web framework previously built on top of the `actix` actor framework and the [Tokio](https://tokio.rs/) async IO system. This is the part that is from an API stability point of view the most stable. -If you haven't used actix yet it's best to start with the [getting started +If you haven't used `actix-web` yet it's best to start with the [getting started guide](getting-started/). If you already know your ways around and you need specific information you might want to read the [actix-web API -docs](https://actix.rs/api/actix-web/stable/actix_web/) (or the lower level [actix API +docs](https://docs.rs/actix-web) (or the lower level [actix API docs](https://docs.rs/actix)). diff --git a/content/docs/installation.md b/content/docs/installation.md index 5ad24b6..964663c 100644 --- a/content/docs/installation.md +++ b/content/docs/installation.md @@ -21,7 +21,7 @@ particular this guide will assume that you actually run Rust Thanks to Rust's `cargo` package manager you won't need to explicitly install `actix-web`. Just depend on it and you're ready to go. For the unlikely -case that you want to use the development version of actix-web you can +case that you want to use the development version of `actix-web` you can depend on the git repository directly. Release version: diff --git a/content/docs/whatis.md b/content/docs/whatis.md index 6a097d3..67765d6 100644 --- a/content/docs/whatis.md +++ b/content/docs/whatis.md @@ -7,14 +7,14 @@ weight: 100 # Actix is Multiple Things Actix is a few things. The base of it is a powerful actor system for Rust on -top of which the `actix-web` system is built. This is what you are most likely -going to work with. What `actix-web` gives you is a fun and very fast web +top of which the `actix-web` system was originally built. This is what you are most +likely going to work with. What `actix-web` gives you is a fun and very fast web development framework. We call `actix-web` a small and pragmatic framework. For all intents and purposes it's a microframework with a few twists. If you are already a Rust programmer you will probably find yourself at home quickly, but even if you are coming from -another programming language you should find actix-web easy to pick up. +another programming language you should find `actix-web` easy to pick up. An application developed with `actix-web` will expose an HTTP server contained within a native executable. You can either put this behind another HTTP server like From da969fed1f34527084fcaad294649f93f382d976 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Wed, 19 Jun 2019 14:24:31 -0400 Subject: [PATCH 46/68] simplifies the front-page examples. --- examples/easy-form-handling/src/main.rs | 4 ++-- examples/main-example/src/main.rs | 4 ++-- examples/powerful-extractors/src/main.rs | 8 ++++---- layouts/index.html | 15 +++++++-------- 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/examples/easy-form-handling/src/main.rs b/examples/easy-form-handling/src/main.rs index da0a115..84f577a 100644 --- a/examples/easy-form-handling/src/main.rs +++ b/examples/easy-form-handling/src/main.rs @@ -14,8 +14,8 @@ fn index() -> HttpResponse { .body(include_str!("../static/form.html")) } -fn register(params: web::Form) -> impl Responder { - format!("Hello {} from {}!", params.username, params.country) +fn register(form: web::Form) -> impl Responder { + format!("Hello {} from {}!", form.username, form.country) } fn main() { diff --git a/examples/main-example/src/main.rs b/examples/main-example/src/main.rs index bc8649d..11f7025 100644 --- a/examples/main-example/src/main.rs +++ b/examples/main-example/src/main.rs @@ -9,8 +9,8 @@ fn greet(req: HttpRequest) -> impl Responder { fn main() { HttpServer::new(|| { App::new() - .service(web::resource("/").to(greet)) - .service(web::resource("/{name}").to(greet)) + .route("/", web::get().to(greet)) + .route("/{name}", web::get().to(greet)) }) .bind("127.0.0.1:8088") .unwrap() diff --git a/examples/powerful-extractors/src/main.rs b/examples/powerful-extractors/src/main.rs index e6b11f8..8b8fe7e 100644 --- a/examples/powerful-extractors/src/main.rs +++ b/examples/powerful-extractors/src/main.rs @@ -9,19 +9,19 @@ struct Event { tags: Vec, } -fn store_event_in_db(timestamp: f64, kind: String, tags: Vec) -> Event { +fn store_in_db(timestamp: f64, kind: &String, tags: &Vec) -> Event { // store item in db and get new_event // use id to lookup item Event { id: Some(1), timestamp: timestamp, - kind: kind, - tags: tags, + kind: kind.to_string(), + tags: tags.to_vec(), } } fn capture_event(evt: web::Json) -> impl Responder { - let new_event = store_event_in_db(evt.timestamp, evt.kind.clone(), evt.tags.clone()); + let new_event = store_in_db(evt.timestamp, &evt.kind, &evt.tags); format!("got event {}", new_event.id.unwrap()) } diff --git a/layouts/index.html b/layouts/index.html index 9cf4c3a..4b0fd05 100644 --- a/layouts/index.html +++ b/layouts/index.html @@ -39,7 +39,7 @@
- {{ highlight `use actix_web::{web, App, HttpRequest, HttpResponse, HttpServer}; + {{ highlight `use actix_web::{web, App, HttpRequest, HttpServer}; fn greet(req: HttpRequest) -> impl Responder { let name = req.match_info().get("name").unwrap_or("World"); @@ -49,8 +49,8 @@ fn greet(req: HttpRequest) -> impl Responder { fn main() { HttpServer::new(|| { App::new() - .service(web::resource("/").to(greet)) - .service(web::resource("/{name}").to(greet)) + .route("/", web::get().to(greet)) + .route("/{name}", web::get().to(greet)) }) .bind("127.0.0.1:8000") .expect("Can not bind to port 8000") @@ -98,10 +98,9 @@ struct Event { kind: String, tags: Vec, } + fn capture_event(evt: web::Json) -> impl Responder { - let new_event = store_event_in_db(evt.timestamp, - evt.kind.clone(), - evt.tags.clone()); + let new_event = store_in_db(evt.timestamp, &evt.kind, &evt.tags); format!("got event {}", new_event.id.unwrap()) }` "rust" "" }}
@@ -118,8 +117,8 @@ struct Register { country: String, } -fn register(params: web::Form) -> impl Responder { - format!("Hello {} from {}!", params.username, params.country) +fn register(form: web::Form) -> impl Responder { + format!("Hello {} from {}!", form.username, form.country) }` "rust" "" }}
From ea7bc84f8d5d8a6e1ebd24376da296ffea016d73 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Wed, 19 Jun 2019 18:00:31 -0400 Subject: [PATCH 47/68] Intro: done-ish. Getting Started: done-ish. Application: done-ish. --- content/docs/application.md | 72 +++++++++++++++++----------- content/docs/getting-started.md | 17 ++++--- content/docs/server.md | 2 +- examples/application/src/app.rs | 5 +- examples/application/src/combine.rs | 4 +- examples/application/src/config.rs | 34 +++++++++++++ examples/application/src/main.rs | 26 +++++----- examples/application/src/scope.rs | 15 ++++++ examples/application/src/state.rs | 2 +- examples/application/src/vh.rs | 14 +++--- examples/getting-started/src/main.rs | 20 +++++--- 11 files changed, 145 insertions(+), 66 deletions(-) create mode 100644 examples/application/src/config.rs create mode 100644 examples/application/src/scope.rs diff --git a/content/docs/application.md b/content/docs/application.md index 68f2aad..80eb660 100644 --- a/content/docs/application.md +++ b/content/docs/application.md @@ -10,16 +10,16 @@ weight: 140 It provides routing, middlewares, pre-processing of requests, post-processing of responses, etc. -All actix web servers are built around the `App` instance. It is used for +All `actix-web` servers are built around the `App` instance. It is used for registering routes for resources and middlewares. It also stores application -state shared across all handlers within same application. +state shared across all handlers within same scope. -Applications act as a namespace for all routes, i.e. all routes for a specific application -have the same url path prefix. The application prefix always contains a leading "/" slash. -If a supplied prefix does not contain leading slash, it is automatically inserted. -The prefix should consist of value path segments. +An application's `scope` acts as a namespace for all routes, i.e. all routes for a +specific application scope have the same url path prefix. The application prefix always +contains a leading "/" slash. If a supplied prefix does not contain leading slash, +it is automatically inserted. The prefix should consist of value path segments. -> For an application with prefix `/app`, +> For an application with scope `/app`, > any request with the paths `/app`, `/app/`, or `/app/test` would match; > however, the path `/application` would not match. @@ -31,9 +31,9 @@ are created. This resource is available through the `/app/index.html` url. > For more information, check the > [URL Dispatch](/docs/url-dispatch/index.html#using-an-application-prefix-to-compose-applications) section. -Multiple applications can be served with one server: +Multiple application scopes can be served with one server: -{{< include-example example="application" file="main.rs" section="run_server" >}} +{{< include-example example="application" file="main.rs" section="multi" >}} All `/app1` requests route to the first application, `/app2` to the second, and all other to the third. **Applications get matched based on registration order**. If an application with a more generic @@ -43,10 +43,10 @@ as the first application, it would match all incoming requests. ## State -Application state is shared with all routes and resources within the same application. -When using an http actor, state can be accessed with the `HttpRequest::state()` as read-only, -but interior mutability with `RefCell` can be used to achieve state mutability. -State is also available for route matching predicates and middlewares. +Application state is shared with all routes and resources within the same scope. State +can be accessed with `web::Data` as read-only, but interior mutability with +`Cell` can be used to achieve state mutability. State is also available for route +matching guards and middlewares. Let's write a simple application that uses shared state. We are going to store request count in the state: @@ -57,10 +57,12 @@ When the app is initialized it needs to be passed the initial state: {{< include-example example="application" file="state.rs" section="make_app" >}} -> **Note**: http server accepts an application factory rather than an application -> instance. Http server constructs an application instance for each thread, thus application state -> must be constructed multiple times. If you want to share state between different threads, a -> shared object should be used, e.g. `Arc`. There is also an [Example](https://github.com/actix/examples/blob/master/state/src/main.rs) using `Arc` for this. Application state does not need to be `Send` and `Sync`, +> **Note**: `HttpServer` accepts an application factory rather than an application +> instance. `HttpServer` constructs an application instance for each thread, thus +> application state must be constructed multiple times. If you want to share state between +> different threads, a shared object should be used, e.g. `Arc`. There is also an +> [Example](https://github.com/actix/examples/blob/master/state/src/main.rs) using `Arc` +> for this. Application state does not need to be `Send` and `Sync`, > but the application factory must be `Send` + `Sync`. To start the previous app, create it into a closure: @@ -71,10 +73,6 @@ To start the previous app, create it into a closure: Combining multiple applications with different state is possible as well. -[server::new](https://docs.rs/actix-web/*/actix_web/server/fn.new.html) requires the handler to have a single type. - -This limitation can easily be overcome with the [App::boxed](https://docs.rs/actix-web/*/actix_web/struct.App.html#method.boxed) method, which converts an App into a boxed trait object. - {{< include-example example="application" file="combine.rs" section="combine" >}} ## Using an Application Scope to Compose Applications @@ -87,7 +85,7 @@ resource names. For example: -{{< include-example example="url-dispatch" file="scope.rs" section="scope" >}} +{{< include-example example="application" file="scope.rs" section="scope" >}} In the above example, the *show_users* route will have an effective route pattern of */users/show* instead of */show* because the application's scope argument will be prepended @@ -99,11 +97,31 @@ it will generate a URL with that same path. You can think of a guard as a simple function that accepts a *request* object reference and returns *true* or *false*. Formally, a guard is any object that implements the -[`Guard`](../actix_web/guard/trait.Guard.html) trait. Actix provides -several guards, you can check -[functions section](../../actix-web/actix_web/guard/index.html#functions) of api docs. +[`Guard`](https://docs.rs/actix-web/1.0.2/actix_web/guard/trait.Guard.html) trait. Actix-web +provides several guards, you can check +[functions section](https://docs.rs/actix-web/1.0.2/actix_web/guard/index.html#functions) +of api docs. -One of the provided guards is [`Host`](../actix_web/guard/fn.Host.html), it can be used -as application's filter based on request's host information. +One of the provided guards is [`Header`](https://docs.rs/actix-web/1.0.2/actix_web/guard/fn.Header.html), +it can be used as application's filter based on request's header information. {{< include-example example="application" file="vh.rs" section="vh" >}} + +# Configure + +For simplicity and reusability both `App` and `web::scope` provide the `configure` method. +This function is useful for moving parts of configuration to a different module or even +library. For example, some of the resource's configuration could be moved to different +module. + +{{< include-example example="application" file="config.rs" section="config" >}} + +The result of the above example would be: + +``` +/ -> "/" +/app -> "app" +/api/test -> "test" +``` + +Each `ServiceConfig` can have it's own `data`, `routes`, and `services` diff --git a/content/docs/getting-started.md b/content/docs/getting-started.md index 042a1ac..a4fe727 100644 --- a/content/docs/getting-started.md +++ b/content/docs/getting-started.md @@ -6,7 +6,7 @@ weight: 130 # Getting Started -Let’s write our first actix web application! +Let’s write our first `actix-web` application! ## Hello, world! @@ -27,17 +27,16 @@ actix-web = "{{< actix-version "actix-web" >}}" In order to implement a web server, we first need to create a request handler. -A request handler is a function that accepts any type that can be extracted from a -request (ie, `impl FromRequest`) as its only parameter and returns a type that -can be converted into an `HttpResponse` (ie, `impl Responder`): +A request handler is a function that accepts zero or more parameters that can be +extracted from a request (ie, `impl FromRequest`) and returns a type that can be +converted into an `HttpResponse` (ie, `impl Responder`): {{< include-example example="getting-started" section="setup" >}} -Next, create an `App` instance and register the request handler with -the application's `route` on a particular *HTTP method* and *path* and -after that, the application instance can be used with `HttpServer` to listen -for incoming connections. The server accepts a function that should return an -application factory. +Next, create an `App` instance and register the request handler with the application's +`route` on a *path* and with a particular *HTTP method*. After that, the application +instance can be used with `HttpServer` to listen for incoming connections. The server +accepts a function that should return an application factory. {{< include-example example="getting-started" section="main" >}} diff --git a/content/docs/server.md b/content/docs/server.md index 614411f..2208dca 100644 --- a/content/docs/server.md +++ b/content/docs/server.md @@ -6,7 +6,7 @@ weight: 150 # The HTTP Server -The [**HttpServer**](../../actix-web/actix_web/server/struct.HttpServer.html) type is responsible for +The [**HttpServer**](https://docs.rs/actix-web/1.0.2/actix_web/struct.HttpServer.html) type is responsible for serving http requests. `HttpServer` accepts an application factory as a parameter, and the diff --git a/examples/application/src/app.rs b/examples/application/src/app.rs index 375c2a3..1f53cd3 100644 --- a/examples/application/src/app.rs +++ b/examples/application/src/app.rs @@ -5,7 +5,10 @@ fn index(_req: HttpRequest) -> impl Responder { "Hello world!" } +#[rustfmt::skip] pub fn main() { - App::new().service(web::scope("/app").route("/index.html", web::get().to(index))); + App::new().service( + web::scope("/app") + .route("/index.html", web::get().to(index))); } // diff --git a/examples/application/src/combine.rs b/examples/application/src/combine.rs index 1057f68..0ce5a88 100644 --- a/examples/application/src/combine.rs +++ b/examples/application/src/combine.rs @@ -8,13 +8,13 @@ struct State2; pub fn main() { HttpServer::new(|| { App::new() - .data(State1) - .data(State2) .service( web::scope("/app1") + .data(State1) .route("/", web::to(|| HttpResponse::Ok()))) .service( web::scope("/app2") + .data(State2) .route("/", web::to(|| HttpResponse::Ok()))) }) .bind("127.0.0.1:8088") diff --git a/examples/application/src/config.rs b/examples/application/src/config.rs new file mode 100644 index 0000000..6d1b9a3 --- /dev/null +++ b/examples/application/src/config.rs @@ -0,0 +1,34 @@ +// +use actix_web::{web, App, HttpResponse, HttpServer}; + +// this function could be located in different module +fn scoped_config(cfg: &mut web::ServiceConfig) { + cfg.service( + web::resource("/test") + .route(web::get().to(|| HttpResponse::Ok().body("test"))) + .route(web::head().to(|| HttpResponse::MethodNotAllowed())), + ); +} + +// this function could be located in different module +fn config(cfg: &mut web::ServiceConfig) { + cfg.service( + web::resource("/app") + .route(web::get().to(|| HttpResponse::Ok().body("app"))) + .route(web::head().to(|| HttpResponse::MethodNotAllowed())), + ); +} + +pub fn main() { + HttpServer::new(|| { + App::new() + .configure(config) + .service(web::scope("/api").configure(scoped_config)) + .route("/", web::get().to(|| HttpResponse::Ok().body("/"))) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); +} +// diff --git a/examples/application/src/main.rs b/examples/application/src/main.rs index be51f1d..a8fe4e1 100644 --- a/examples/application/src/main.rs +++ b/examples/application/src/main.rs @@ -1,22 +1,22 @@ -use actix_web::{web, App, HttpResponse, HttpServer}; +use actix_web::{web, App, HttpResponse}; pub mod app; pub mod combine; +pub mod config; +pub mod scope; pub mod state; pub mod vh; #[rustfmt::skip] -// +// fn main() { - HttpServer::new(|| { - App::new() - .service( - web::scope("/app1") - .route("/", web::to(|| HttpResponse::Ok()))) - .service( - web::scope("/app2") - .route("/", web::to(|| HttpResponse::Ok()))) - .route("/", web::to(|| HttpResponse::Ok())) - }); + App::new() + .service( + web::scope("/app1") + .route("/", web::to(|| HttpResponse::Ok()))) + .service( + web::scope("/app2") + .route("/", web::to(|| HttpResponse::Ok()))) + .route("/", web::to(|| HttpResponse::Ok())); } -// +// diff --git a/examples/application/src/scope.rs b/examples/application/src/scope.rs new file mode 100644 index 0000000..b9c5742 --- /dev/null +++ b/examples/application/src/scope.rs @@ -0,0 +1,15 @@ +use actix_web::{web, App, HttpRequest, Responder}; + +fn show_users(_req: HttpRequest) -> impl Responder { + unimplemented!() +} + +#[rustfmt::skip] +// +pub fn main() { + App::new() + .service( + web::scope("/users") + .route("/show", web::get().to(show_users))); +} +// diff --git a/examples/application/src/state.rs b/examples/application/src/state.rs index 9944412..6f5c278 100644 --- a/examples/application/src/state.rs +++ b/examples/application/src/state.rs @@ -4,7 +4,7 @@ use std::cell::Cell; // This struct represents state struct AppState { - counter: Cell, + counter: Cell, } fn index(data: web::Data) -> String { diff --git a/examples/application/src/vh.rs b/examples/application/src/vh.rs index 88f60bd..bd8e34e 100644 --- a/examples/application/src/vh.rs +++ b/examples/application/src/vh.rs @@ -1,22 +1,24 @@ -#![allow(unused)] -use actix_web::{guard, web, App, HttpRequest, HttpResponse, HttpServer, Responder}; +use actix_web::{guard, web, App, HttpResponse, HttpServer}; // -fn main() { +pub fn main() { HttpServer::new(|| { App::new() .service( web::scope("/") .guard(guard::Header("Host", "www.rust-lang.org")) - .route("", web::to(|| HttpResponse::Ok())), + .route("", web::to(|| HttpResponse::Ok().body("www"))), ) .service( web::scope("/") .guard(guard::Header("Host", "users.rust-lang.org")) - .route("", web::to(|| HttpResponse::Ok())), + .route("", web::to(|| HttpResponse::Ok().body("user"))), ) .route("/", web::to(|| HttpResponse::Ok())) }) - .run(); + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // diff --git a/examples/getting-started/src/main.rs b/examples/getting-started/src/main.rs index f3f4186..821e428 100644 --- a/examples/getting-started/src/main.rs +++ b/examples/getting-started/src/main.rs @@ -1,17 +1,25 @@ // use actix_web::{web, App, HttpRequest, HttpResponse, HttpServer, Responder}; -fn index(_req: HttpRequest) -> impl Responder { +fn index() -> impl Responder { HttpResponse::Ok().body("Hello world!") } + +fn index2(_req: HttpRequest) -> impl Responder { + HttpResponse::Ok().body("Hello world again!") +} // //
fn main() { - HttpServer::new(|| App::new().route("/", web::get().to(index))) - .bind("127.0.0.1:8088") - .unwrap() - .run() - .unwrap(); + HttpServer::new(|| { + App::new() + .route("/", web::get().to(index)) + .route("/again", web::get().to(index2)) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } //
From 4291b822fc10c65ad1920fe14a672d5b665584d6 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Wed, 19 Jun 2019 20:26:25 -0400 Subject: [PATCH 48/68] Server section is as good as I'm qualified. --- examples/server/Cargo.toml | 1 + examples/server/src/keep_alive.rs | 14 ++++++++------ examples/server/src/keep_alive_tp.rs | 3 +++ examples/server/src/main.rs | 2 +- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/examples/server/Cargo.toml b/examples/server/Cargo.toml index 95e9a7c..d3bfa22 100644 --- a/examples/server/Cargo.toml +++ b/examples/server/Cargo.toml @@ -9,3 +9,4 @@ actix-rt = "0.2" actix-web = { version = "1.0", features = ["ssl"] } futures = "0.1" openssl = "0.10" +actix-http = "0.2" diff --git a/examples/server/src/keep_alive.rs b/examples/server/src/keep_alive.rs index 86aa88f..d997286 100644 --- a/examples/server/src/keep_alive.rs +++ b/examples/server/src/keep_alive.rs @@ -2,19 +2,21 @@ use actix_web::{web, App, HttpResponse, HttpServer}; pub fn main() { - HttpServer::new(|| { + let one = HttpServer::new(|| { App::new().route("/", web::get().to(|| HttpResponse::Ok())) }) .keep_alive(75); // <- Set keep-alive to 75 seconds - HttpServer::new(|| { - App::new().route("/", web::get().to(|| HttpResponse::Ok())) - }) - .keep_alive(server::KeepAlive::Tcp(75)); // <- Use `SO_KEEPALIVE` socket option. + // let _two = HttpServer::new(|| { + // App::new().route("/", web::get().to(|| HttpResponse::Ok())) + // }) + // .keep_alive(); // <- Use `SO_KEEPALIVE` socket option. - HttpServer::new(|| { + let _three = HttpServer::new(|| { App::new().route("/", web::get().to(|| HttpResponse::Ok())) }) .keep_alive(None); // <- Disable keep-alive + + one.bind("127.0.0.1:8088").unwrap().run().unwrap(); } // diff --git a/examples/server/src/keep_alive_tp.rs b/examples/server/src/keep_alive_tp.rs index 252c53c..19287ee 100644 --- a/examples/server/src/keep_alive_tp.rs +++ b/examples/server/src/keep_alive_tp.rs @@ -8,3 +8,6 @@ pub fn index(req: HttpRequest) -> HttpResponse { .finish() } // +// ConnectionType::Close +// ConnectionType::KeepAlive +// ConnectionType::Upgrade diff --git a/examples/server/src/main.rs b/examples/server/src/main.rs index 735f613..6d43ee1 100644 --- a/examples/server/src/main.rs +++ b/examples/server/src/main.rs @@ -1,4 +1,4 @@ -// pub mod keep_alive; +pub mod keep_alive; // pub mod keep_alive_tp; pub mod signals; pub mod ssl; From 59f010461aa5f2c4d7809b174f55778089e32e18 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Thu, 20 Jun 2019 02:04:22 -0400 Subject: [PATCH 49/68] Handlers done-ish. --- content/docs/handlers.md | 55 +++++++-------------- examples/async-handlers/Cargo.toml | 4 +- examples/async-handlers/src/async_stream.rs | 18 ++++--- examples/async-handlers/src/main.rs | 31 ++++++------ examples/async-handlers/src/stream.rs | 18 ++++--- examples/either/src/main.rs | 4 +- examples/request-handlers/src/main.rs | 4 +- examples/responder-trait/src/main.rs | 7 ++- 8 files changed, 62 insertions(+), 79 deletions(-) diff --git a/content/docs/handlers.md b/content/docs/handlers.md index 2923dbe..699adf7 100644 --- a/content/docs/handlers.md +++ b/content/docs/handlers.md @@ -6,13 +6,17 @@ weight: 160 # Request Handlers -A request handler can be any object that implements -[*Handler*](../../actix-web/actix_web/dev/trait.Handler.html) trait. +A request handler is a function that accepts zero or more parameters that can be extracted +from a request (ie, +[*impl FromRequest*](https://docs.rs/actix-web/1.0.2/actix_web/trait.FromRequest.html)) +and returns a type that can be converted into an HttpResponse (ie, +[*impl Responder*](https://docs.rs/actix-web/1.0.2/actix_web/trait.Responder.html)). Request handling happens in two stages. First the handler object is called, returning any object that implements the -[*Responder*](../../actix-web/actix_web/trait.Responder.html#foreign-impls) trait. -Then, `respond_to()` is called on the returned object, converting itself to a `AsyncResult` or `Error`. +[*Responder*](https://docs.rs/actix-web/1.0.2/actix_web/trait.Responder.html) trait. +Then, `respond_to()` is called on the returned object, converting itself to a `HttpResponse` +or `Error`. By default actix provides `Responder` implementations for some standard types, such as `&'static str`, `String`, etc. @@ -29,7 +33,7 @@ fn index(req: &HttpRequest) -> &'static str { ``` ```rust -fn index(req: &HttpRequest) -> String { +fn index(req: HttpRequest) -> String { "Hello world!".to_owned() } ``` @@ -38,49 +42,24 @@ You can also change the signature to return `impl Responder` which works well if complex types are involved. ```rust -fn index(req: &HttpRequest) -> impl Responder { +fn index(req: HttpRequest) -> impl Responder { Bytes::from_static("Hello world!") } ``` -```rust,ignore -fn index(req: &HttpRequest) -> Box> { +```rust +fn index(req: HttpRequest) -> Box> { ... } ``` -*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 use interior mutably to access its own -> state. **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: - -{{< include-example example="request-handlers" file="main.rs" section="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`. - -{{< include-example example="request-handlers" file="handlers_arc.rs" section="arc" >}} - -> Be careful with synchronization primitives like `Mutex` or `RwLock`. The `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: -{{< include-example example="responder-trait" file="main.rs" section="main" >}} +{{< include-example example="responder-trait" file="main.rs" section="responder-trait" >}} ## Async handlers @@ -89,12 +68,12 @@ or more precisely, any type that implements the [*Responder*](../../actix-web/ac In this case, the handler must return a `Future` object that resolves to the *Responder* type, i.e: -{{< include-example example="async-handlers" file="main.rs" section="main" >}} +{{< include-example example="async-handlers" file="main.rs" section="async-responder" >}} Or the response body can be generated asynchronously. In this case, body must implement the stream trait `Stream`, i.e: -{{< include-example example="async-handlers" file="stream.rs" section="main" >}} +{{< include-example example="async-handlers" file="stream.rs" section="stream" >}} Both methods can be combined. (i.e Async response with streaming body) @@ -102,7 +81,7 @@ 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`. -{{< include-example example="async-handlers" file="async_stream.rs" section="main" >}} +{{< include-example example="async-handlers" file="async_stream.rs" section="async-stream" >}} ## Different return types (Either) @@ -112,4 +91,4 @@ you can error check and return errors, return async responses, or any result tha For this case, the [*Either*](../../actix-web/actix_web/enum.Either.html) type can be used. `Either` allows combining two different responder types into a single type. -{{< include-example example="either" file="main.rs" section="main" >}} +{{< include-example example="either" file="main.rs" section="either" >}} diff --git a/examples/async-handlers/Cargo.toml b/examples/async-handlers/Cargo.toml index 9a9e413..afdf0dc 100644 --- a/examples/async-handlers/Cargo.toml +++ b/examples/async-handlers/Cargo.toml @@ -1,9 +1,9 @@ [package] name = "async-handlers" -version = "0.7.0" +version = "1.0.0" edition = "2018" [dependencies] -actix-web = "0.7" +actix-web = "1.0" futures = "0.1" bytes = "0.4" diff --git a/examples/async-handlers/src/async_stream.rs b/examples/async-handlers/src/async_stream.rs index 2641e21..b954cb0 100644 --- a/examples/async-handlers/src/async_stream.rs +++ b/examples/async-handlers/src/async_stream.rs @@ -1,24 +1,28 @@ fn is_error() -> bool { - true + false } -//
-use actix_web::{error, App, Error, HttpRequest, HttpResponse}; +// +use actix_web::{error, web, App, Error, HttpRequest, HttpResponse, HttpServer}; use futures::future::{result, Future}; fn index( - _req: &HttpRequest, + _req: HttpRequest, ) -> Result>, Error> { if is_error() { Err(error::ErrorBadRequest("bad request")) } else { Ok(Box::new(result(Ok(HttpResponse::Ok() .content_type("text/html") - .body(format!("Hello!")))))) + .body("Hello!"))))) } } -//
+// pub fn main() { - App::new().resource("/", |r| r.route().f(index)).finish(); + HttpServer::new(|| App::new().route("/", web::to_async(index))) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } diff --git a/examples/async-handlers/src/main.rs b/examples/async-handlers/src/main.rs index b8c5f8f..f86d286 100644 --- a/examples/async-handlers/src/main.rs +++ b/examples/async-handlers/src/main.rs @@ -1,25 +1,22 @@ -mod async_stream; -mod stream; -//
-use actix_web::{App, AsyncResponder, Error, HttpRequest, HttpResponse}; -use futures::future::{result, Future}; +pub mod async_stream; +pub mod stream; +// +use actix_web::{web, App, Error, HttpRequest, HttpResponse}; +use futures::future::{ok, Future}; -fn index(_req: &HttpRequest) -> Box> { - result(Ok(HttpResponse::Ok() - .content_type("text/html") - .body(format!("Hello!")))) - .responder() +fn index(_req: HttpRequest) -> Box> { + Box::new(ok::<_, Error>( + HttpResponse::Ok().content_type("text/html").body("Hello!"), + )) } -fn index2(_req: &HttpRequest) -> Box> { - result(Ok("Welcome!")).responder() +fn index2(_req: HttpRequest) -> Box> { + Box::new(ok::<_, Error>("Welcome!")) } fn main() { App::new() - .resource("/async", |r| r.route().a(index)) - .resource("/", |r| r.route().a(index2)) - // .resource("/", |r| r.route().f(async_stream::index)) - .finish(); + .route("/async", web::to_async(index)) + .route("/", web::to_async(index2)); } -//
+// diff --git a/examples/async-handlers/src/stream.rs b/examples/async-handlers/src/stream.rs index da4c8a0..abcefb1 100644 --- a/examples/async-handlers/src/stream.rs +++ b/examples/async-handlers/src/stream.rs @@ -1,17 +1,21 @@ -//
-use actix_web::{App, Body, HttpRequest, HttpResponse}; +// +use actix_web::{web, App, Error, HttpRequest, HttpResponse, HttpServer}; use bytes::Bytes; use futures::stream::once; -fn index(_req: &HttpRequest) -> HttpResponse { - let body = once(Ok(Bytes::from_static(b"test"))); +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))) + .streaming(Box::new(body)) } pub fn main() { - App::new().resource("/async", |r| r.f(index)).finish(); + HttpServer::new(|| App::new().route("/async", web::to_async(index))) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } -//
+// diff --git a/examples/either/src/main.rs b/examples/either/src/main.rs index 453239d..83e1fcf 100644 --- a/examples/either/src/main.rs +++ b/examples/either/src/main.rs @@ -1,4 +1,4 @@ -//
+// use actix_web::{web, App, Either, Error, HttpRequest, HttpResponse}; use futures::future::{ok, Future}; @@ -22,7 +22,7 @@ fn index(_req: HttpRequest) -> RegisterResult { fn main() { App::new().route("/", web::get().to(index)); } -//
+// fn is_a_variant() -> bool { true diff --git a/examples/request-handlers/src/main.rs b/examples/request-handlers/src/main.rs index 84d7aca..8756e7d 100644 --- a/examples/request-handlers/src/main.rs +++ b/examples/request-handlers/src/main.rs @@ -1,5 +1,5 @@ mod handlers_arc; -//
+// use actix_web::{dev::Handler, server, App, HttpRequest, HttpResponse}; use std::cell::Cell; @@ -22,4 +22,4 @@ fn main() { .unwrap() .run(); } -//
+// diff --git a/examples/responder-trait/src/main.rs b/examples/responder-trait/src/main.rs index e635151..869ea54 100644 --- a/examples/responder-trait/src/main.rs +++ b/examples/responder-trait/src/main.rs @@ -1,7 +1,6 @@ -//
+// use actix_web::{web, App, Error, HttpRequest, HttpResponse, HttpServer, Responder}; use serde::Serialize; -use serde_json; #[derive(Serialize)] struct MyObj { @@ -23,9 +22,10 @@ impl Responder for MyObj { } } -fn index(_req: HttpRequest) -> impl Responder { +fn index() -> impl Responder { MyObj { name: "user" } } +// fn main() { HttpServer::new(|| App::new().route("/", web::get().to(index))) @@ -34,4 +34,3 @@ fn main() { .run() .unwrap(); } -//
From c4c32091a6e51d8854393f89a12b308134d94217 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Thu, 20 Jun 2019 04:20:12 -0400 Subject: [PATCH 50/68] extractors: done-ish. --- content/docs/extractors.md | 94 +++++++++++-------- examples/extractors/src/custom_handler.rs | 18 ---- examples/extractors/src/form.rs | 8 +- examples/extractors/src/json_one.rs | 10 +- examples/extractors/src/json_two.rs | 42 +++++---- examples/extractors/src/main.rs | 9 +- examples/extractors/src/multiple.rs | 23 +++-- examples/extractors/src/path_one.rs | 18 ++-- examples/extractors/src/path_two.rs | 16 +++- examples/extractors/src/query.rs | 10 +- examples/request-handlers/Cargo.toml | 5 +- examples/request-handlers/src/handlers_arc.rs | 41 ++++---- examples/request-handlers/src/main.rs | 47 ++++++---- 13 files changed, 199 insertions(+), 142 deletions(-) delete mode 100644 examples/extractors/src/custom_handler.rs diff --git a/content/docs/extractors.md b/content/docs/extractors.md index f6668f6..df6c6bc 100644 --- a/content/docs/extractors.md +++ b/content/docs/extractors.md @@ -6,37 +6,26 @@ weight: 170 # Type-safe information extraction -Actix provides facility for type-safe request information extraction. By default, -actix provides several extractor implementations. +Actix-web provides a facility for type-safe request information access called *extractors* +(ie, `impl FromRequest`). By default, actix-web provides several extractor implementations. -# Accessing Extractors +## Extractors Within Handler Functions -How you access an Extractor depends on whether you are using a handler function -or a custom Handler type. +An extractor can be accessed in a few different ways. -## Within Handler Functions +Option 1 - passed as a parameter to a handler function: -An Extractor can be passed to a handler function as a function parameter -*or* accessed within the function by calling the ExtractorType::<...>::extract(req) -function. +{{< include-example example="extractors" file="main.rs" section="option-one" >}} -{{< include-example example="extractors" file="main.rs" section="main" >}} +Option 2 - accessed by calling `extract()` on the Extractor -## Within Custom Handler Types - -Like a handler function, a custom Handler type can *access* an Extractor by -calling the ExtractorType::<...>::extract(&req) function. An Extractor -*cannot* be passed as a parameter to a custom Handler type because a custom -Handler type must follow the ``handle`` function signature specified by the -Handler trait it implements. - -{{< include-example example="extractors" file="custom_handler.rs" section="custom-handler" >}} +{{< include-example example="extractors" file="main.rs" section="option-two" >}} # Path -[*Path*](../../actix-web/actix_web/struct.Path.html) provides information that can -be extracted from the Request's path. You can deserialize any variable -segment from the path. +[*Path*](https://docs.rs/actix-web/1.0.2/actix_web/dev/struct.Path.html) provides +information that can be extracted from the Request's path. You can deserialize any +variable segment from the path. For instance, for resource that registered for the `/users/{userid}/{friend}` path two segments could be deserialized, `userid` and `friend`. These segments @@ -51,27 +40,31 @@ instead of a *tuple* type. {{< include-example example="extractors" file="path_two.rs" section="path-two" >}} +It is also possible to `get` or `query` the request for path parameters by name: + +{{< include-example example="extractors" file="path_three.rs" section="path-three" >}} + # Query -Same can be done with the request's query. -The [*Query*](../../actix-web/actix_web/struct.Query.html) -type provides extraction functionality. Underneath it uses *serde_urlencoded* crate. +The [*Query*](https://docs.rs/actix-web/1.0.2/actix_web/web/struct.Query.html) +type provides extraction functionality for the request's query parameters. Underneath it +uses *serde_urlencoded* crate. {{< include-example example="extractors" file="query.rs" section="query" >}} # Json -[*Json*](../../actix-web/actix_web/struct.Json.html) allows to deserialize +[*Json*](https://docs.rs/actix-web/1.0.2/actix_web/web/struct.Json.html) allows to deserialize a request body into a struct. To extract typed information from a request's body, the type `T` must implement the `Deserialize` trait from *serde*. {{< include-example example="extractors" file="json_one.rs" section="json-one" >}} Some extractors provide a way to configure the extraction process. Json extractor -[*JsonConfig*](../../actix-web/actix_web/dev/struct.JsonConfig.html) type for configuration. -When you register a handler using `Route::with()`, it returns a configuration instance. In case of -a *Json* extractor it returns a *JsonConfig*. You can configure the maximum size of the json -payload as well as a custom error handler function. +[*JsonConfig*](https://docs.rs/actix-web/1.0.2/actix_web/web/struct.JsonConfig.html) type +for configuration. When you register a handler using `Route::with()`, it returns a +configuration instance. In case of a *Json* extractor it returns a *JsonConfig*. You can +configure the maximum size of the json payload as well as a custom error handler function. The following example limits the size of the payload to 4kb and uses a custom error handler. @@ -83,14 +76,14 @@ At the moment only url-encoded forms are supported. The url-encoded body could be extracted to a specific type. This type must implement the `Deserialize` trait from the *serde* crate. -[*FormConfig*](../../actix-web/actix_web/dev/struct.FormConfig.html) allows +[*FormConfig*](https://docs.rs/actix-web/1.0.2/actix_web/web/struct.FormConfig.html) allows configuring the extraction process. {{< include-example example="extractors" file="form.rs" section="form" >}} # Multiple extractors -Actix provides extractor implementations for tuples (up to 10 elements) +Actix-web provides extractor implementations for tuples (up to 10 elements) whose elements implement `FromRequest`. For example we can use a path extractor and a query extractor at the same time. @@ -99,15 +92,42 @@ For example we can use a path extractor and a query extractor at the same time. # Other -Actix also provides several other extractors: +Actix-web also provides several other extractors: -* [*Data*](../../actix-web/actix_web/web/struct.Data.html) - If you need - access to an application state. This is similar to a `HttpRequest::app_data()`. +* [*Data*](https://docs.rs/actix-web/1.0.2/actix_web/web/struct.Data.html) - If you need + access to an application state. * *HttpRequest* - *HttpRequest* itself is an extractor which returns self, in case you need access to the request. * *String* - You can convert a request's payload to a *String*. - [*Example*](../../actix-web/actix_web/trait.FromRequest.html#example-1) + [*Example*](https://docs.rs/actix-web/1.0.2/actix_web/trait.FromRequest.html#example-2) is available in doc strings. * *bytes::Bytes* - You can convert a request's payload into *Bytes*. - [*Example*](../../actix-web/actix_web/trait.FromRequest.html#example) + [*Example*](https://docs.rs/actix-web/1.0.2/actix_web/trait.FromRequest.html#example-4) is available in doc strings. +* *Payload* - You can access a request's payload. + [*Example*](https://docs.rs/actix-web/1.0.2/actix_web/web/struct.Payload.html) + +# Async Data Access + +Application state is accessible from the handler with the `web::Data` extractor; +however, state is accessible as a read-only reference. If you need mutable access to state, +it must be implemented. + +> **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: + +{{< include-example example="request-handlers" file="main.rs" section="data" >}} + +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`. + +{{< include-example example="request-handlers" file="handlers_arc.rs" section="arc" >}} + +> Be careful with synchronization primitives like `Mutex` or `RwLock`. The `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. diff --git a/examples/extractors/src/custom_handler.rs b/examples/extractors/src/custom_handler.rs deleted file mode 100644 index 93596d9..0000000 --- a/examples/extractors/src/custom_handler.rs +++ /dev/null @@ -1,18 +0,0 @@ -use actix_web::{web, HttpRequest, HttpResponse}; - -struct MyHandler {} -struct MyInfo {} - -// -impl Handler for MyHandler { - type Result = HttpResponse; - - /// Handle request - fn handle(&self, req: &HttpRequest) -> Self::Result { - let params = web::Path::<(String, String)>::extract(req); - let info = web::Json::::extract(req); - - HttpResponse::Ok().into() - } -} -// diff --git a/examples/extractors/src/form.rs b/examples/extractors/src/form.rs index 1af09d4..394a255 100644 --- a/examples/extractors/src/form.rs +++ b/examples/extractors/src/form.rs @@ -1,5 +1,5 @@ //
-use actix_web::{web, App, Result}; +use actix_web::{web, App, HttpServer, Result}; use serde::Deserialize; #[derive(Deserialize)] @@ -16,5 +16,9 @@ fn index(form: web::Form) -> Result { // pub fn main() { - App::new().route("", web::post().to(index)); + HttpServer::new(|| App::new().route("/", web::post().to(index))) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } diff --git a/examples/extractors/src/json_one.rs b/examples/extractors/src/json_one.rs index d54459b..255959d 100644 --- a/examples/extractors/src/json_one.rs +++ b/examples/extractors/src/json_one.rs @@ -1,5 +1,5 @@ // -use actix_web::{web, App, Result}; +use actix_web::{web, App, HttpServer, Result}; use serde::Deserialize; #[derive(Deserialize)] @@ -11,8 +11,12 @@ struct Info { fn index(info: web::Json) -> Result { Ok(format!("Welcome {}!", info.username)) } +// pub fn main() { - App::new().route("/", web::get().to(index)); + HttpServer::new(|| App::new().route("/", web::post().to(index))) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } -// diff --git a/examples/extractors/src/json_two.rs b/examples/extractors/src/json_two.rs index c6464ac..e5e8a22 100644 --- a/examples/extractors/src/json_two.rs +++ b/examples/extractors/src/json_two.rs @@ -1,5 +1,5 @@ // -use actix_web::{error, web, App, FromRequest, HttpResponse, Responder}; +use actix_web::{error, web, App, FromRequest, HttpResponse, HttpServer, Responder}; use serde::Deserialize; #[derive(Deserialize)] @@ -13,22 +13,28 @@ fn index(info: web::Json) -> impl Responder { } pub fn main() { - App::new().service( - web::resource("/") - .data( - // change json extractor configuration - web::Json::::configure(|cfg| { - cfg.limit(4096).error_handler(|err, _req| { - // <- create custom error response - error::InternalError::from_response( - err, - HttpResponse::Conflict().finish(), - ) - .into() - }) - }), - ) - .route(web::post().to(index)), - ); + HttpServer::new(|| { + App::new().service( + web::resource("/") + .data( + // change json extractor configuration + web::Json::::configure(|cfg| { + cfg.limit(4096).error_handler(|err, _req| { + // <- create custom error response + error::InternalError::from_response( + err, + HttpResponse::Conflict().finish(), + ) + .into() + }) + }), + ) + .route(web::post().to(index)), + ) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // diff --git a/examples/extractors/src/main.rs b/examples/extractors/src/main.rs index 276b1b6..0925a79 100644 --- a/examples/extractors/src/main.rs +++ b/examples/extractors/src/main.rs @@ -8,6 +8,7 @@ pub mod json_one; pub mod json_two; pub mod multiple; pub mod path_one; +pub mod path_three; pub mod path_two; pub mod query; @@ -17,13 +18,13 @@ struct MyInfo { id: u32, } -//
-// Option 1: passed as a parameter to a handler function +// fn index(path: web::Path<(String, String)>, json: web::Json) -> impl Responder { format!("{} {} {} {}", path.0, path.1, json.id, json.username) } +// -// Option 2: accessed by calling extract() on the Extractor +// fn extract(req: HttpRequest) -> impl Responder { let params = web::Path::<(String, String)>::extract(&req).unwrap(); @@ -33,7 +34,7 @@ fn extract(req: HttpRequest) -> impl Responder { format!("{} {} {} {}", params.0, params.1, info.username, info.id) } -//
+// fn main() { HttpServer::new(|| { diff --git a/examples/extractors/src/multiple.rs b/examples/extractors/src/multiple.rs index 1d861d4..118dd5c 100644 --- a/examples/extractors/src/multiple.rs +++ b/examples/extractors/src/multiple.rs @@ -1,5 +1,5 @@ // -use actix_web::{web, App}; +use actix_web::{web, App, HttpServer}; use serde::Deserialize; #[derive(Deserialize)] @@ -7,14 +7,23 @@ struct Info { username: String, } -fn index((_path, query): (web::Path<(u32, String)>, web::Query)) -> String { - format!("Welcome {}!", query.username) +fn index((path, query): (web::Path<(u32, String)>, web::Query)) -> String { + format!( + "Welcome {}, friend {}, useri {}!", + query.username, path.1, path.0 + ) } pub fn main() { - App::new().route( - "/users/{userid}/{friend}", // <- define path parameters - web::get().to(index), - ); + HttpServer::new(|| { + App::new().route( + "/users/{userid}/{friend}", // <- define path parameters + web::get().to(index), + ) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // diff --git a/examples/extractors/src/path_one.rs b/examples/extractors/src/path_one.rs index eb46b9b..0b83de8 100644 --- a/examples/extractors/src/path_one.rs +++ b/examples/extractors/src/path_one.rs @@ -1,17 +1,23 @@ // -use actix_web::{web, App, Result}; +use actix_web::{web, App, HttpServer, Result}; /// extract path info from "/users/{userid}/{friend}" url /// {userid} - - deserializes to a u32 /// {friend} - deserializes to a String fn index(info: web::Path<(u32, String)>) -> Result { - Ok(format!("Welcome {}! {}", info.1, info.0)) + Ok(format!("Welcome {}, userid {}!", info.1, info.0)) } pub fn main() { - App::new().route( - "/users/{userid}/{friend}", // <- define path parameters - web::get().to(index), - ); + HttpServer::new(|| { + App::new().route( + "/users/{userid}/{friend}", // <- define path parameters + web::get().to(index), + ) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // diff --git a/examples/extractors/src/path_two.rs b/examples/extractors/src/path_two.rs index 7c5a4c3..aa836d6 100644 --- a/examples/extractors/src/path_two.rs +++ b/examples/extractors/src/path_two.rs @@ -1,5 +1,5 @@ // -use actix_web::{web, App, Result}; +use actix_web::{web, App, HttpServer, Result}; use serde::Deserialize; #[derive(Deserialize)] @@ -14,9 +14,15 @@ fn index(info: web::Path) -> Result { } pub fn main() { - App::new().route( - "/users/{userid}/{friend}", // <- define path parameters - web::get().to(index), - ); + HttpServer::new(|| { + App::new().route( + "/users/{userid}/{friend}", // <- define path parameters + web::get().to(index), + ) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // diff --git a/examples/extractors/src/query.rs b/examples/extractors/src/query.rs index ff1883b..10af0ce 100644 --- a/examples/extractors/src/query.rs +++ b/examples/extractors/src/query.rs @@ -1,5 +1,5 @@ // -use actix_web::{web, App}; +use actix_web::{web, App, HttpServer}; use serde::Deserialize; #[derive(Deserialize)] @@ -11,8 +11,12 @@ struct Info { fn index(info: web::Query) -> String { format!("Welcome {}!", info.username) } +// pub fn main() { - App::new().route("/", web::get().to(index)); + HttpServer::new(|| App::new().route("/", web::get().to(index))) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } -// diff --git a/examples/request-handlers/Cargo.toml b/examples/request-handlers/Cargo.toml index da4764a..325b659 100644 --- a/examples/request-handlers/Cargo.toml +++ b/examples/request-handlers/Cargo.toml @@ -1,8 +1,7 @@ [package] name = "request-handlers" -version = "0.7.0" +version = "1.0.0" edition = "2018" [dependencies] -actix-web = "0.7" -actix = "0.7" +actix-web = "1.0" diff --git a/examples/request-handlers/src/handlers_arc.rs b/examples/request-handlers/src/handlers_arc.rs index 9858355..f3002d8 100644 --- a/examples/request-handlers/src/handlers_arc.rs +++ b/examples/request-handlers/src/handlers_arc.rs @@ -1,34 +1,37 @@ // -use actix_web::{dev::Handler, server, App, HttpRequest, HttpResponse}; +use actix_web::{web, App, HttpServer, Responder}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; -struct MyHandler(Arc); +#[derive(Clone)] +struct AppState { + count: Arc, +} -impl Handler for MyHandler { - type Result = HttpResponse; +fn show_count(data: web::Data) -> impl Responder { + format!("count: {}", data.count.load(Ordering::Relaxed)) +} - /// Handle request - fn handle(&self, _req: &HttpRequest) -> Self::Result { - self.0.fetch_add(1, Ordering::Relaxed); - HttpResponse::Ok().into() - } +fn add_one(data: web::Data) -> impl Responder { + data.count.fetch_add(1, Ordering::Relaxed); + + format!("count: {}", data.count.load(Ordering::Relaxed)) } pub fn main() { - let sys = actix::System::new("example"); + let data = AppState { + count: Arc::new(AtomicUsize::new(0)), + }; - let inc = Arc::new(AtomicUsize::new(0)); - - server::new(move || { - let cloned = inc.clone(); - App::new().resource("/", move |r| r.h(MyHandler(cloned))) + HttpServer::new(move || { + App::new() + .data(data.clone()) + .route("/", web::to(show_count)) + .route("/add", web::to(add_one)) }) .bind("127.0.0.1:8088") .unwrap() - .start(); - - println!("Started http server: 127.0.0.1:8088"); - let _ = sys.run(); + .run() + .unwrap(); } // diff --git a/examples/request-handlers/src/main.rs b/examples/request-handlers/src/main.rs index 8756e7d..48d7842 100644 --- a/examples/request-handlers/src/main.rs +++ b/examples/request-handlers/src/main.rs @@ -1,25 +1,38 @@ -mod handlers_arc; -// -use actix_web::{dev::Handler, server, App, HttpRequest, HttpResponse}; +pub mod handlers_arc; +// +use actix_web::{web, App, HttpServer, Responder}; use std::cell::Cell; -struct MyHandler(Cell); +#[derive(Clone)] +struct AppState { + count: Cell, +} -impl Handler for MyHandler { - type Result = HttpResponse; +fn show_count(data: web::Data) -> impl Responder { + format!("count: {}", data.count.get()) +} - /// Handle request - fn handle(&self, _req: &HttpRequest) -> Self::Result { - let i = self.0.get(); - self.0.set(i + 1); - HttpResponse::Ok().into() - } +fn add_one(data: web::Data) -> impl Responder { + let count = data.count.get(); + data.count.set(count + 1); + + format!("count: {}", data.count.get()) } fn main() { - server::new(|| App::new().resource("/", |r| r.h(MyHandler(Cell::new(0))))) //use r.h() to bind handler, not the r.f() - .bind("127.0.0.1:8088") - .unwrap() - .run(); + let data = AppState { + count: Cell::new(0), + }; + + HttpServer::new(move || { + App::new() + .data(data.clone()) + .route("/", web::to(show_count)) + .route("/add", web::to(add_one)) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } -// +// From 339ac4381422ec35ba5d26b4b41b40879ca6f6fb Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Thu, 20 Jun 2019 04:26:34 -0400 Subject: [PATCH 51/68] Fixes missed example and config for extractors. --- content/docs/extractors.md | 4 ++-- examples/extractors/src/path_three.rs | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 examples/extractors/src/path_three.rs diff --git a/content/docs/extractors.md b/content/docs/extractors.md index df6c6bc..35a08ec 100644 --- a/content/docs/extractors.md +++ b/content/docs/extractors.md @@ -62,8 +62,8 @@ the type `T` must implement the `Deserialize` trait from *serde*. Some extractors provide a way to configure the extraction process. Json extractor [*JsonConfig*](https://docs.rs/actix-web/1.0.2/actix_web/web/struct.JsonConfig.html) type -for configuration. When you register a handler using `Route::with()`, it returns a -configuration instance. In case of a *Json* extractor it returns a *JsonConfig*. You can +for configuration. To configure an extractor, pass it's configuration object to the resource's +`.data()` method. In case of a *Json* extractor it returns a *JsonConfig*. You can configure the maximum size of the json payload as well as a custom error handler function. The following example limits the size of the payload to 4kb and uses a custom error handler. diff --git a/examples/extractors/src/path_three.rs b/examples/extractors/src/path_three.rs new file mode 100644 index 0000000..9ca71c9 --- /dev/null +++ b/examples/extractors/src/path_three.rs @@ -0,0 +1,23 @@ +use actix_web::{web, App, HttpRequest, HttpServer, Result}; + +// +fn index(req: HttpRequest) -> Result { + let name: String = req.match_info().get("friend").unwrap().parse().unwrap(); + let userid: i32 = req.match_info().query("userid").parse().unwrap(); + + Ok(format!("Welcome {}, userid {}!", name, userid)) +} + +pub fn main() { + HttpServer::new(|| { + App::new().route( + "/users/{userid}/{friend}", // <- define path parameters + web::get().to(index), + ) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); +} +// From 4f57ce2fdb5f66397e0a022bfd86a7fb28e4eef1 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Sat, 22 Jun 2019 09:18:08 -0400 Subject: [PATCH 52/68] Clippy fixes. --- examples/either/src/main.rs | 2 +- examples/powerful-extractors/src/main.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/either/src/main.rs b/examples/either/src/main.rs index 83e1fcf..3ecd892 100644 --- a/examples/either/src/main.rs +++ b/examples/either/src/main.rs @@ -14,7 +14,7 @@ fn index(_req: HttpRequest) -> RegisterResult { // <- variant B Box::new(ok(HttpResponse::Ok() .content_type("text/html") - .body(format!("Hello!")))), + .body("Hello!".to_string()))), ) } } diff --git a/examples/powerful-extractors/src/main.rs b/examples/powerful-extractors/src/main.rs index 8b8fe7e..5d80d7f 100644 --- a/examples/powerful-extractors/src/main.rs +++ b/examples/powerful-extractors/src/main.rs @@ -9,12 +9,12 @@ struct Event { tags: Vec, } -fn store_in_db(timestamp: f64, kind: &String, tags: &Vec) -> Event { +fn store_in_db(timestamp: f64, kind: &str, tags: &[String]) -> Event { // store item in db and get new_event // use id to lookup item Event { id: Some(1), - timestamp: timestamp, + timestamp, kind: kind.to_string(), tags: tags.to_vec(), } From 60f4f116cf3531180e5f1d78f0a3b50955430b04 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Mon, 24 Jun 2019 17:43:31 -0400 Subject: [PATCH 53/68] Testing is done-ish. --- content/docs/testing.md | 49 +++++-------- examples/testing/Cargo.toml | 2 + examples/testing/src/integration_one.rs | 43 +++++++----- examples/testing/src/integration_three.rs | 21 ------ examples/testing/src/integration_two.rs | 46 ++++++++----- examples/testing/src/main.rs | 40 +++++++---- examples/testing/src/stream_response.rs | 83 +++++++++++------------ examples/testing/src/websockets.rs | 30 -------- 8 files changed, 141 insertions(+), 173 deletions(-) delete mode 100644 examples/testing/src/integration_three.rs delete mode 100644 examples/testing/src/websockets.rs diff --git a/content/docs/testing.md b/content/docs/testing.md index 5f7b59d..335300b 100644 --- a/content/docs/testing.md +++ b/content/docs/testing.md @@ -6,13 +6,13 @@ weight: 210 # Testing -Every application should be well tested. Actix provides tools to perform unit and +Every application should be well tested. Actix-web 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/actix_web/test/struct.TestRequest.html) +For unit testing, actix-web provides a request builder type and a simple handler runner. +[*TestRequest*](https://docs.rs/actix-web/1.0.2/actix_web/test/struct.TestRequest.html) implements a builder-like pattern. You can generate a `HttpRequest` instance with `to_http_request()`, or you can run your handler with `block_on()`. @@ -21,49 +21,32 @@ run your handler with `block_on()`. # Integration tests -There are several methods for testing your application. Actix provides -[*TestServer*](../../actix-web/actix_web/test/struct.TestServer.html), which can be used +There a few methods for testing your application. Actix-web can be used to run the application with specific handlers in a real http server. -`TestServer::get()`, `TestServer::post()`, and `TestServer::client()` +`TestRequest::get()`, `TestRequest::post()`, and `TestRequest::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. +To create a `Service` for testing, use the `test::init_serivce` method which accepts a +regular `App` builder. -> Check the [api documentation](../../actix-web/actix_web/test/struct.TestApp.html) +> Check the [api documentation](https://docs.rs/actix-web/1.0.2/actix_web/test/index.html) > for more information. {{< include-example example="testing" file="integration_one.rs" section="integration-one" >}} -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. +If you need more complex application configuration testing should be very similar to creating +the normal application. For example, you may need to initialize application state. Create an +`App` with a `data` method and attach state just like you would from a normal application. {{< include-example example="testing" file="integration_two.rs" section="integration-two" >}} -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. - -{{< include-example example="testing" file="integration_three.rs" section="integration-three" >}} - # Stream response tests -If you need to test stream it would be enough to convert a [*ClientResponse*](../../actix-web/actix_web/client/struct.ClientResponse.html) to future and execute it. -For example of testing [*Server Sent Events*](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events). +If you need to test stream it would be enough to convert a +[*ClientResponse*](../../actix-web/actix_web/client/struct.ClientResponse.html) to future +and execute it. +For example of testing +[*Server Sent Events*](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events). {{< include-example example="testing" file="stream_response.rs" section="stream-response" >}} - -# 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: - -{{< include-example example="testing" file="websockets.rs" section="web-socket" >}} diff --git a/examples/testing/Cargo.toml b/examples/testing/Cargo.toml index 15532db..5eba424 100644 --- a/examples/testing/Cargo.toml +++ b/examples/testing/Cargo.toml @@ -7,3 +7,5 @@ edition = "2018" actix-web = "1.0" futures = "0.1" bytes = "0.4" +serde = "1.0" +serde_json = "1.0" diff --git a/examples/testing/src/integration_one.rs b/examples/testing/src/integration_one.rs index 5507d7d..750cbc9 100644 --- a/examples/testing/src/integration_one.rs +++ b/examples/testing/src/integration_one.rs @@ -1,22 +1,33 @@ +use actix_web::{HttpRequest, Responder}; + +#[allow(dead_code)] +fn index(_req: HttpRequest) -> impl Responder { + "Hello world!" +} + // -// use actix_web::test::TestServer; -// use actix_web::HttpRequest; -// use std::str; +#[cfg(test)] +mod tests { + use super::*; + use actix_web::dev::Service; + use actix_web::{test, web, App}; -// fn index(req: HttpRequest) -> &'static str { -// "Hello world!" -// } + #[test] + fn test_index_get() { + let mut app = test::init_service(App::new().route("/", web::get().to(index))); + let req = test::TestRequest::get().uri("/").to_request(); + let resp = test::block_on(app.call(req)).unwrap(); -// fn main() { -// // start new test server -// let mut srv = TestServer::new(|app| app.handler(index)); + assert!(resp.status().is_success()); + } -// let request = srv.get().finish().unwrap(); -// let response = srv.execute(request.send()).unwrap(); -// assert!(response.status().is_success()); + #[test] + fn test_index_post() { + let mut app = test::init_service(App::new().route("/", web::get().to(index))); + let req = test::TestRequest::post().uri("/").to_request(); + let resp = test::block_on(app.call(req)).unwrap(); -// let bytes = srv.execute(response.body()).unwrap(); -// let body = str::from_utf8(&bytes).unwrap(); -// assert_eq!(body, "Hello world!"); -// } + assert!(resp.status().is_client_error()); + } +} // diff --git a/examples/testing/src/integration_three.rs b/examples/testing/src/integration_three.rs deleted file mode 100644 index 1373b32..0000000 --- a/examples/testing/src/integration_three.rs +++ /dev/null @@ -1,21 +0,0 @@ -// -// #[test] -// fn test() { -// let srv = TestServer::build_with_state(|| { -// // 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} -// }) - -// // register server handlers and start test server -// .start(|app| { -// app.resource( -// "/{username}/index.html", |r| r.with( -// |p: Path| format!("Welcome {}!", p.username))); -// }); -// // now we can run our test code -// ); -// diff --git a/examples/testing/src/integration_two.rs b/examples/testing/src/integration_two.rs index b5920f7..0c5e164 100644 --- a/examples/testing/src/integration_two.rs +++ b/examples/testing/src/integration_two.rs @@ -1,21 +1,33 @@ +use actix_web::{web, HttpResponse, Responder}; +use serde::{Deserialize, Serialize}; + +#[derive(Deserialize, Serialize, Debug)] +struct AppState { + count: i32, +} + +#[allow(dead_code)] +fn index(data: web::Data) -> impl Responder { + HttpResponse::Ok().json(data.get_ref()) +} + // -// use actix_web::{http, test, App, HttpRequest, HttpResponse}; +#[cfg(test)] +mod tests { + use super::*; + use actix_web::{test, web, App}; -// fn index(req: &HttpRequest) -> HttpResponse { -// HttpResponse::Ok().into() -// } + #[test] + fn test_index_get() { + let mut app = test::init_service( + App::new() + .data(AppState { count: 4 }) + .route("/", web::get().to(index)), + ); + let req = test::TestRequest::get().uri("/").to_request(); + let resp: AppState = test::read_response_json(&mut app, req); -// /// 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); - -// let request = srv.client(http::Method::GET, "/test").finish().unwrap(); -// let response = srv.execute(request.send()).unwrap(); - -// assert!(response.status().is_success()); -// } + assert!(resp.count == 4); + } +} // diff --git a/examples/testing/src/main.rs b/examples/testing/src/main.rs index 82b8bc4..f1780fb 100644 --- a/examples/testing/src/main.rs +++ b/examples/testing/src/main.rs @@ -1,10 +1,7 @@ -mod integration_one; -mod integration_three; -mod integration_two; -mod stream_response; -mod websockets; -// -use actix_web::{http, test, HttpRequest, HttpResponse}; +pub mod integration_one; +pub mod integration_two; +pub mod stream_response; +use actix_web::{http, web, App, HttpRequest, HttpResponse}; fn index(req: HttpRequest) -> HttpResponse { if let Some(hdr) = req.headers().get(http::header::CONTENT_TYPE) { @@ -16,14 +13,29 @@ fn index(req: HttpRequest) -> HttpResponse { } fn main() { - let req = - test::TestRequest::with_header("content-type", "text/plain").to_http_request(); + App::new().route("/", web::get().to(index)); +} - let resp = test::block_on(index(req)).unwrap(); - assert_eq!(resp.status(), http::StatusCode::OK); +// +#[cfg(test)] +mod tests { + use super::*; + use actix_web::test; - let req = test::TestRequest::default().to_http_request(); - let resp = test::block_on(index(req)).unwrap(); - assert_eq!(resp.status(), http::StatusCode::BAD_REQUEST); + #[test] + fn test_index_ok() { + let req = test::TestRequest::with_header("content-type", "text/plain") + .to_http_request(); + + let resp = test::block_on(index(req)).unwrap(); + assert_eq!(resp.status(), http::StatusCode::OK); + } + + #[test] + fn test_index_not_ok() { + let req = test::TestRequest::default().to_http_request(); + let resp = test::block_on(index(req)).unwrap(); + assert_eq!(resp.status(), http::StatusCode::BAD_REQUEST); + } } // diff --git a/examples/testing/src/stream_response.rs b/examples/testing/src/stream_response.rs index 9fea603..f922e05 100644 --- a/examples/testing/src/stream_response.rs +++ b/examples/testing/src/stream_response.rs @@ -1,50 +1,49 @@ // -// use bytes::Bytes; -// use futures::stream::poll_fn; -// use futures::{Async, Poll, Stream}; +use bytes::Bytes; +use futures::stream::poll_fn; +use futures::{Async, Poll}; -// use actix_web::http::{ContentEncoding, StatusCode}; -// use actix_web::test::TestServer; -// use actix_web::{Error, HttpRequest, HttpResponse}; +use actix_web::http::{ContentEncoding, StatusCode}; +use actix_web::{middleware::BodyEncoding, web, App, Error, HttpRequest, HttpResponse}; -// fn sse(_req: &HttpRequest) -> HttpResponse { -// let mut counter = 5usize; -// // yields `data: N` where N in [5; 1] -// let server_events = poll_fn(move || -> Poll, Error> { -// if counter == 0 { -// return Ok(Async::Ready(None)); -// } -// let payload = format!("data: {}\n\n", counter); -// counter -= 1; -// Ok(Async::Ready(Some(Bytes::from(payload)))) -// }); +fn sse(_req: HttpRequest) -> HttpResponse { + let mut counter: usize = 5; -// HttpResponse::build(StatusCode::OK) -// .content_encoding(ContentEncoding::Identity) -// .content_type("text/event-stream") -// .streaming(server_events) -// } + // yields `data: N` where N in [5; 1] + let server_events = poll_fn(move || -> Poll, Error> { + if counter == 0 { + return Ok(Async::Ready(None)); + } + let payload = format!("data: {}\n\n", counter); + counter -= 1; + Ok(Async::Ready(Some(Bytes::from(payload)))) + }); -// fn main() { -// // start new test server -// let mut srv = TestServer::new(|app| app.handler(sse)); + HttpResponse::build(StatusCode::OK) + .encoding(ContentEncoding::Identity) + .content_type("text/event-stream") + .streaming(server_events) +} -// // request stream -// let request = srv.get().finish().unwrap(); -// let response = srv.execute(request.send()).unwrap(); -// assert!(response.status().is_success()); +pub fn main() { + App::new().route("/", web::get().to(sse)); +} -// // convert ClientResponse to future, start read body and wait first chunk -// let mut stream = response.payload(); -// loop { -// match srv.execute(stream.into_future()) { -// Ok((Some(bytes), remain)) => { -// println!("{:?}", bytes); -// stream = remain -// } -// Ok((None, _)) => break, -// Err(_) => panic!(), -// } -// } -// } +#[cfg(test)] +mod tests { + use super::*; + use actix_web::{test, web, App}; + + #[test] + fn test_stream() { + let mut app = test::init_service(App::new().route("/", web::get().to(sse))); + let req = test::TestRequest::get().to_request(); + let resp = test::read_response(&mut app, req); + assert!( + resp == Bytes::from_static( + b"data: 5\n\ndata: 4\n\ndata: 3\n\ndata: 2\n\ndata: 1\n\n" + ) + ); + } +} // diff --git a/examples/testing/src/websockets.rs b/examples/testing/src/websockets.rs deleted file mode 100644 index 8034116..0000000 --- a/examples/testing/src/websockets.rs +++ /dev/null @@ -1,30 +0,0 @@ -// -use actix::{Actor, StreamHandler}; -use actix_web::*; -use futures::Stream; - -struct Ws; // <- WebSocket actor - -impl Actor for Ws { - type Context = ws::WebsocketContext; -} - -impl StreamHandler 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(|app| app.handler(|req| ws::start(req, Ws))); - - let (reader, mut writer) = srv.ws().unwrap(); - writer.text("text"); - - let (item, reader) = srv.execute(reader.into_future()).unwrap(); - assert_eq!(item, Some(ws::Message::Text("text".to_owned()))); -} -// From 6b08c4664b6793609ad70d689aba4edc8f94f4b5 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Mon, 24 Jun 2019 21:18:30 -0400 Subject: [PATCH 54/68] Errors section is done-ish. --- content/docs/errors.md | 24 ++++++++++++------------ examples/errors/Cargo.toml | 2 ++ examples/errors/src/helpers.rs | 11 +++++++++-- examples/errors/src/main.rs | 15 ++++++++++++--- examples/errors/src/override_error.rs | 21 +++++++++++++++------ examples/errors/src/recommend_one.rs | 17 +++++++++++------ examples/errors/src/recommend_two.rs | 22 ++++++++++++++++------ 7 files changed, 77 insertions(+), 35 deletions(-) diff --git a/content/docs/errors.md b/content/docs/errors.md index ace3a4c..25c30d1 100644 --- a/content/docs/errors.md +++ b/content/docs/errors.md @@ -6,13 +6,13 @@ weight: 180 # Errors -Actix uses its own [`actix_web::error::Error`][actixerror] type and +Actix-web uses its own [`actix_web::error::Error`][actixerror] type and [`actix_web::error::ResponseError`][responseerror] trait for error handling from web handlers. If a handler returns an `Error` (referring to the [general Rust trait `std::error::Error`][stderror]) in a `Result` that also implements the -`ResponseError` trait, actix will render that error as an HTTP response. +`ResponseError` trait, actix-web will render that error as an HTTP response. `ResponseError` has a single function called `error_response()` that returns `HttpResponse`: @@ -30,7 +30,7 @@ A `Responder` coerces compatible `Result`s into HTTP responses: impl> Responder for Result ``` -`Error` in the code above is actix's error definition, and any errors that +`Error` in the code above is actix-web's error definition, and any errors that implement `ResponseError` can be converted to one automatically. Actix-web provides `ResponseError` implementations for some common non-actix @@ -45,8 +45,8 @@ fn index(req: &HttpRequest) -> io::Result { } ``` -See [the actix-web API documentation][responseerrorimpls] for a full list of -foreign implementations for `ResponseError`. +See [the actix-web API documentation][responseerrorimpls] for a full list of foreign +implementations for `ResponseError`. ## An example of a custom error response @@ -64,15 +64,15 @@ Override `error_response()` to produce more useful results: # Error helpers -Actix provides a set of error helper functions that are useful for generating +Actix-web provides a set of error helper functions that are useful for generating specific HTTP error codes from other errors. Here we convert `MyError`, which doesn't implement the `ResponseError` trait, to a *400* (bad request) using `map_err`: {{< include-example example="errors" file="helpers.rs" section="helpers" >}} -See the [API documentation for actix-web's `error` module][errorhelpers] for a -full list of available error helpers. +See the [API documentation for actix-web's `error` module][actixerror] +for a full list of available error helpers. # Compatibility with failure @@ -128,9 +128,9 @@ By dividing errors into those which are user facing and those which are not, we can ensure that we don't accidentally expose users to errors thrown by application internals which they weren't meant to see. -[actixerror]: ../../actix-web/actix_web/error/struct.Error.html -[errorhelpers]: ../../actix-web/actix_web/error/index.html#functions +[actixerror]: https://docs.rs/actix-web/1.0.2/actix_web/error/struct.Error.html +[errorhelpers]: https://docs.rs/actix-web/1.0.2/actix_web/trait.ResponseError.html [failure]: https://github.com/rust-lang-nursery/failure -[responseerror]: ../../actix-web/actix_web/error/trait.ResponseError.html -[responseerrorimpls]: ../../actix-web/actix_web/error/trait.ResponseError.html#foreign-impls +[responseerror]: https://docs.rs/actix-web/1.0.2/actix_web/error/trait.ResponseError.html +[responseerrorimpls]: https://docs.rs/actix-web/1.0.2/actix_web/error/trait.ResponseError.html#foreign-impls [stderror]: https://doc.rust-lang.org/std/error/trait.Error.html diff --git a/examples/errors/Cargo.toml b/examples/errors/Cargo.toml index cb2e9c0..6fcbcbd 100644 --- a/examples/errors/Cargo.toml +++ b/examples/errors/Cargo.toml @@ -6,3 +6,5 @@ edition = "2018" [dependencies] actix-web = "1.0" failure = "0.1" +env_logger = "0.6" +log = "0.4" diff --git a/examples/errors/src/helpers.rs b/examples/errors/src/helpers.rs index bbdb0be..17da403 100644 --- a/examples/errors/src/helpers.rs +++ b/examples/errors/src/helpers.rs @@ -8,11 +8,18 @@ struct MyError { } pub fn index(_req: HttpRequest) -> Result<&'static str> { - let result: Result<&'static str, MyError> = Err(MyError { name: "test" }); + let result: Result<&'static str, MyError> = Err(MyError { name: "test error" }); Ok(result.map_err(|e| error::ErrorBadRequest(e.name))?) } // + pub fn main() { - App::new().route("/", web::get().to(index)); + use actix_web::HttpServer; + + HttpServer::new(|| App::new().route("/", web::get().to(index))) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } diff --git a/examples/errors/src/main.rs b/examples/errors/src/main.rs index 637cda4..0f46d09 100644 --- a/examples/errors/src/main.rs +++ b/examples/errors/src/main.rs @@ -1,9 +1,10 @@ pub mod helpers; pub mod override_error; pub mod recommend_one; -use actix_web::{web, App}; +pub mod recommend_two; + // -use actix_web::{error, HttpRequest}; +use actix_web::{error, HttpRequest, Result}; use failure::Fail; #[derive(Fail, Debug)] @@ -19,6 +20,14 @@ fn index(_req: HttpRequest) -> Result<&'static str, MyError> { Err(MyError { name: "test" }) } // + pub fn main() { - App::new().route("/", web::get().to(index)); + // use actix_web::{web, App, HttpServer}; + + // HttpServer::new(|| App::new().route("/", web::get().to(index))) + // .bind("127.0.0.1:8088") + // .unwrap() + // .run() + // .unwrap(); + recommend_two::main(); } diff --git a/examples/errors/src/override_error.rs b/examples/errors/src/override_error.rs index 98870ac..10da432 100644 --- a/examples/errors/src/override_error.rs +++ b/examples/errors/src/override_error.rs @@ -29,12 +29,6 @@ fn index(_req: HttpRequest) -> Result<&'static str, MyError> { Err(MyError::BadClientData) } // -pub fn main() { - App::new() - .route("/", web::get().to(index)) - .route("/e2", web::get().to(error2)) - .route("/e3", web::get().to(error3)); -} fn error2(_req: HttpRequest) -> Result<&'static str, MyError> { Err(MyError::InternalError) @@ -43,3 +37,18 @@ fn error2(_req: HttpRequest) -> Result<&'static str, MyError> { fn error3(_req: HttpRequest) -> Result<&'static str, MyError> { Err(MyError::Timeout) } + +pub fn main() { + use actix_web::HttpServer; + + HttpServer::new(|| { + App::new() + .route("/", web::get().to(index)) + .route("/e2", web::get().to(error2)) + .route("/e3", web::get().to(error3)) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); +} diff --git a/examples/errors/src/recommend_one.rs b/examples/errors/src/recommend_one.rs index c88048e..5e8e4f2 100644 --- a/examples/errors/src/recommend_one.rs +++ b/examples/errors/src/recommend_one.rs @@ -1,4 +1,3 @@ -use actix_web::{web, App, HttpRequest}; // use actix_web::{error, http, HttpResponse}; use failure::Fail; @@ -19,12 +18,18 @@ impl error::ResponseError for UserError { } } // -pub fn main() { - App::new().route("/", web::get().to(index)); -} - -fn index(_req: HttpRequest) -> Result<&'static str, UserError> { +fn index() -> Result<&'static str, UserError> { Err(UserError::ValidationError { field: "bad stuff".to_string(), }) } + +pub fn main() { + use actix_web::{web, App, HttpServer}; + + HttpServer::new(|| App::new().route("/", web::get().to(index))) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); +} diff --git a/examples/errors/src/recommend_two.rs b/examples/errors/src/recommend_two.rs index e587d32..cbb34de 100644 --- a/examples/errors/src/recommend_two.rs +++ b/examples/errors/src/recommend_two.rs @@ -1,6 +1,5 @@ -use actix_web::App; // -use actix_web::{error, fs, http, HttpRequest, HttpResponse}; +use actix_web::{error, http, HttpResponse}; use failure::Fail; #[derive(Fail, Debug)] @@ -19,11 +18,22 @@ impl error::ResponseError for UserError { } } -fn index(_req: HttpRequest) -> Result<&'static str, UserError> { - fs::NamedFile::open("static/index.html").map_err(|_e| UserError::InternalError)?; +fn index() -> Result<&'static str, UserError> { + do_thing_that_failes().map_err(|_e| UserError::InternalError)?; Ok("success!") } // -pub fn main() { - App::new().route("/", web::get().to(index)); + +fn do_thing_that_failes() -> Result<(), std::io::Error> { + Err(std::io::Error::new(std::io::ErrorKind::Other, "some error")) +} + +pub fn main() { + use actix_web::{web, App, HttpServer}; + + HttpServer::new(|| App::new().route("/", web::get().to(index))) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } From b9c78c1a581681cdc22410ceeb76a1a06d626e01 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Mon, 24 Jun 2019 23:36:32 -0400 Subject: [PATCH 55/68] All links in markdown are now footnotes for easier updating. --- content/docs/_index.md | 19 +++-- content/docs/application.md | 33 ++++---- content/docs/autoreload.md | 19 +++-- content/docs/databases.md | 8 +- content/docs/extractors.md | 74 +++++++++-------- content/docs/getting-started.md | 4 +- content/docs/handlers.md | 45 +++++----- content/docs/http2.md | 21 +++-- content/docs/installation.md | 25 +++--- content/docs/middleware.md | 53 ++++++------ content/docs/request.md | 30 +++---- content/docs/response.md | 7 +- content/docs/sentry.md | 17 ++-- content/docs/server.md | 78 +++++++++--------- content/docs/static-files.md | 11 +-- content/docs/testing.md | 21 ++--- content/docs/url-dispatch.md | 140 ++++++++++++++++---------------- content/docs/websockets.md | 13 +-- 18 files changed, 325 insertions(+), 293 deletions(-) diff --git a/content/docs/_index.md b/content/docs/_index.md index a8622d4..8b2e33b 100644 --- a/content/docs/_index.md +++ b/content/docs/_index.md @@ -12,13 +12,16 @@ weight: 10 Actix is your door to developing web services with Rust and this documentation is going to guide you. -This documentation currently covers mostly the `actix-web` part which is the -high level web framework previously built on top of the `actix` actor framework and the -[Tokio](https://tokio.rs/) async IO system. This is the part that is from an -API stability point of view the most stable. +This documentation currently covers mostly the `actix-web` part which is the high level +web framework previously built on top of the `actix` actor framework and the [Tokio][tokio] +async IO system. This is the part that is from an API stability point of view the most stable. If you haven't used `actix-web` yet it's best to start with the [getting started -guide](getting-started/). If you already know your ways around and you need -specific information you might want to read the [actix-web API -docs](https://docs.rs/actix-web) (or the lower level [actix API -docs](https://docs.rs/actix)). +guide][gettingstarted]. If you already know your ways around and you need +specific information you might want to read the [actix-web API docs][actixwebdocs] +(or the lower level [actix API docs][actixdocs]). + +[gettingstarted]: ./getting-started +[actixwebdocs]: https://docs.rs/actix-web +[actixdocs]: https://docs.rs/actix +[tokio]: (https://tokio.rs/) diff --git a/content/docs/application.md b/content/docs/application.md index 80eb660..9da0f0c 100644 --- a/content/docs/application.md +++ b/content/docs/application.md @@ -28,8 +28,7 @@ it is automatically inserted. The prefix should consist of value path segments. 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](/docs/url-dispatch/index.html#using-an-application-prefix-to-compose-applications) section. +> For more information, check the [URL Dispatch][usingappprefix] section. Multiple application scopes can be served with one server: @@ -61,9 +60,8 @@ When the app is initialized it needs to be passed the initial state: > instance. `HttpServer` constructs an application instance for each thread, thus > application state must be constructed multiple times. If you want to share state between > different threads, a shared object should be used, e.g. `Arc`. There is also an -> [Example](https://github.com/actix/examples/blob/master/state/src/main.rs) using `Arc` -> for this. Application state does not need to be `Send` and `Sync`, -> but the application factory must be `Send` + `Sync`. +> [Example][stateexample] using `Arc` for this. Application state does not need to be +> `Send` and `Sync`, but the application factory must be `Send` + `Sync`. To start the previous app, create it into a closure: @@ -77,11 +75,10 @@ Combining multiple applications with different state is possible as well. ## Using an Application Scope to Compose Applications -The `web::scope()` method allows to set a specific application prefix. -This scope 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. +The `web::scope()` method allows to set a specific application prefix. This scope 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: @@ -97,13 +94,11 @@ it will generate a URL with that same path. You can think of a guard as a simple function that accepts a *request* object reference and returns *true* or *false*. Formally, a guard is any object that implements the -[`Guard`](https://docs.rs/actix-web/1.0.2/actix_web/guard/trait.Guard.html) trait. Actix-web -provides several guards, you can check -[functions section](https://docs.rs/actix-web/1.0.2/actix_web/guard/index.html#functions) -of api docs. +[`Guard`][guardtrait] trait. Actix-web provides several guards, you can check +[functions section][guardfuncs] of api docs. -One of the provided guards is [`Header`](https://docs.rs/actix-web/1.0.2/actix_web/guard/fn.Header.html), -it can be used as application's filter based on request's header information. +One of the provided guards is [`Header`][guardheader], it can be used as application's +filter based on request's header information. {{< include-example example="application" file="vh.rs" section="vh" >}} @@ -125,3 +120,9 @@ The result of the above example would be: ``` Each `ServiceConfig` can have it's own `data`, `routes`, and `services` + +[usingappprefix]: /docs/url-dispatch/index.html#using-an-application-prefix-to-compose-applications +[stateexample]: https://github.com/actix/examples/blob/master/state/src/main.rs +[guardtrait]: https://docs.rs/actix-web/1.0.2/actix_web/guard/trait.Guard.html +[guardfuncs]: https://docs.rs/actix-web/1.0.2/actix_web/guard/index.html#functions +[guardheader]: ((https://docs.rs/actix-web/1.0.2/actix_web/guard/fn.Header.html diff --git a/content/docs/autoreload.md b/content/docs/autoreload.md index f1f0902..0ec49dd 100644 --- a/content/docs/autoreload.md +++ b/content/docs/autoreload.md @@ -6,13 +6,11 @@ weight: 1000 # Auto-Reloading Development Server -During development it can be very handy to have cargo automatically recompile -the code on change. This can be accomplished by using -[cargo-watch](https://github.com/passcod/cargo-watch). Because an actix app -will typically bind to a port for listening for incoming HTTP requests it makes -sense to combine this with the [listenfd](https://crates.io/crates/listenfd) -crate and the [systemfd](https://github.com/mitsuhiko/systemfd) utility to -ensure the socket is kept open while the app is compiling and reloading. +During development it can be very handy to have cargo automatically recompile the code +on change. This can be accomplished by using [cargo-watch][cargowatch]. Because an +actix app will typically bind to a port for listening for incoming HTTP requests it makes +sense to combine this with the [listenfd][listenfd] crate and the [systemfd][systemfd] +utility to ensure the socket is kept open while the app is compiling and reloading. `systemfd` will open a socket and pass it to `cargo-watch` which will watch for changes and then invoke the compiler and run your actix app. The actix app @@ -30,8 +28,7 @@ cargo install systemfd cargo-watch ## Code Changes Additionally you need to slightly modify your actix app so that it can pick up -an external socket opened by `systemfd`. Add the listenfd dependency to your -app: +an external socket opened by `systemfd`. Add the listenfd dependency to your app: ```ini [dependencies] @@ -49,3 +46,7 @@ To now run the development server invoke this command: ``` systemfd --no-pid -s http::3000 -- cargo watch -x run ``` + +[cargowatch]: https://github.com/passcod/cargo-watch +[listenfd]: https://crates.io/crates/listenfd +[systemfd]: https://github.com/mitsuhiko/systemfd diff --git a/content/docs/databases.md b/content/docs/databases.md index e7df061..a453a65 100644 --- a/content/docs/databases.md +++ b/content/docs/databases.md @@ -39,8 +39,10 @@ thus, we receive the message response asynchronously. {{< include-example example="og_databases" file="main.rs" section="index" >}} -> A full example is available in the -> [examples directory](https://github.com/actix/examples/tree/master/diesel/). +> A full example is available in the [examples directory][examples]. > More information on sync actors can be found in the -> [actix documentation](https://docs.rs/actix/0.7.0/actix/sync/index.html). +> [actix documentation][actixdocs]. + +[examples]: https://github.com/actix/examples/tree/master/diesel/ +[actixdocs]: https://docs.rs/actix/0.7.0/actix/sync/index.html diff --git a/content/docs/extractors.md b/content/docs/extractors.md index 35a08ec..e77adfd 100644 --- a/content/docs/extractors.md +++ b/content/docs/extractors.md @@ -23,19 +23,18 @@ Option 2 - accessed by calling `extract()` on the Extractor # Path -[*Path*](https://docs.rs/actix-web/1.0.2/actix_web/dev/struct.Path.html) provides -information that can be extracted from the Request's path. You can deserialize any -variable segment from the path. +[*Path*][pathstruct] provides information that can be extracted from the Request's +path. You can deserialize any variable segment from the path. For instance, for resource that registered for the `/users/{userid}/{friend}` path -two segments could be deserialized, `userid` and `friend`. These segments -could be extracted into a `tuple`, i.e. `Path<(u32, String)>` or any structure -that implements the `Deserialize` trait from the *serde* crate. +two segments could be deserialized, `userid` and `friend`. These segments could be +extracted into a `tuple`, i.e. `Path<(u32, String)>` or any structure that implements +the `Deserialize` trait from the *serde* crate. {{< include-example example="extractors" file="path_one.rs" section="path-one" >}} -It is also possible to extract path information to a specific type that -implements the `Deserialize` trait from *serde*. Here is an equivalent example that uses *serde* +It is also possible to extract path information to a specific type that implements the +`Deserialize` trait from *serde*. Here is an equivalent example that uses *serde* instead of a *tuple* type. {{< include-example example="extractors" file="path_two.rs" section="path-two" >}} @@ -46,25 +45,24 @@ It is also possible to `get` or `query` the request for path parameters by name: # Query -The [*Query*](https://docs.rs/actix-web/1.0.2/actix_web/web/struct.Query.html) -type provides extraction functionality for the request's query parameters. Underneath it -uses *serde_urlencoded* crate. +The [*Query*][querystruct] type provides extraction functionality for the request's +query parameters. Underneath it uses *serde_urlencoded* crate. {{< include-example example="extractors" file="query.rs" section="query" >}} # Json -[*Json*](https://docs.rs/actix-web/1.0.2/actix_web/web/struct.Json.html) allows to deserialize -a request body into a struct. To extract typed information from a request's body, -the type `T` must implement the `Deserialize` trait from *serde*. +[*Json*][jsonstruct] allows to deserialize a request body into a struct. To extract +typed information from a request's body, the type `T` must implement the `Deserialize` +trait from *serde*. {{< include-example example="extractors" file="json_one.rs" section="json-one" >}} Some extractors provide a way to configure the extraction process. Json extractor -[*JsonConfig*](https://docs.rs/actix-web/1.0.2/actix_web/web/struct.JsonConfig.html) type -for configuration. To configure an extractor, pass it's configuration object to the resource's -`.data()` method. In case of a *Json* extractor it returns a *JsonConfig*. You can -configure the maximum size of the json payload as well as a custom error handler function. +[*JsonConfig*][jsonconfig] type for configuration. To configure an extractor, pass it's +configuration object to the resource's `.data()` method. In case of a *Json* extractor +it returns a *JsonConfig*. You can configure the maximum size of the json payload as +well as a custom error handler function. The following example limits the size of the payload to 4kb and uses a custom error handler. @@ -72,19 +70,18 @@ The following example limits the size of the payload to 4kb and uses a custom er # Form -At the moment only url-encoded forms are supported. The url-encoded body -could be extracted to a specific type. This type must implement -the `Deserialize` trait from the *serde* crate. +At the moment only url-encoded forms are supported. The url-encoded body could be +extracted to a specific type. This type must implement the `Deserialize` trait from +the *serde* crate. -[*FormConfig*](https://docs.rs/actix-web/1.0.2/actix_web/web/struct.FormConfig.html) allows -configuring the extraction process. +[*FormConfig*][formconfig] allows configuring the extraction process. {{< include-example example="extractors" file="form.rs" section="form" >}} # Multiple extractors -Actix-web provides extractor implementations for tuples (up to 10 elements) -whose elements implement `FromRequest`. +Actix-web provides extractor implementations for tuples (up to 10 elements) whose +elements implement `FromRequest`. For example we can use a path extractor and a query extractor at the same time. @@ -94,18 +91,16 @@ For example we can use a path extractor and a query extractor at the same time. Actix-web also provides several other extractors: -* [*Data*](https://docs.rs/actix-web/1.0.2/actix_web/web/struct.Data.html) - If you need - access to an application state. -* *HttpRequest* - *HttpRequest* itself is an extractor which returns self, - in case you need access to the request. -* *String* - You can convert a request's payload to a *String*. - [*Example*](https://docs.rs/actix-web/1.0.2/actix_web/trait.FromRequest.html#example-2) +* [*Data*][datastruct] - If you need access to an application state. +* *HttpRequest* - *HttpRequest* itself is an extractor which returns self, in case you + need access to the request. +* *String* - You can convert a request's payload to a *String*. [*Example*][stringexample] is available in doc strings. * *bytes::Bytes* - You can convert a request's payload into *Bytes*. - [*Example*](https://docs.rs/actix-web/1.0.2/actix_web/trait.FromRequest.html#example-4) + [*Example*][bytesexample] is available in doc strings. * *Payload* - You can access a request's payload. - [*Example*](https://docs.rs/actix-web/1.0.2/actix_web/web/struct.Payload.html) + [*Example*][payloadexample] # Async Data Access @@ -130,4 +125,15 @@ number of requests processed per thread. A proper implementation would use `Arc` > Be careful with synchronization primitives like `Mutex` or `RwLock`. The `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. +> from multiple threads, consider using the [actix][actix] actor system. + +[pathstruct]: (https://docs.rs/actix-web/1.0.2/actix_web/dev/struct.Path.html +[querystruct]: https://docs.rs/actix-web/1.0.2/actix_web/web/struct.Query.html +[jsonstruct]: https://docs.rs/actix-web/1.0.2/actix_web/web/struct.Json.html +[jsonconfig]: https://docs.rs/actix-web/1.0.2/actix_web/web/struct.JsonConfig.html +[formconfig]: https://docs.rs/actix-web/1.0.2/actix_web/web/struct.FormConfig.html +[datastruct]: https://docs.rs/actix-web/1.0.2/actix_web/web/struct.Data.html +[stringexample]: https://docs.rs/actix-web/1.0.2/actix_web/trait.FromRequest.html#example-2 +[bytesexample]: https://docs.rs/actix-web/1.0.2/actix_web/trait.FromRequest.html#example-4 +[payloadexample]: https://docs.rs/actix-web/1.0.2/actix_web/web/struct.Payload.html +[actix]: https://actix.github.io/actix/actix/ diff --git a/content/docs/getting-started.md b/content/docs/getting-started.md index a4fe727..3472e27 100644 --- a/content/docs/getting-started.md +++ b/content/docs/getting-started.md @@ -45,4 +45,6 @@ Head over to ``http://localhost:8088/`` to see the results. If you want, you can have an automatic reloading server during development that recompiles on demand. To see how this can be accomplished have a look -at the [autoreload pattern](../autoreload/). +at the [autoreload pattern][autoload]. + +[autoload]: ../autoreload/ diff --git a/content/docs/handlers.md b/content/docs/handlers.md index 699adf7..ac00ffd 100644 --- a/content/docs/handlers.md +++ b/content/docs/handlers.md @@ -7,22 +7,17 @@ weight: 160 # Request Handlers A request handler is a function that accepts zero or more parameters that can be extracted -from a request (ie, -[*impl FromRequest*](https://docs.rs/actix-web/1.0.2/actix_web/trait.FromRequest.html)) -and returns a type that can be converted into an HttpResponse (ie, -[*impl Responder*](https://docs.rs/actix-web/1.0.2/actix_web/trait.Responder.html)). +from a request (ie, [*impl FromRequest*][implfromrequest]) and returns a type that can +be converted into an HttpResponse (ie, [*impl Responder*][implresponder]). -Request handling happens in two stages. First the handler object is called, -returning any object that implements the -[*Responder*](https://docs.rs/actix-web/1.0.2/actix_web/trait.Responder.html) trait. -Then, `respond_to()` is called on the returned object, converting itself to a `HttpResponse` -or `Error`. +Request handling happens in two stages. First the handler object is called, returning any +object that implements the [*Responder*][respondertrait] trait. Then, `respond_to()` is +called on the returned object, converting itself to a `HttpResponse` or `Error`. -By default actix provides `Responder` implementations for some standard types, +By default actix-web provides `Responder` implementations for some standard types, such as `&'static str`, `String`, etc. -> For a complete list of implementations, check -> [*Responder documentation*](../../actix-web/actix_web/trait.Responder.html#foreign-impls). +> For a complete list of implementations, check [*Responder documentation*][responderimpls]. Examples of valid handlers: @@ -64,31 +59,37 @@ Let's create a response for a custom type that serializes to an `application/jso ## 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/actix_web/trait.Responder.html) trait. +or more precisely, any type that implements the [*Responder*][respondertrait] trait. In this case, the handler must return a `Future` object that resolves to the *Responder* type, i.e: {{< include-example example="async-handlers" file="main.rs" section="async-responder" >}} -Or the response body can be generated asynchronously. In this case, body -must implement the stream trait `Stream`, i.e: +Or the response body can be generated asynchronously. In this case, body must implement +the stream trait `Stream`, i.e: {{< include-example example="async-handlers" file="stream.rs" section="stream" >}} 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`. +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`. {{< include-example example="async-handlers" file="async_stream.rs" section="async-stream" >}} ## 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. +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/actix_web/enum.Either.html) type can be used. -`Either` allows combining two different responder types into a single type. +For this case, the [*Either*][either] type can be used. `Either` allows combining two +different responder types into a single type. {{< include-example example="either" file="main.rs" section="either" >}} + +[implfromrequest]: https://docs.rs/actix-web/1.0.2/actix_web/trait.FromRequest.html +[implresponder]: https://docs.rs/actix-web/1.0.2/actix_web/trait.Responder.html +[respondertrait]: https://docs.rs/actix-web/1.0.2/actix_web/trait.Responder.html +[responderimpls]: ../../actix-web/actix_web/trait.Responder.html#foreign-impls +[either]: ../../actix-web/actix_web/enum.Either.html diff --git a/content/docs/http2.md b/content/docs/http2.md index 2d7dfe1..3c257c9 100644 --- a/content/docs/http2.md +++ b/content/docs/http2.md @@ -8,13 +8,12 @@ weight: 250 # Negotiation -*HTTP/2.0* protocol over tls without prior knowledge requires -[tls alpn](https://tools.ietf.org/html/rfc7301). +*HTTP/2.0* protocol over tls without prior knowledge requires [tls alpn][tlsalpn]. > Currently, only `rust-openssl` has support. `alpn` negotiation requires enabling the feature. When enabled, `HttpServer` provides the -[bind_ssl](../../actix-web/actix_web/server/struct.HttpServer.html#method.serve_tls) method. +[bind_ssl][bindssl] method. ```toml [dependencies] @@ -23,10 +22,14 @@ openssl = { version = "0.10", features = ["v110"] } ``` {{< include-example example="http2" file="main.rs" section="main" >}} -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) +Upgrades to *HTTP/2.0* schema described in [rfc section 3.2][rfcsection32] is not +supported. Starting *HTTP/2* with prior knowledge is supported for both clear text +connection and tls connection. [rfc section 3.4][rfcsection34]. -> Check out [examples/tls](https://github.com/actix/examples/tree/master/tls) -> for a concrete example. +> Check out [examples/tls][examples] for a concrete example. + +[rfcsection32]: https://http2.github.io/http2-spec/#rfc.section.3.2 +[rfcsection34]: https://http2.github.io/http2-spec/#rfc.section.3.4 +[bindssl]: ../../actix-web/actix_web/server/struct.HttpServer.html#method.serve_tls +[tlsalpn]: https://tools.ietf.org/html/rfc7301 +[examples]: https://github.com/actix/examples/tree/master/tls diff --git a/content/docs/installation.md b/content/docs/installation.md index 964663c..8e41323 100644 --- a/content/docs/installation.md +++ b/content/docs/installation.md @@ -6,16 +6,13 @@ weight: 110 # Installing Rust -Since `actix-web` is a Rust framework you will need Rust to get started with it. -If you don't have it yet we recommend you use `rustup` to manage your Rust -installation. The [official rust -guide](https://doc.rust-lang.org/book/ch01-01-installation.html) -has a wonderful section on getting started. +Since `actix-web` is a Rust framework you will need Rust to get started with it. If you +don't have it yet we recommend you use `rustup` to manage your Rust installation. The +[official rust guide][rustguide] has a wonderful section on getting started. -We currently require at least Rust {{< rust-version "actix-web" >}} so make sure you -run `rustup update` to have the latest and greatest Rust version available. In -particular this guide will assume that you actually run Rust -{{< rust-version "actix-web" >}} or later. +We currently require at least Rust {{< rust-version "actix-web" >}} so make sure you run +`rustup update` to have the latest and greatest Rust version available. In particular +this guide will assume that you actually run Rust {{< rust-version "actix-web" >}} or later. # Installing `actix-web` @@ -40,10 +37,9 @@ actix-web = { git = "https://github.com/actix/actix-web" } # Diving In -There are two paths you can take here. You can follow the guide along or if -you are very impatient you might want to have a look at our -[extensive example repository](https://github.com/actix/examples) and run the -included examples. Here for instance is how you run the included `basics` +There are two paths you can take here. You can follow the guide along or if you are very +impatient you might want to have a look at our [extensive example repository][exmaples] +and run the included examples. Here for instance is how you run the included `basics` example: ``` @@ -51,3 +47,6 @@ git clone https://github.com/actix/examples cd examples/basics cargo run ``` + +[rustguide]: https://doc.rust-lang.org/book/ch01-01-installation.html +[examples]: https://github.com/actix/examples diff --git a/content/docs/middleware.md b/content/docs/middleware.md index 0a1c853..ef02106 100644 --- a/content/docs/middleware.md +++ b/content/docs/middleware.md @@ -19,12 +19,10 @@ Typically, middleware is involved in the following actions: * 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 -[*Service trait*](../../actix-web/actix_web/dev/trait.Service.html) and -[*Transform trait*](../../actix-web/actix_web/dev/trait.Transform.html). -Each method in the traits has a default implementation. Each method can return -a result immediately or a *future* object. +Middleware is registered for each application and executed in same order as registration. +In general, a *middleware* is a type that implements the [*Service trait*][servicetrait] and +[*Transform trait*][transformtrait]. Each method in the traits has a default +implementation. Each method can return a result immediately or a *future* object. The following demonstrates creating a simple middleware: @@ -39,7 +37,7 @@ It is common to register a logging middleware as the first middleware for the ap 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/) +for *actix_web* package to see access log ([env_logger][envlogger] or similar). ## Usage @@ -96,31 +94,30 @@ a specified header. ## User sessions -Actix provides a general solution for session management. The -[**actix-session**](https://docs.rs/actix-session/0.1.1/actix_session/) middleware can be -used with different backend types to store session data in different backends. +Actix provides a general solution for session management. The [**actix-session**][actixsession] +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. -[**CookieSession**](../../actix-web/actix_web/middleware/session/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. +[**CookieSession**][cookiesession] 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 `CookieSession` constructor. +A cookie may have a security policy of *signed* or *private*. Each has a respective +`CookieSession` 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. +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. +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 `CookieSession`. To access session data, -[*HttpRequest::session()*](../../actix-web/actix_web/middleware/session/trait.RequestSession.html#tymethod.session) - must be used. This method returns a -[*Session*](../../actix-web/actix_web/middleware/session/struct.Session.html) object, which allows us to get or set -session data. +In general, you create a `SessionStorage` middleware and initialize it with specific +backend implementation, such as a `CookieSession`. To access session data, +[*HttpRequest::session()*][requestsession] must be used. This method returns a +[*Session*][sessionobj] object, which allows us to get or set session data. {{< include-example example="middleware" file="user_sessions.rs" section="user-session" >}} @@ -134,3 +131,11 @@ one. The error handler can return a response immediately or return a future that into a response. {{< include-example example="middleware" file="errorhandler.rs" section="error-handler" >}} + +[sessionobj]: ../../actix-web/actix_web/middleware/session/struct.Session.html +[requestsession]: ../../actix-web/actix_web/middleware/session/trait.RequestSession.html#tymethod.session +[cookiesession]: ../../actix-web/actix_web/middleware/session/struct.CookieSessionBackend.html +[actixsession]: https://docs.rs/actix-session/0.1.1/actix_session/ +[envlogger]: https://docs.rs/env_logger/*/env_logger/ +[servicetrait]: ../../actix-web/actix_web/dev/trait.Service.html +[transformtrait]: ../../actix-web/actix_web/dev/trait.Transform.html diff --git a/content/docs/request.md b/content/docs/request.md index 35e3f79..31962f4 100644 --- a/content/docs/request.md +++ b/content/docs/request.md @@ -18,8 +18,7 @@ Actix automatically *decompresses* payloads. The following codecs are supported: * EncodingExt 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`. +according to the header value. Multiple codecs are not supported, i.e: `Content-Encoding: br, gzip`. # JSON Request @@ -39,8 +38,7 @@ body first and then deserialize the json into an object. {{< include-example example="requests" file="manual.rs" section="json-manual" >}} -> A complete example for both options is available in -> [examples directory](https://github.com/actix/examples/tree/master/json/). +> A complete example for both options is available in [examples directory][examples]. # Chunked transfer encoding @@ -51,26 +49,22 @@ compression codecs (br, gzip, deflate), then the byte stream is decompressed. # Multipart body Actix provides multipart stream support. -[*Multipart*](../../actix-web/actix_web/multipart/struct.Multipart.html) is implemented as -a stream of multipart items. Each item can be a -[*Field*](../../actix-web/actix_web/multipart/struct.Field.html) or a nested -*Multipart* stream.`HttpResponse::multipart()` returns the *Multipart* stream -for the current request. +[*Multipart*][multipartstruct] is implemented as a stream of multipart items. Each item +can be a [*Field*][fieldstruct] 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: {{< include-example example="requests" file="multipart.rs" section="multipart" >}} -> A full example is available in the -> [examples directory](https://github.com/actix/examples/tree/master/multipart/). +> A full example is available in the [examples directory][multipartexample]. # Urlencoded body Actix provides support for *application/x-www-form-urlencoded* encoded bodies. -`HttpResponse::urlencoded()` returns a -[*UrlEncoded*](../../actix-web/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*. +`HttpResponse::urlencoded()` returns a [*UrlEncoded*][urlencoder] 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: @@ -89,3 +83,9 @@ body payload. In the following example, we read and print the request payload chunk by chunk: {{< include-example example="requests" file="streaming.rs" section="streaming" >}} + +[examples]: https://github.com/actix/examples/tree/master/json/ +[multipartstruct]: ../../actix-web/actix_web/multipart/struct.Multipart.html +[fieldstruct]: ../../actix-web/actix_web/multipart/struct.Field.html +[multipartexample]: https://github.com/actix/examples/tree/master/multipart/ +[urlencoder]: ../../actix-web/actix_web/dev/struct.UrlEncoded.html diff --git a/content/docs/response.md b/content/docs/response.md index b890eb9..62f370d 100644 --- a/content/docs/response.md +++ b/content/docs/response.md @@ -10,8 +10,7 @@ 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/actix_web/dev/struct.HttpResponseBuilder.html) -> for type descriptions. +> Check the [documentation][responsebuilder] 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 @@ -21,7 +20,7 @@ builder instance multiple times, the builder will panic. # Content encoding -Actix automatically *compresses* payloads. The following codecs are supported: +Actix-web automatically *compresses* payloads. The following codecs are supported: * Brotli * Gzip @@ -75,3 +74,5 @@ is enabled automatically. > Enabling chunked encoding for *HTTP/2.0* responses is forbidden. {{< include-example example="responses" file="chunked.rs" section="chunked" >}} + +[responsebuilder]: ../../actix-web/actix_web/dev/struct.HttpResponseBuilder.html diff --git a/content/docs/sentry.md b/content/docs/sentry.md index 99f4384..813ddca 100644 --- a/content/docs/sentry.md +++ b/content/docs/sentry.md @@ -6,19 +6,18 @@ weight: 1020 # Sentry Crash Reporting -[Sentry](https://sentry.io/) is a crash reporting system that supports the -failure crate which is the base of the actix error reporting. With a -middleware it's possible to automatically report server errors to Sentry. +[Sentry][sentrysite] is a crash reporting system that supports the failure crate which +is the base of the actix error reporting. With a middleware it's possible to +automatically report server errors to Sentry. # Middleware This middleware captures any error in the server error range (500 - 599) and sends the attached error to sentry with its stacktrace. -To use the middleware the [sentry crate](https://crates.io/crates/sentry) needs to be -initialized and configured and the [sentry-actix middleware](https://crates.io/crates/sentry-actix) -needs to be added. Additionally it makes sense to also register the panic handler -to be informed about hard panics. +To use the middleware the [sentry crate][sentrycrate] needs to be initialized and configured +and the [sentry-actix middleware][sentrymiddleware] needs to be added. Additionally it +makes sense to also register the panic handler to be informed about hard panics. {{< include-example example="sentry" file="main.rs" section="middleware" >}} @@ -33,3 +32,7 @@ The hub can also be made current for the duration of a call. Then `Hub::current until the end of the `run` block. {{< include-example example="sentry" file="main.rs" section="hub2" >}} + +[sentrysite]: https://sentry.io/ +[sentrycrate]: https://crates.io/crates/sentry +[sentrymiddleware]: https://crates.io/crates/sentry-actix diff --git a/content/docs/server.md b/content/docs/server.md index 2208dca..6e65f69 100644 --- a/content/docs/server.md +++ b/content/docs/server.md @@ -6,22 +6,17 @@ weight: 150 # The HTTP Server -The [**HttpServer**](https://docs.rs/actix-web/1.0.2/actix_web/struct.HttpServer.html) type is responsible for -serving http requests. +The [**HttpServer**][httpserverstruct] 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. +`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()`](../../actix-web/actix_web/server/struct.HttpServer.html#method.bind) -must be used, and it may be called multiple times. To bind ssl socket, -[`bind_ssl()`](../../actix-web/actix_web/server/struct.HttpServer.html#method.bind_ssl) -or [`bind_rustls()`](../../actix-web/1.0.0/actix_web/struct.HttpServer.html#method.bind_rustls) -should be used. To start the http server, use one of the start methods. +To bind to a specific socket address, [`bind()`][bindmethod] must be used, and it may be +called multiple times. To bind ssl socket, [`bind_ssl()`][bindsslmethod] or +[`bind_rustls()`][bindrusttls] should be used. To start the http server, use one of the +start methods. -- use [`start()`](../../actix-web/actix_web/server/struct.HttpServer.html#method.start) -for a server +- use [`start()`] for a server {{< include-example example="server" section="main" >}} @@ -30,8 +25,8 @@ for a server > 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. Start method, e.g. `start()`, returns the -address of the started http server. It accepts several messages: +via a messaging system. Start method, e.g. `start()`, returns the address of the started +http server. It accepts several messages: - `PauseServer` - Pause accepting incoming connections - `ResumeServer` - Resume accepting incoming connections @@ -41,18 +36,16 @@ address of the started http server. It accepts several messages: ## Multi-threading -`HttpServer` automatically starts a 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::workers()`](../../actix-web/actix_web/server/struct.HttpServer.html#method.workers) method. +`HttpServer` automatically starts a 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::workers()`][workers] method. {{< include-example example="server" file="workers.rs" section="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`. +> Application state does not need to be `Send` and `Sync`, but factories must be `Send` + `Sync`. ## SSL @@ -66,18 +59,16 @@ actix-web = { version = "{{< actix-version "actix-web" >}}", features = ["ssl"] {{< include-example example="server" file="ssl.rs" section="ssl" >}} -> **Note**: the *HTTP/2.0* protocol requires -> [tls alpn](https://tools.ietf.org/html/rfc7301). +> **Note**: the *HTTP/2.0* protocol requires [tls alpn][tlsalpn]. > At the moment, only `openssl` has `alpn` support. -> For a full example, check out -> [examples/tls](https://github.com/actix/examples/tree/master/tls). +> For a full example, check out [examples/tls][exampletls]. To create the key.pem and cert.pem use the command. **Fill in your own subject** ```bash $ openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem \ -days 365 -sha256 -subj "/C=CN/ST=Fujian/L=Xiamen/O=TVlinux/OU=Org/CN=muro.lxd" ``` -To remove the password, then copy nopass.pem to key.pem +To remove the password, then copy nopass.pem to key.pem ```bash $ openssl rsa -in key.pem -out nopass.pem ``` @@ -94,10 +85,9 @@ Actix can wait for requests on a keep-alive connection. {{< include-example example="server" file="keep_alive.rs" section="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. +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*. @@ -109,22 +99,30 @@ defined by the request's http version. `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()`](../../actix-web/actix_web/server/struct.HttpServer.html#method.shutdown_timeout) method. +timeout are force-dropped. By default the shutdown timeout is set to 30 seconds. You +can change this parameter with the [`HttpServer::shutdown_timeout()`][shutdowntimeout] +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()`](../../actix-web/actix_web/server/struct.HttpServer.html#method.start) -method returns address of the server. +graceful shutdown or not. The [`start()`][startmethod] method returns address of the server. -`HttpServer` handles several OS signals. *CTRL-C* is available on all OSs, -other signals are available on unix systems. +`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()`](../../actix-web/actix_web/server/struct.HttpServer.html#method.disable_signals) -> method. +[`HttpServer::disable_signals()`][disablesignals] method. + +[httpserverstruct]: https://docs.rs/actix-web/1.0.2/actix_web/struct.HttpServer.html +[bindmethod]: ../../actix-web/actix_web/server/struct.HttpServer.html#method.bind +[bindsslmethod]: ../../actix-web/actix_web/server/struct.HttpServer.html#method.bind_ssl +[bindrusttls]: ../../actix-web/1.0.0/actix_web/struct.HttpServer.html#method.bind_rustls +[startmethod]: ../../actix-web/actix_web/server/struct.HttpServer.html#method.start +[workers]: ../../actix-web/actix_web/server/struct.HttpServer.html#method.workers +[tlsalpn]: https://tools.ietf.org/html/rfc7301 +[exampletls]: https://github.com/actix/examples/tree/master/tls +[shutdowntimeout]: ../../actix-web/actix_web/server/struct.HttpServer.html#method.shutdown_timeout +[disablesignals]: (../../actix-web/actix_web/server/struct.HttpServer.html#method.disable_signals) diff --git a/content/docs/static-files.md b/content/docs/static-files.md index abfc003..2038286 100644 --- a/content/docs/static-files.md +++ b/content/docs/static-files.md @@ -21,13 +21,11 @@ it will be unable to serve sub-paths. 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 -[*Files::show_files_listing()*](https://docs.rs/actix-files/0.1.2/actix_files/struct.Files.html) +[*Files::show_files_listing()*][showfileslisting] method. -Instead of showing files listing for directory, it is possible to redirect -to a specific index file. Use the -[*Files::index_file()*](https://docs.rs/actix-files/0.1.2/actix_files/struct.Files.html#method.index_file) -method to configure this redirect. +Instead of showing files listing for directory, it is possible to redirect to a specific +index file. Use the [*Files::index_file()*][indexfile] method to configure this redirect. # Configuration @@ -47,3 +45,6 @@ But it is possible to customize any of them by implementing the trait onto own s The Configuration cal also be applied to directory service: {{< include-example example="static-files" file="configuration_two.rs" section="config-two" >}} + +[showfileslisting]: https://docs.rs/actix-files/0.1.2/actix_files/struct.Files.html +[indexfile]: https://docs.rs/actix-files/0.1.2/actix_files/struct.Files.html#method.index_file diff --git a/content/docs/testing.md b/content/docs/testing.md index 335300b..2441ef0 100644 --- a/content/docs/testing.md +++ b/content/docs/testing.md @@ -12,9 +12,8 @@ integration tests. # Unit Tests For unit testing, actix-web provides a request builder type and a simple handler runner. -[*TestRequest*](https://docs.rs/actix-web/1.0.2/actix_web/test/struct.TestRequest.html) -implements a builder-like pattern. -You can generate a `HttpRequest` instance with `to_http_request()`, or you can +[*TestRequest*][testrequest] implements a builder-like pattern. You can generate a +`HttpRequest` instance with `to_http_request()`, or you can run your handler with `block_on()`. {{< include-example example="testing" file="main.rs" section="unit-tests" >}} @@ -30,8 +29,7 @@ methods can be used to send requests to the test server. To create a `Service` for testing, use the `test::init_serivce` method which accepts a regular `App` builder. -> Check the [api documentation](https://docs.rs/actix-web/1.0.2/actix_web/test/index.html) -> for more information. +> Check the [api documentation][actixdocs] for more information. {{< include-example example="testing" file="integration_one.rs" section="integration-one" >}} @@ -43,10 +41,13 @@ the normal application. For example, you may need to initialize application stat # Stream response tests -If you need to test stream it would be enough to convert a -[*ClientResponse*](../../actix-web/actix_web/client/struct.ClientResponse.html) to future -and execute it. -For example of testing -[*Server Sent Events*](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events). +If you need to test stream it would be enough to convert a [*ClientResponse*][clientresponse] +to future and execute it. +For example of testing [*Server Sent Events*][serversentevents]. {{< include-example example="testing" file="stream_response.rs" section="stream-response" >}} + +[serversentevents]: https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events +[clientresponse]: ../../actix-web/actix_web/client/struct.ClientResponse.html +[actixdocs]: (https://docs.rs/actix-web/1.0.2/actix_web/test/index.html) +[testrequest]: https://docs.rs/actix-web/1.0.2/actix_web/error/trait.ResponseError.html#foreign-impls diff --git a/content/docs/url-dispatch.md b/content/docs/url-dispatch.md index 8edce57..3a95dcb 100644 --- a/content/docs/url-dispatch.md +++ b/content/docs/url-dispatch.md @@ -10,31 +10,29 @@ URL dispatch provides a simple way for mapping URLs to handler code using a simp 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](sec-4-handler.html). +> 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][sec4handler]. # 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* (the portion following the scheme and -port, e.g. */foo/bar* in the *URL* *http://localhost:8080/foo/bar?q=value*). -It does not match against the *QUERY* portion (the portion that follows *?*, e.g. *q=value* in *http://localhost:8080/foo/bar?q=value*). +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* (the portion following the scheme and +port, e.g. */foo/bar* in the *URL* *http://localhost:8080/foo/bar?q=value*). It does not +match against the *QUERY* portion (the portion that follows *?*, e.g. *q=value* +in *http://localhost:8080/foo/bar?q=value*). -The [*App::route()*](../../actix-web/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*, +The [*App::route()*][approute] 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. {{< include-example example="url-dispatch" section="main" >}} -While *App::route()* provides simple way of registering routes, to access -complete resource configuration, a different method has to be used. -The [*App::resource()*](../../actix-web/actix_web/struct.App.html#method.resource) method +While *App::route()* provides simple way of registering routes, to access complete resource +configuration, a different method has to be used. The [*App::resource()*][appresource] method adds a single resource to application routing table. This method accepts a *path pattern* and a resource configuration function. @@ -71,24 +69,19 @@ 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. -[*ResourceHandler::route()*](../../actix-web/actix_web/dev/struct.ResourceHandler.html#method.route) returns a -[*Route*](../../actix-web/actix_web/dev/struct.Route.html) object. Route can be configured with a -builder-like pattern. Following configuration methods are available: +[*ResourceHandler::route()*][resourcehandler] returns a [*Route*][route] object. Route +can be configured with a builder-like pattern. Following configuration methods are available: -* [*Route::guard()*](../../actix-web/actix_web/dev/struct.Route.html#method.guard) - registers a new guard. Any number of guards can be registered for each route. -* [*Route::method()*](../../actix-web/actix_web/dev/struct.Route.html#method.method) - registers a method guard. Any number of guards can be registered for each route. -* [*Route::to()*](../../actix-web/actix_web/dev/struct.Route.html#method.to) 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) -> R + 'static` -* [*Route::to_async()*](../../actix-web/actix_web/dev/struct.Route.html#method.to_async) 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 +* [*Route::guard()*][routeguard] registers a new guard. Any number of guards can be + registered for each route. +* [*Route::method()*][routemethod] registers a method guard. Any number of guards can be + registered for each route. +* [*Route::to()*][routeto] 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) -> R + 'static` +* [*Route::to_async()*][routetoasync] 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) -> Future + 'static` # Route matching @@ -272,10 +265,8 @@ You can get variable path segments from `HttpRequest::match_info()`. # 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). +All values representing matched path segments are available in [`HttpRequest::match_info`][matchinfo]. +Specific values can be retrieved with [`Params::get()`][paramsget]. {{< include-example example="url-dispatch" file="minfo.rs" section="minfo" >}} @@ -301,13 +292,11 @@ safe to interpolate within, or use as a suffix of, a path without additional che ## Path information extractor -Actix provides functionality for type safe path information extraction. -[*Path*](../../actix-web/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 +Actix provides functionality for type safe path information extraction. [*Path*][pathstruct] +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 -`Path<(u32, String)>` type, but `Path<(String, String, String)>` type will -always fail. +`Path<(u32, String)>` type, but `Path<(String, String, String)>` type will always fail. {{< include-example example="url-dispatch" file="path.rs" section="path" >}} @@ -316,21 +305,19 @@ this struct must implement *serde's *`Deserialize` trait. {{< include-example example="url-dispatch" file="path2.rs" section="path" >}} -[*Query*](../../actix-web/actix_web/struct.Query.html) provides similar -functionality for request query parameters. +[*Query*][query] provides similar functionality for request query parameters. # Generating resource URLs -Use the [*HttpRequest.url_for()*](../../actix-web/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: +Use the [*HttpRequest.url_for()*][urlfor] 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: {{< include-example example="url-dispatch" file="urls.rs" section="url" >}} 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.7.0/url/struct.Url.html) so you -can modify this url (add query parameters, anchor, etc). +the current protocol and hostname implied http://example.com). `url_for()` method +returns [*Url object*][urlobj] 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 @@ -347,14 +334,13 @@ By normalizing it means: * To add a trailing slash to the path. * To replace multiple slashes with one. -The handler returns as soon as it finds a path that resolves -correctly. The order of normalization conditions, if all are enabled, is 1) merge, 2) 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. +The handler returns as soon as it finds a path that resolves correctly. The order of +normalization conditions, if all are enabled, is 1) merge, 2) 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 *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. @@ -375,11 +361,10 @@ It is possible to register path normalization only for *GET* requests only: ## Using an Application Prefix to Compose Applications -The `web::scope()` method allows to set a specific application scope. -This scope 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. +The `web::scope()` method allows to set a specific application scope. This scope 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: @@ -395,9 +380,8 @@ it will generate a URL with that same path. You can think of a guard as a simple function that accepts a *request* object reference and returns *true* or *false*. Formally, a guard is any object that implements the -[`Guard`](../actix_web/guard/trait.Guard.html) trait. Actix provides -several predicates, you can check -[functions section](../../actix-web/actix_web/guard/index.html#functions) of api docs. +[`Guard`][guardtrait] trait. Actix provides several predicates, you can check +[functions section][guardfuncs] of api docs. Here is a simple guard that check that a request contains a specific *header*: @@ -405,9 +389,8 @@ Here is a simple guard that check that a request contains a specific *header*: In this example, *index* handler will be called only if request contains *CONTENT-TYPE* header. -Guards have access to the application's state via `HttpRequest::data()`. -Also predicates can store extra information in -[request extensions](../../actix-web/actix_web/struct.HttpRequest.html#method.extensions). +Guards have access to the application's state via `HttpRequest::data()`. Also predicates +can store extra information in [request extensions][httprequest]. ## Modifying guard values @@ -440,3 +423,22 @@ This method accepts a *configuration function* same as normal resource configura with `App::service()` method. {{< include-example example="url-dispatch" file="dhandler.rs" section="default" >}} + +[sec4handler]: sec-4-handler.html +[approute]: ../../actix-web/actix_web/struct.App.html#method.route +[appresource]: ../../actix-web/actix_web/struct.App.html#method.resource +[resourcehandler]: ../../actix-web/actix_web/dev/struct.ResourceHandler.html#method.route +[route]: ../../actix-web/actix_web/dev/struct.Route.html +[routeguard]: ../../actix-web/actix_web/dev/struct.Route.html#method.guard +[routemethod]: ../../actix-web/actix_web/dev/struct.Route.html#method.method +[routeto]: ../../actix-web/actix_web/dev/struct.Route.html#method.to +[routetoasync]: ../../actix-web/actix_web/dev/struct.Route.html#method.to_async +[matchinfo]: ../actix_web/struct.HttpRequest.html#method.match_info +[paramsget]: ../actix_web/dev/struct.Params.html#method.get +[pathstruct]: ../../actix-web/actix_web/struct.Path.html +[query]: ../../actix-web/actix_web/struct.Query.html +[urlfor]: ../../actix-web/actix_web/struct.HttpRequest.html#method.url_for +[urlobj]: https://docs.rs/url/1.7.0/url/struct.Url.html +[guardtrait]: ../actix_web/guard/trait.Guard.html +[guardfuncs]: ../../actix-web/actix_web/guard/index.html#functions +[httprequest]: ../../actix-web/actix_web/struct.HttpRequest.html#method.extensions diff --git a/content/docs/websockets.md b/content/docs/websockets.md index c0335cd..664a8ee 100644 --- a/content/docs/websockets.md +++ b/content/docs/websockets.md @@ -5,8 +5,7 @@ weight: 240 --- Actix supports WebSockets out-of-the-box. It is possible to convert a request's `Payload` -to a stream of [*ws::Message*](../../actix-web/actix_web/ws/enum.Message.html) with -a [*ws::WsStream*](../../actix-web/actix_web/ws/struct.WsStream.html) and then use stream +to a stream of [*ws::Message*][message] with a [*ws::WsStream*][wsstream] and then use stream combinators to handle actual messages, but it is simpler to handle websocket communications with an http actor. @@ -14,8 +13,12 @@ The following is an example of a simple websocket echo server: {{< include-example example="websockets" file="main.rs" section="websockets" >}} -> A simple websocket echo server example is available in the -> [examples directory](https://github.com/actix/examples/tree/master/websocket/). +> A simple websocket echo server example is available in the [examples directory][examples]. > 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/examples/tree/master/websocket-chat/) +> is available in [websocket-chat directory][chat] + +[message]: ../../actix-web/actix_web/ws/enum.Message.html +[wsstream]: ../../actix-web/actix_web/ws/struct.WsStream.html +[examples]: https://github.com/actix/examples/tree/master/websocket/ +[chat]: https://github.com/actix/examples/tree/master/websocket-chat/ From be68e418b0c37e8b7a7847f48076a41214547140 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Tue, 25 Jun 2019 18:20:36 -0400 Subject: [PATCH 56/68] URL-Dispatch is done-ish. --- content/docs/url-dispatch.md | 100 ++++++++++++-------------- examples/url-dispatch/src/cfg.rs | 29 +++++--- examples/url-dispatch/src/dhandler.rs | 22 +++--- examples/url-dispatch/src/guard.rs | 28 ++++++++ examples/url-dispatch/src/guard2.rs | 18 +++++ examples/url-dispatch/src/main.rs | 22 +++--- examples/url-dispatch/src/minfo.rs | 14 +++- examples/url-dispatch/src/norm.rs | 25 ++++--- examples/url-dispatch/src/norm2.rs | 22 +++--- examples/url-dispatch/src/path.rs | 17 +++-- examples/url-dispatch/src/path2.rs | 16 +++-- examples/url-dispatch/src/pbuf.rs | 8 ++- examples/url-dispatch/src/pred.rs | 20 ------ examples/url-dispatch/src/pred2.rs | 12 ---- examples/url-dispatch/src/resource.rs | 12 ++-- examples/url-dispatch/src/scope.rs | 22 ++++-- examples/url-dispatch/src/url_ext.rs | 16 +++-- examples/url-dispatch/src/urls.rs | 25 ++++--- 18 files changed, 264 insertions(+), 164 deletions(-) create mode 100644 examples/url-dispatch/src/guard.rs create mode 100644 examples/url-dispatch/src/guard2.rs delete mode 100644 examples/url-dispatch/src/pred.rs delete mode 100644 examples/url-dispatch/src/pred2.rs diff --git a/content/docs/url-dispatch.md b/content/docs/url-dispatch.md index 3a95dcb..0a0f5e3 100644 --- a/content/docs/url-dispatch.md +++ b/content/docs/url-dispatch.md @@ -10,9 +10,10 @@ URL dispatch provides a simple way for mapping URLs to handler code using a simp 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][sec4handler]. +> A request handler is a function that accepts zero or more parameters that can be extracted +> from a request (ie, [*impl FromRequest*][implfromrequest]) and returns a type that can +> be converted into an HttpResponse (ie, [*impl Responder*][implresponder]). More information +> is available in the [handler section][handlersection]. # Resource configuration @@ -32,40 +33,33 @@ for the same path, in that case, multiple routes register for the same resource {{< include-example example="url-dispatch" section="main" >}} While *App::route()* provides simple way of registering routes, to access complete resource -configuration, a different method has to be used. The [*App::resource()*][appresource] method -adds a single resource to application routing table. This method accepts a *path pattern* -and a resource configuration function. +configuration, a different method has to be used. The [*App::service()*][appservice] method +adds a single [resource][webresource] to application routing table. This method accepts a +*path pattern*, guards, and one or more routes. {{< include-example example="url-dispatch" file="resource.rs" section="resource" >}} -The *Configuration function* has the following type: - -```rust -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. +Resource contains a set of routes. Each route in turn has a set of `guards` 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 +to new *Route* instance. By default the *route* does not contain any guards, 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. +> A *Route* can contain any number of *guards* but only one handler. {{< include-example example="url-dispatch" file="cfg.rs" section="cfg" >}} -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. +In this example, `HttpResponse::Ok()` is returned for *GET* requests if the request +contains `Content-Type` header, the value of this header is *text/plain*, and path +equals to `/path`. If a resource can not match any route, a "NOT FOUND" response is returned. @@ -77,19 +71,16 @@ can be configured with a builder-like pattern. Following configuration methods a * [*Route::method()*][routemethod] registers a method guard. Any number of guards can be registered for each route. * [*Route::to()*][routeto] 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) -> R + 'static` + can be registered. Usually handler registration is the last config operation. * [*Route::to_async()*][routetoasync] 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) -> Future + '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, +The way that *actix-web* 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, @@ -261,12 +252,12 @@ A *scoped* path can contain variable path segments as resources. Consistent with unscoped paths. You can get variable path segments from `HttpRequest::match_info()`. -`Path` extractor also is able to extract scope level variable segments. +[`Path` extractor][pathextractor] also is able to extract scope level variable segments. # Match information All values representing matched path segments are available in [`HttpRequest::match_info`][matchinfo]. -Specific values can be retrieved with [`Params::get()`][paramsget]. +Specific values can be retrieved with [`Path::get()`][pathget]. {{< include-example example="url-dispatch" file="minfo.rs" section="minfo" >}} @@ -339,16 +330,9 @@ normalization conditions, if all are enabled, is 1) merge, 2) both merge and app 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*. - {{< include-example example="url-dispatch" file="norm.rs" section="norm" >}} -In this example `/resource`, `//resource///` will be redirected to `/resource/`. +In this example `//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 @@ -385,12 +369,12 @@ and returns *true* or *false*. Formally, a guard is any object that implements t Here is a simple guard that check that a request contains a specific *header*: -{{< include-example example="url-dispatch" file="pred.rs" section="pred" >}} +{{< include-example example="url-dispatch" file="guard.rs" section="guard" >}} In this example, *index* handler will be called only if request contains *CONTENT-TYPE* header. -Guards have access to the application's state via `HttpRequest::data()`. Also predicates -can store extra information in [request extensions][httprequest]. +Guards can not access or modify the request object, but it is possible to store extra +information in [request extensions][requestextensions]. ## Modifying guard values @@ -398,7 +382,7 @@ You can invert the meaning of any predicate value by wrapping it in a `Not` pred For example, if you want to return "METHOD NOT ALLOWED" response for all methods except "GET": -{{< include-example example="url-dispatch" file="pred2.rs" section="pred" >}} +{{< include-example example="url-dispatch" file="guard2.rs" section="guard2" >}} The `Any` guard accepts a list of guards and matches if any of the supplied guards match. i.e: @@ -424,21 +408,25 @@ with `App::service()` method. {{< include-example example="url-dispatch" file="dhandler.rs" section="default" >}} -[sec4handler]: sec-4-handler.html -[approute]: ../../actix-web/actix_web/struct.App.html#method.route -[appresource]: ../../actix-web/actix_web/struct.App.html#method.resource -[resourcehandler]: ../../actix-web/actix_web/dev/struct.ResourceHandler.html#method.route -[route]: ../../actix-web/actix_web/dev/struct.Route.html -[routeguard]: ../../actix-web/actix_web/dev/struct.Route.html#method.guard -[routemethod]: ../../actix-web/actix_web/dev/struct.Route.html#method.method -[routeto]: ../../actix-web/actix_web/dev/struct.Route.html#method.to -[routetoasync]: ../../actix-web/actix_web/dev/struct.Route.html#method.to_async -[matchinfo]: ../actix_web/struct.HttpRequest.html#method.match_info -[paramsget]: ../actix_web/dev/struct.Params.html#method.get -[pathstruct]: ../../actix-web/actix_web/struct.Path.html -[query]: ../../actix-web/actix_web/struct.Query.html -[urlfor]: ../../actix-web/actix_web/struct.HttpRequest.html#method.url_for -[urlobj]: https://docs.rs/url/1.7.0/url/struct.Url.html -[guardtrait]: ../actix_web/guard/trait.Guard.html -[guardfuncs]: ../../actix-web/actix_web/guard/index.html#functions -[httprequest]: ../../actix-web/actix_web/struct.HttpRequest.html#method.extensions +[handlersection]: ../handlers/ +[approute]: https://docs.rs/actix-web/1.0.2/actix_web/struct.App.html#method.route +[appservice]: https://docs.rs/actix-web/1.0.2/actix_web/struct.App.html?search=#method.service +[webresource]: https://docs.rs/actix-web/1.0.2/actix_web/struct.Resource.html +[resourcehandler]: https://docs.rs/actix-web/1.0.2/actix_web/struct.Resource.html#method.route +[route]: https://docs.rs/actix-web/1.0.2/actix_web/struct.Route.html +[routeguard]: https://docs.rs/actix-web/1.0.2/actix_web/struct.Route.html#method.guard +[routemethod]: https://docs.rs/actix-web/1.0.2/actix_web/struct.Route.html#method.method +[routeto]: https://docs.rs/actix-web/1.0.2/actix_web/struct.Route.html#method.to +[routetoasync]: https://docs.rs/actix-web/1.0.2/actix_web/struct.Route.html#method.to_async +[matchinfo]: https://docs.rs/actix-web/1.0.2/actix_web/struct.HttpRequest.html#method.match_info +[pathget]: https://docs.rs/actix-web/1.0.2/actix_web/dev/struct.Path.html#method.get +[pathstruct]: https://docs.rs/actix-web/1.0.2/actix_web/dev/struct.Path.html +[query]: https://docs.rs/actix-web/1.0.2/actix_web/web/struct.Query.html +[urlfor]: https://docs.rs/actix-web/1.0.2/actix_web/struct.HttpRequest.html#method.url_for +[urlobj]: https://docs.rs/url/1.7.2/url/struct.Url.html +[guardtrait]: https://docs.rs/actix-web/1.0.2/actix_web/guard/trait.Guard.html +[guardfuncs]: https://docs.rs/actix-web/1.0.2/actix_web/guard/index.html#functions +[requestextensions]: https://docs.rs/actix-web/1.0.2/actix_web/struct.HttpRequest.html#method.extensions +[implfromrequest]: https://docs.rs/actix-web/1.0.2/actix_web/trait.FromRequest.html +[implresponder]: https://docs.rs/actix-web/1.0.2/actix_web/trait.Responder.html +[pathextractor]: ../extractors diff --git a/examples/url-dispatch/src/cfg.rs b/examples/url-dispatch/src/cfg.rs index de4de25..dfad2cd 100644 --- a/examples/url-dispatch/src/cfg.rs +++ b/examples/url-dispatch/src/cfg.rs @@ -1,14 +1,23 @@ -// use actix_web::{guard, web, App, HttpResponse}; +#[rustfmt::skip] pub fn main() { - App::new().service( - web::resource("/path").route( - web::route() - .guard(guard::Get()) - .guard(guard::Header("content-type", "text/plain")) - .to(|| HttpResponse::Ok()), - ), - ); -} + use actix_web::HttpServer; + + HttpServer::new(|| { +// +App::new().service( + web::resource("/path").route( + web::route() + .guard(guard::Get()) + .guard(guard::Header("content-type", "text/plain")) + .to(|| HttpResponse::Ok()), + ), +) // + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); +} diff --git a/examples/url-dispatch/src/dhandler.rs b/examples/url-dispatch/src/dhandler.rs index cb7a3db..e67891a 100644 --- a/examples/url-dispatch/src/dhandler.rs +++ b/examples/url-dispatch/src/dhandler.rs @@ -1,4 +1,4 @@ -use actix_web::{guard, web, App, HttpRequest, HttpResponse, Responder}; +use actix_web::{guard, web, App, HttpRequest, HttpResponse, HttpServer, Responder}; fn index(_req: HttpRequest) -> impl Responder { "Welcome!" @@ -6,12 +6,18 @@ fn index(_req: HttpRequest) -> impl Responder { // pub fn main() { - App::new() - .service(web::resource("/").route(web::get().to(index))) - .default_service( - web::route() - .guard(guard::Not(guard::Get())) - .to(|| HttpResponse::MethodNotAllowed()), - ); + HttpServer::new(|| { + App::new() + .service(web::resource("/").route(web::get().to(index))) + .default_service( + web::route() + .guard(guard::Not(guard::Get())) + .to(|| HttpResponse::MethodNotAllowed()), + ) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // diff --git a/examples/url-dispatch/src/guard.rs b/examples/url-dispatch/src/guard.rs new file mode 100644 index 0000000..19bd514 --- /dev/null +++ b/examples/url-dispatch/src/guard.rs @@ -0,0 +1,28 @@ +// +use actix_web::{ + dev::RequestHead, guard::Guard, http, web, App, HttpResponse, HttpServer, +}; + +struct ContentTypeHeader; + +impl Guard for ContentTypeHeader { + fn check(&self, req: &RequestHead) -> bool { + req.headers().contains_key(http::header::CONTENT_TYPE) + } +} + +pub fn main() { + HttpServer::new(|| { + App::new().route( + "/", + web::route() + .guard(ContentTypeHeader) + .to(|| HttpResponse::Ok()), + ) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); +} +// diff --git a/examples/url-dispatch/src/guard2.rs b/examples/url-dispatch/src/guard2.rs new file mode 100644 index 0000000..2d3d30b --- /dev/null +++ b/examples/url-dispatch/src/guard2.rs @@ -0,0 +1,18 @@ +// +use actix_web::{guard, web, App, HttpResponse, HttpServer}; + +pub fn main() { + HttpServer::new(|| { + App::new().route( + "/", + web::route() + .guard(guard::Not(guard::Get())) + .to(|| HttpResponse::MethodNotAllowed()), + ) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); +} +// diff --git a/examples/url-dispatch/src/main.rs b/examples/url-dispatch/src/main.rs index bea247a..009b26a 100644 --- a/examples/url-dispatch/src/main.rs +++ b/examples/url-dispatch/src/main.rs @@ -1,28 +1,34 @@ pub mod cfg; pub mod dhandler; +pub mod guard; +pub mod guard2; pub mod minfo; pub mod norm; pub mod norm2; pub mod path; pub mod path2; pub mod pbuf; -pub mod pred; -pub mod pred2; pub mod resource; pub mod scope; pub mod url_ext; pub mod urls; //
-use actix_web::{web, App, HttpRequest, HttpResponse}; +use actix_web::{web, App, HttpResponse, HttpServer}; -fn index(_req: HttpRequest) -> HttpResponse { - unimplemented!() +fn index() -> HttpResponse { + HttpResponse::Ok().body("Hello") } fn main() { - App::new() - .route("/user/{name}", web::get().to(index)) - .route("/user/{name}", web::post().to(index)); + HttpServer::new(|| { + App::new() + .route("/", web::get().to(index)) + .route("/user", web::post().to(index)) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } //
diff --git a/examples/url-dispatch/src/minfo.rs b/examples/url-dispatch/src/minfo.rs index 2222945..920611a 100644 --- a/examples/url-dispatch/src/minfo.rs +++ b/examples/url-dispatch/src/minfo.rs @@ -9,8 +9,16 @@ fn index(req: HttpRequest) -> Result { } pub fn main() { - App::new() - .route("/a/{v1}/{v2}/", web::get().to(index)) - .route("", web::get().to(|| actix_web::HttpResponse::Ok())); + use actix_web::HttpServer; + + HttpServer::new(|| { + App::new() + .route("/a/{v1}/{v2}/", web::get().to(index)) + .route("", web::get().to(|| actix_web::HttpResponse::Ok())) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // diff --git a/examples/url-dispatch/src/norm.rs b/examples/url-dispatch/src/norm.rs index d396da4..75723d0 100644 --- a/examples/url-dispatch/src/norm.rs +++ b/examples/url-dispatch/src/norm.rs @@ -1,14 +1,21 @@ // -use actix_web::{middleware, web, App}; +use actix_web::{middleware, web, App, HttpResponse}; + +fn index() -> HttpResponse { + HttpResponse::Ok().body("Hello") +} pub fn main() { - App::new() - .wrap(middleware::NormalizePath) - .route("/", web::get().to(index)); + use actix_web::HttpServer; + + HttpServer::new(|| { + App::new() + .wrap(middleware::NormalizePath) + .route("/resource/", web::to(index)) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // - -use actix_web::HttpRequest; -fn index(_req: HttpRequest) -> String { - unimplemented!() -} diff --git a/examples/url-dispatch/src/norm2.rs b/examples/url-dispatch/src/norm2.rs index 1efc527..bd0f019 100644 --- a/examples/url-dispatch/src/norm2.rs +++ b/examples/url-dispatch/src/norm2.rs @@ -1,16 +1,22 @@ // -use actix_web::{http::Method, middleware, web, App}; +use actix_web::{http::Method, middleware, web, App, HttpServer}; pub fn main() { - App::new() - .wrap(middleware::NormalizePath) - .route("/resource/", web::get().to(index)) - .default_service(web::route().method(Method::GET)); + HttpServer::new(|| { + App::new() + .wrap(middleware::NormalizePath) + .route("/resource/", web::get().to(index)) + .default_service(web::route().method(Method::GET)) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // -use actix_web::HttpRequest; +use actix_web::HttpResponse; -fn index(_req: HttpRequest) -> String { - unimplemented!() +fn index() -> HttpResponse { + HttpResponse::Ok().body("Hello") } diff --git a/examples/url-dispatch/src/path.rs b/examples/url-dispatch/src/path.rs index f3aea1a..1c84400 100644 --- a/examples/url-dispatch/src/path.rs +++ b/examples/url-dispatch/src/path.rs @@ -1,15 +1,22 @@ // use actix_web::{web, App, Result}; -// extract path info using serde fn index(info: web::Path<(String, u32)>) -> Result { Ok(format!("Welcome {}! id: {}", info.0, info.1)) } pub fn main() { - App::new().route( - "/{username}/{id}/index.html", // <- define path parameters - web::get().to(index), - ); + use actix_web::HttpServer; + + HttpServer::new(|| { + App::new().route( + "/{username}/{id}/index.html", // <- define path parameters + web::get().to(index), + ) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // diff --git a/examples/url-dispatch/src/path2.rs b/examples/url-dispatch/src/path2.rs index 53d4532..783949f 100644 --- a/examples/url-dispatch/src/path2.rs +++ b/examples/url-dispatch/src/path2.rs @@ -13,9 +13,17 @@ fn index(info: web::Path) -> Result { } pub fn main() { - App::new().route( - "/{username}/index.html", // <- define path parameters - web::get().to(index), - ); + use actix_web::HttpServer; + + HttpServer::new(|| { + App::new().route( + "/{username}/index.html", // <- define path parameters + web::get().to(index), + ) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // diff --git a/examples/url-dispatch/src/pbuf.rs b/examples/url-dispatch/src/pbuf.rs index 4ca0102..1319ad0 100644 --- a/examples/url-dispatch/src/pbuf.rs +++ b/examples/url-dispatch/src/pbuf.rs @@ -8,6 +8,12 @@ fn index(req: HttpRequest) -> Result { } pub fn main() { - App::new().route(r"/a/{tail:.*}", web::get().to(index)); + use actix_web::HttpServer; + + HttpServer::new(|| App::new().route(r"/a/{tail:.*}", web::get().to(index))) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // diff --git a/examples/url-dispatch/src/pred.rs b/examples/url-dispatch/src/pred.rs deleted file mode 100644 index 2617fa2..0000000 --- a/examples/url-dispatch/src/pred.rs +++ /dev/null @@ -1,20 +0,0 @@ -// -use actix_web::{dev::RequestHead, guard::Guard, http, web, App, HttpResponse}; - -struct ContentTypeHeader; - -impl Guard for ContentTypeHeader { - fn check(&self, req: &RequestHead) -> bool { - req.headers().contains_key(http::header::CONTENT_TYPE) - } -} - -pub fn main() { - App::new().route( - "", - web::route() - .guard(ContentTypeHeader) - .to(|| HttpResponse::Ok()), - ); -} -// diff --git a/examples/url-dispatch/src/pred2.rs b/examples/url-dispatch/src/pred2.rs deleted file mode 100644 index 68d13d7..0000000 --- a/examples/url-dispatch/src/pred2.rs +++ /dev/null @@ -1,12 +0,0 @@ -// -use actix_web::{guard, web, App, HttpResponse}; - -pub fn main() { - App::new().route( - "/", - web::route() - .guard(guard::Not(guard::Get())) - .to(|| HttpResponse::MethodNotAllowed()), - ); -} -// diff --git a/examples/url-dispatch/src/resource.rs b/examples/url-dispatch/src/resource.rs index a231856..778a712 100644 --- a/examples/url-dispatch/src/resource.rs +++ b/examples/url-dispatch/src/resource.rs @@ -1,15 +1,19 @@ // -use actix_web::{web, App, HttpRequest, HttpResponse}; +use actix_web::{guard, web, App, HttpResponse}; -fn index(_req: HttpRequest) -> HttpResponse { - unimplemented!() +fn index() -> HttpResponse { + HttpResponse::Ok().body("Hello") } pub fn main() { App::new() .service(web::resource("/prefix").to(index)) .service( - web::resource("/user/{name}").route(web::get().to(|| HttpResponse::Ok())), + web::resource("/user/{name}") + .name("user_detail") + .guard(guard::Header("content-type", "application/json")) + .route(web::get().to(|| HttpResponse::Ok())) + .route(web::put().to(|| HttpResponse::Ok())), ); } // diff --git a/examples/url-dispatch/src/scope.rs b/examples/url-dispatch/src/scope.rs index 01795ef..388acef 100644 --- a/examples/url-dispatch/src/scope.rs +++ b/examples/url-dispatch/src/scope.rs @@ -1,11 +1,25 @@ -use actix_web::{web, App, HttpRequest, HttpResponse}; +use actix_web::{web, App, HttpResponse, HttpServer}; // -fn show_users(_req: HttpRequest) -> HttpResponse { - unimplemented!() +fn show_users() -> HttpResponse { + HttpResponse::Ok().body("Show users") +} + +fn user_detail(_path: web::Path<(u32,)>) -> HttpResponse { + HttpResponse::Ok().body("User detail") } pub fn main() { - App::new().service(web::scope("/users").route("/show", web::get().to(show_users))); + HttpServer::new(|| { + App::new().service( + web::scope("/users") + .route("/show", web::get().to(show_users)) + .route("/show/{id}", web::get().to(user_detail)), + ) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // diff --git a/examples/url-dispatch/src/url_ext.rs b/examples/url-dispatch/src/url_ext.rs index 8f1869c..fafb66d 100644 --- a/examples/url-dispatch/src/url_ext.rs +++ b/examples/url-dispatch/src/url_ext.rs @@ -9,9 +9,17 @@ fn index(req: HttpRequest) -> impl Responder { } pub fn main() { - App::new() - .route("/index.html", web::get().to(index)) - .external_resource("youtube", "https://youtube.com/watch/{video_id}") - .route("/", actix_web::web::get().to(index)); + use actix_web::HttpServer; + + HttpServer::new(|| { + App::new() + .route("/", web::get().to(index)) + .external_resource("youtube", "https://youtube.com/watch/{video_id}") + .route("/", actix_web::web::get().to(index)) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // diff --git a/examples/url-dispatch/src/urls.rs b/examples/url-dispatch/src/urls.rs index 0ad653a..24cff65 100644 --- a/examples/url-dispatch/src/urls.rs +++ b/examples/url-dispatch/src/urls.rs @@ -3,19 +3,28 @@ use actix_web::{guard, http::header, web, App, HttpRequest, HttpResponse, Result fn index(req: HttpRequest) -> Result { let url = req.url_for("foo", &["1", "2", "3"])?; // <- generate url for "foo" resource + Ok(HttpResponse::Found() .header(header::LOCATION, url.as_str()) .finish()) } pub fn main() { - App::new() - .service( - web::resource("/test/{a}/{b}/{c}") - .name("foo") // <- set resource name, then it could be used in `url_for` - .guard(guard::Get()) - .to(|| HttpResponse::Ok()), - ) - .route("/test/", web::get().to(index)); + use actix_web::HttpServer; + + HttpServer::new(|| { + App::new() + .service( + web::resource("/test/{a}/{b}/{c}") + .name("foo") // <- set resource name, then it could be used in `url_for` + .guard(guard::Get()) + .to(|| HttpResponse::Ok()), + ) + .route("/test/", web::get().to(index)) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // From d7d4392d87719d397d0a0e9e0a1bb1a6386a0b54 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Wed, 26 Jun 2019 01:27:17 -0400 Subject: [PATCH 57/68] Requests is done-ish. --- content/docs/request.md | 26 ++++++++++---------- examples/requests/Cargo.toml | 1 + examples/requests/src/main.rs | 9 +++++-- examples/requests/src/manual.rs | 8 ++++++- examples/requests/src/streaming.rs | 35 +++++++++++++++++---------- examples/requests/src/urlencoded.rs | 37 +++++++++++++++-------------- 6 files changed, 69 insertions(+), 47 deletions(-) diff --git a/content/docs/request.md b/content/docs/request.md index 31962f4..f2cfcec 100644 --- a/content/docs/request.md +++ b/content/docs/request.md @@ -6,7 +6,7 @@ weight: 200 # Content Encoding -Actix automatically *decompresses* payloads. The following codecs are supported: +Actix-web automatically *decompresses* payloads. The following codecs are supported: * Brotli * Chunked @@ -42,29 +42,24 @@ body first and then deserialize the json into an object. # 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. +Actix automatically decodes *chunked* encoding. The [`web::Payload`][payloadextractor] +extractor 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. # Multipart body -Actix provides multipart stream support. -[*Multipart*][multipartstruct] is implemented as a stream of multipart items. Each item -can be a [*Field*][fieldstruct] or a nested *Multipart* stream.`HttpResponse::multipart()` -returns the *Multipart* stream for the current request. +Actix provides multipart stream support with an external crate, [`actix-multipart`][multipartcrate]. The following demonstrates multipart stream handling for a simple form: -{{< include-example example="requests" file="multipart.rs" section="multipart" >}} - > A full example is available in the [examples directory][multipartexample]. # Urlencoded body -Actix provides support for *application/x-www-form-urlencoded* encoded bodies. -`HttpResponse::urlencoded()` returns a [*UrlEncoded*][urlencoder] future, which resolves -to the deserialized instance. The type of the instance must implement the `Deserialize` -trait from *serde*. +Actix-web provides support for *application/x-www-form-urlencoded* encoded bodies with +the [`web::Form`][urlencoded] extractor 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: @@ -89,3 +84,6 @@ In the following example, we read and print the request payload chunk by chunk: [fieldstruct]: ../../actix-web/actix_web/multipart/struct.Field.html [multipartexample]: https://github.com/actix/examples/tree/master/multipart/ [urlencoder]: ../../actix-web/actix_web/dev/struct.UrlEncoded.html +[payloadextractor]: https://docs.rs/actix-web/1.0.2/actix_web/web/struct.Payload.html +[multipartcrate]: https://crates.io/crates/actix-multipart +[urlencoded]:Jhttps://docs.rs/actix-web/1.0.2/actix_web/web/struct.Form.html diff --git a/examples/requests/Cargo.toml b/examples/requests/Cargo.toml index cc4ba8d..4d26310 100644 --- a/examples/requests/Cargo.toml +++ b/examples/requests/Cargo.toml @@ -9,3 +9,4 @@ serde_json = "1.0" actix-web = "1.0" futures = "0.1" bytes = "0.4" +actix-multipart = "0.1" diff --git a/examples/requests/src/main.rs b/examples/requests/src/main.rs index b44e0bd..7d822e2 100644 --- a/examples/requests/src/main.rs +++ b/examples/requests/src/main.rs @@ -3,8 +3,9 @@ pub mod manual; pub mod multipart; pub mod streaming; pub mod urlencoded; + // -use actix_web::{web, App, Result}; +use actix_web::{web, App, HttpServer, Result}; use serde::Deserialize; #[derive(Deserialize)] @@ -18,6 +19,10 @@ fn index(info: web::Json) -> Result { } fn main() { - App::new().route("/index.html", web::post().to(index)); + HttpServer::new(|| App::new().route("/", web::post().to(index))) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // diff --git a/examples/requests/src/manual.rs b/examples/requests/src/manual.rs index a850b0e..44eeefc 100644 --- a/examples/requests/src/manual.rs +++ b/examples/requests/src/manual.rs @@ -43,5 +43,11 @@ pub fn index_manual( // pub fn main() { - App::new().route("/", web::post().to_async(index_manual)); + use actix_web::HttpServer; + + HttpServer::new(|| App::new().route("/", web::post().to_async(index_manual))) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } diff --git a/examples/requests/src/streaming.rs b/examples/requests/src/streaming.rs index 6444171..a219d4a 100644 --- a/examples/requests/src/streaming.rs +++ b/examples/requests/src/streaming.rs @@ -1,15 +1,26 @@ // -// use actix_web::{error, web, Error, HttpResponse}; -// use futures::{future::result, Future, Stream}; +use actix_web::{error, web, Error, HttpResponse}; +use futures::{future::result, Future, Stream}; -// pub fn index(payload: web::Payload) -> Box> { -// payload -// .from_err() -// .fold((), |_, chunk| { -// println!("Chunk: {:?}", chunk); -// result::<_, error::PayloadError>(Ok(())) -// }) -// .map(|_| HttpResponse::Ok().finish()) -// .responder() -// } +pub fn index(payload: web::Payload) -> Box> { + Box::new( + payload + .from_err() + .fold((), |_, chunk| { + println!("Chunk: {:?}", chunk); + result::<_, error::PayloadError>(Ok(())) + }) + .map(|_| HttpResponse::Ok().into()), + ) +} // + +pub fn main() { + use actix_web::{App, HttpServer}; + + HttpServer::new(|| App::new().route("/", web::post().to_async(index))) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); +} diff --git a/examples/requests/src/urlencoded.rs b/examples/requests/src/urlencoded.rs index 5e64efb..211c5a6 100644 --- a/examples/requests/src/urlencoded.rs +++ b/examples/requests/src/urlencoded.rs @@ -1,22 +1,23 @@ // -// use actix_web::{Error, HttpRequest, HttpResponse}; -// use futures::future::{ok, Future}; -// use serde::Deserialize; +use actix_web::{web, HttpResponse}; +use serde::Deserialize; -// #[derive(Deserialize)] -// struct FormData { -// username: String, -// } +#[derive(Deserialize)] +struct FormData { + username: String, +} -// fn index(req: &HttpRequest) -> Box> { -// req.urlencoded::() // <- get UrlEncoded future -// .from_err() -// .and_then(|data| { -// // <- deserialized instance -// println!("USERNAME: {:?}", data.username); -// ok(HttpResponse::Ok().into()) -// }) -// .responder() -// } +fn index(form: web::Form) -> HttpResponse { + HttpResponse::Ok().body(format!("username: {}", form.username)) +} // -pub fn main() {} + +pub fn main() { + use actix_web::{App, HttpServer}; + + HttpServer::new(|| App::new().route("/", web::post().to(index))) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); +} From 1c3697197dcf5489be9bfb07ab5ebd33d2c20699 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Wed, 26 Jun 2019 01:58:47 -0400 Subject: [PATCH 58/68] Responses section is done-ish. --- content/docs/response.md | 16 ++++++++-------- examples/responses/src/auto.rs | 22 ++++++++++++++-------- examples/responses/src/brotli.rs | 15 +++++++++------ examples/responses/src/chunked.rs | 11 ++++++++++- examples/responses/src/identity.rs | 15 +++++++++------ examples/responses/src/identity_two.rs | 9 +++++++-- examples/responses/src/json_resp.rs | 20 +++++++++++++------- examples/responses/src/main.rs | 18 +++++++++++------- 8 files changed, 81 insertions(+), 45 deletions(-) diff --git a/content/docs/response.md b/content/docs/response.md index 62f370d..54a62b7 100644 --- a/content/docs/response.md +++ b/content/docs/response.md @@ -6,15 +6,15 @@ weight: 210 # 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. +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][responsebuilder] 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. +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. {{< include-example example="responses" file="main.rs" section="builder" >}} @@ -39,8 +39,8 @@ For example, to enable `brotli` use `ContentEncoding::Br`: {{< include-example example="responses" file="brotli.rs" section="brotli" >}} -In this case we explicitly disable content compression -by setting content encoding to a `Identity` value: +In this case we explicitly disable content compression by setting content encoding to +an `Identity` value: {{< include-example example="responses" file="identity.rs" section="identity" >}} diff --git a/examples/responses/src/auto.rs b/examples/responses/src/auto.rs index d4b2cb7..bd0f14e 100644 --- a/examples/responses/src/auto.rs +++ b/examples/responses/src/auto.rs @@ -1,16 +1,22 @@ // -use actix_web::{ - http::ContentEncoding, middleware, web, App, HttpRequest, HttpResponse, -}; +use actix_web::{http::ContentEncoding, middleware, HttpResponse}; -fn index(_req: HttpRequest) -> HttpResponse { +fn index() -> HttpResponse { HttpResponse::Ok().body("data") } pub fn main() { - App::new() - // v- disable compression for all routes - .wrap(middleware::Compress::new(ContentEncoding::Identity)) - .route("/", web::get().to(index)); + use actix_web::{web, App, HttpServer}; + + HttpServer::new(|| { + App::new() + // v- disable compression for all routes + .wrap(middleware::Compress::new(ContentEncoding::Identity)) + .route("/", web::get().to(index)) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // diff --git a/examples/responses/src/brotli.rs b/examples/responses/src/brotli.rs index 79717ff..5694b28 100644 --- a/examples/responses/src/brotli.rs +++ b/examples/responses/src/brotli.rs @@ -1,16 +1,19 @@ // -use actix_web::{ - http::ContentEncoding, middleware::BodyEncoding, HttpRequest, HttpResponse, -}; +use actix_web::{http::ContentEncoding, middleware::BodyEncoding, HttpResponse}; -fn index_br(_req: HttpRequest) -> HttpResponse { +fn index_br() -> HttpResponse { HttpResponse::Ok() .encoding(ContentEncoding::Br) .body("data") } // -use actix_web::{web, App}; pub fn main() { - App::new().route("/", web::get().to(index_br)); + use actix_web::{web, App, HttpServer}; + + HttpServer::new(|| App::new().route("/", web::get().to(index_br))) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } diff --git a/examples/responses/src/chunked.rs b/examples/responses/src/chunked.rs index a2c4a62..50899cb 100644 --- a/examples/responses/src/chunked.rs +++ b/examples/responses/src/chunked.rs @@ -11,4 +11,13 @@ // )))))) // } // -pub fn main() {} + +// pub fn main() { +// use actix_web::{web, App, HttpServer}; + +// HttpServer::new(|| App::new().route("/", web::get().to(index))) +// .bind("127.0.0.1:8088") +// .unwrap() +// .run() +// .unwrap(); +// } diff --git a/examples/responses/src/identity.rs b/examples/responses/src/identity.rs index 039d713..63fb968 100644 --- a/examples/responses/src/identity.rs +++ b/examples/responses/src/identity.rs @@ -1,9 +1,7 @@ // -use actix_web::{ - http::ContentEncoding, middleware::BodyEncoding, HttpRequest, HttpResponse, -}; +use actix_web::{http::ContentEncoding, middleware::BodyEncoding, HttpResponse}; -fn index(_req: HttpRequest) -> HttpResponse { +fn index() -> HttpResponse { HttpResponse::Ok() // v- disable compression .encoding(ContentEncoding::Identity) @@ -11,7 +9,12 @@ fn index(_req: HttpRequest) -> HttpResponse { } // -use actix_web::{web, App}; pub fn main() { - App::new().route("/", web::get().to(index)); + use actix_web::{web, App, HttpServer}; + + HttpServer::new(|| App::new().route("/", web::get().to(index))) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } diff --git a/examples/responses/src/identity_two.rs b/examples/responses/src/identity_two.rs index 0ac8f65..8e6020f 100644 --- a/examples/responses/src/identity_two.rs +++ b/examples/responses/src/identity_two.rs @@ -17,7 +17,12 @@ pub fn index(_req: HttpRequest) -> HttpResponse { } // -use actix_web::{web, App}; pub fn main() { - App::new().route("/", web::get().to(index)); + use actix_web::{web, App, HttpServer}; + + HttpServer::new(|| App::new().route("/", web::get().to(index))) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } diff --git a/examples/responses/src/json_resp.rs b/examples/responses/src/json_resp.rs index 96d9591..7fc329d 100644 --- a/examples/responses/src/json_resp.rs +++ b/examples/responses/src/json_resp.rs @@ -1,19 +1,25 @@ // -use actix_web::{web, App, HttpRequest, Result}; -use serde::Serialize; +use actix_web::{web, HttpResponse, Result}; +use serde::{Deserialize, Serialize}; -#[derive(Serialize)] +#[derive(Serialize, Deserialize)] struct MyObj { name: String, } -fn index(req: HttpRequest) -> Result> { - Ok(web::Json(MyObj { - name: req.match_info().query("name").to_string(), +fn index(obj: web::Path) -> Result { + Ok(HttpResponse::Ok().json(MyObj { + name: obj.name.to_string(), })) } pub fn main() { - App::new().route(r"/a/{name}", web::get().to(index)); + use actix_web::{App, HttpServer}; + + HttpServer::new(|| App::new().route(r"/a/{name}", web::get().to(index))) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // diff --git a/examples/responses/src/main.rs b/examples/responses/src/main.rs index 943612e..1d63343 100644 --- a/examples/responses/src/main.rs +++ b/examples/responses/src/main.rs @@ -4,12 +4,11 @@ pub mod chunked; pub mod identity; pub mod identity_two; pub mod json_resp; -// -use actix_web::{ - http::ContentEncoding, middleware::BodyEncoding, HttpRequest, HttpResponse, -}; -fn index(_req: HttpRequest) -> HttpResponse { +// +use actix_web::{http::ContentEncoding, middleware::BodyEncoding, HttpResponse}; + +fn index() -> HttpResponse { HttpResponse::Ok() .encoding(ContentEncoding::Br) .content_type("plain/text") @@ -18,7 +17,12 @@ fn index(_req: HttpRequest) -> HttpResponse { } // -use actix_web::{web, App}; pub fn main() { - App::new().route("/", web::get().to(index)); + use actix_web::{web, App, HttpServer}; + + HttpServer::new(|| App::new().route("/", web::get().to(index))) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } From eff4edb6fa557785605d55b147126c661db095c3 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Wed, 26 Jun 2019 02:59:20 -0400 Subject: [PATCH 59/68] Middleware section is done-ish. --- content/docs/middleware.md | 87 ++++++++++------------ examples/middleware/src/default_headers.rs | 30 +++++--- examples/middleware/src/errorhandler.rs | 30 +++++--- examples/middleware/src/logger.rs | 15 +++- examples/middleware/src/main.rs | 24 ++++-- examples/middleware/src/user_sessions.rs | 38 +++++----- 6 files changed, 122 insertions(+), 102 deletions(-) diff --git a/content/docs/middleware.md b/content/docs/middleware.md index ef02106..0a9537e 100644 --- a/content/docs/middleware.md +++ b/content/docs/middleware.md @@ -6,9 +6,9 @@ weight: 220 # 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. +Actix-web'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. @@ -19,31 +19,32 @@ Typically, middleware is involved in the following actions: * 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 [*Service trait*][servicetrait] and -[*Transform trait*][transformtrait]. Each method in the traits has a default -implementation. Each method can return a result immediately or a *future* object. +Middleware is registered for each `App`, `scope`, or `Resource` and executed in opposite +order as registration. In general, a *middleware* is a type that implements the +[*Service trait*][servicetrait] and [*Transform trait*][transformtrait]. Each method in +the traits has a default implementation. Each method can return a result immediately +or a *future* object. The following demonstrates creating a simple middleware: -{{< include-example example="middleware" file="main.rs" section="main" >}} +{{< include-example example="middleware" file="main.rs" section="simple" >}} -> Actix provides several useful middlewares, such as *logging*, *user sessions*, etc. +> Actix-web provides several useful middlewares, such as *logging*, *user sessions*, +> *compress*, 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. +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][envlogger] -or similar). +for *actix_web* package to see access log ([env_logger][envlogger] or similar). ## Usage -Create `Logger` middleware with the specified `format`. -Default `Logger` can be created with `default` method, it uses the default format: +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 @@ -60,29 +61,18 @@ INFO:actix_web::middleware::logger: 127.0.0.1:59947 [02/Dec/2017:00:22:40 -0800] ## 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'] +- `%%` 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 @@ -94,8 +84,9 @@ a specified header. ## User sessions -Actix provides a general solution for session management. The [**actix-session**][actixsession] -middleware can be used with different backend types to store session data in different backends. +Actix-web provides a general solution for session management. The +[**actix-session**][actixsession] 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. @@ -115,8 +106,8 @@ The constructors take a key as an argument. This is the private key for cookie s 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 `CookieSession`. To access session data, -[*HttpRequest::session()*][requestsession] must be used. This method returns a +backend implementation, such as a `CookieSession`. To access session data the +[`Session`][requestsession] extractor must be used. This method returns a [*Session*][sessionobj] object, which allows us to get or set session data. {{< include-example example="middleware" file="user_sessions.rs" section="user-session" >}} @@ -132,10 +123,10 @@ into a response. {{< include-example example="middleware" file="errorhandler.rs" section="error-handler" >}} -[sessionobj]: ../../actix-web/actix_web/middleware/session/struct.Session.html -[requestsession]: ../../actix-web/actix_web/middleware/session/trait.RequestSession.html#tymethod.session -[cookiesession]: ../../actix-web/actix_web/middleware/session/struct.CookieSessionBackend.html +[sessionobj]: https://docs.rs/actix-session/0.1.1/actix_session/struct.Session.html +[requestsession]: https://docs.rs/actix-session/0.1.1/actix_session/struct.Session.html +[cookiesession]: https://docs.rs/actix-session/0.1.1/actix_session/struct.CookieSession.html [actixsession]: https://docs.rs/actix-session/0.1.1/actix_session/ [envlogger]: https://docs.rs/env_logger/*/env_logger/ -[servicetrait]: ../../actix-web/actix_web/dev/trait.Service.html -[transformtrait]: ../../actix-web/actix_web/dev/trait.Transform.html +[servicetrait]: https://docs.rs/actix-web/1.0.2/actix_web/dev/trait.Service.html +[transformtrait]: https://docs.rs/actix-web/1.0.2/actix_web/dev/trait.Transform.html diff --git a/examples/middleware/src/default_headers.rs b/examples/middleware/src/default_headers.rs index cf14468..d998a15 100644 --- a/examples/middleware/src/default_headers.rs +++ b/examples/middleware/src/default_headers.rs @@ -1,16 +1,24 @@ // -use actix_web::{http, middleware, web, App, HttpResponse}; +use actix_web::{http, middleware, HttpResponse}; pub fn main() { - App::new() - .wrap(middleware::DefaultHeaders::new().header("X-Version", "0.2")) - .service( - web::resource("/test") - .route(web::get().to(|| HttpResponse::Ok())) - .route( - web::method(http::Method::HEAD) - .to(|| HttpResponse::MethodNotAllowed()), - ), - ); + use actix_web::{web, App, HttpServer}; + + HttpServer::new(|| { + App::new() + .wrap(middleware::DefaultHeaders::new().header("X-Version", "0.2")) + .service( + web::resource("/test") + .route(web::get().to(|| HttpResponse::Ok())) + .route( + web::method(http::Method::HEAD) + .to(|| HttpResponse::MethodNotAllowed()), + ), + ) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // diff --git a/examples/middleware/src/errorhandler.rs b/examples/middleware/src/errorhandler.rs index 6d33db5..dacef6e 100644 --- a/examples/middleware/src/errorhandler.rs +++ b/examples/middleware/src/errorhandler.rs @@ -1,6 +1,6 @@ // use actix_web::middleware::errhandlers::{ErrorHandlerResponse, ErrorHandlers}; -use actix_web::{dev, http, web, App, HttpResponse, Result}; +use actix_web::{dev, http, HttpResponse, Result}; fn render_500(mut res: dev::ServiceResponse) -> Result> { res.response_mut().headers_mut().insert( @@ -11,15 +11,23 @@ fn render_500(mut res: dev::ServiceResponse) -> Result diff --git a/examples/middleware/src/logger.rs b/examples/middleware/src/logger.rs index 8a5cecd..254e5d1 100644 --- a/examples/middleware/src/logger.rs +++ b/examples/middleware/src/logger.rs @@ -1,14 +1,21 @@ // use actix_web::middleware::Logger; -use actix_web::App; use env_logger; pub fn main() { + use actix_web::{App, HttpServer}; + std::env::set_var("RUST_LOG", "actix_web=info"); env_logger::init(); - App::new() - .wrap(Logger::default()) - .wrap(Logger::new("%a %{User-Agent}i")); + HttpServer::new(|| { + App::new() + .wrap(Logger::default()) + .wrap(Logger::new("%a %{User-Agent}i")) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // diff --git a/examples/middleware/src/main.rs b/examples/middleware/src/main.rs index d39d2d8..22ed711 100644 --- a/examples/middleware/src/main.rs +++ b/examples/middleware/src/main.rs @@ -2,9 +2,10 @@ pub mod default_headers; pub mod errorhandler; pub mod logger; pub mod user_sessions; -//
+ +// use actix_service::{Service, Transform}; -use actix_web::{dev::ServiceRequest, dev::ServiceResponse, web, App, Error}; +use actix_web::{dev::ServiceRequest, dev::ServiceResponse, Error}; use futures::future::{ok, FutureResult}; use futures::{Future, Poll}; @@ -63,10 +64,19 @@ where })) } } -//
+// + fn main() { - App::new().wrap(SayHi).service( - web::resource("/") - .to(|| "Hello, middleware! Check the console where the server is run."), - ); + use actix_web::{web, App, HttpServer}; + + HttpServer::new(|| { + App::new().wrap(SayHi).service( + web::resource("/") + .to(|| "Hello, middleware! Check the console where the server is run."), + ) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } diff --git a/examples/middleware/src/user_sessions.rs b/examples/middleware/src/user_sessions.rs index d51c740..b4f99ff 100644 --- a/examples/middleware/src/user_sessions.rs +++ b/examples/middleware/src/user_sessions.rs @@ -1,37 +1,33 @@ // use actix_session::{CookieSession, Session}; -use actix_web::{middleware::Logger, web, App, HttpRequest, HttpServer, Result}; +use actix_web::{web, App, Error, HttpResponse, HttpServer}; -/// simple index handler with session -fn index(session: Session, req: HttpRequest) -> Result<&'static str> { - println!("{:?}", req); - - // RequestSession trait is used for session access - let mut counter = 1; +pub fn index(session: Session) -> Result { + // access session data if let Some(count) = session.get::("counter")? { - println!("SESSION value: {}", count); - counter = count + 1; - session.set("counter", counter)?; + session.set("counter", count + 1)?; } else { - session.set("counter", counter)?; + session.set("counter", 1)?; } - Ok("welcome!") + Ok(HttpResponse::Ok().body(format!( + "Count is {:?}!", + session.get::("counter")?.unwrap() + ))) } -pub fn main() -> std::io::Result<()> { - std::env::set_var("RUST_LOG", "actix_web=info"); - env_logger::init(); - +pub fn main() { HttpServer::new(|| { App::new() - // enable logger - .wrap(Logger::default()) - // cookie session middleware - .wrap(CookieSession::signed(&[0; 32]).secure(false)) + .wrap( + CookieSession::signed(&[0; 32]) // <- create cookie based session middleware + .secure(false), + ) .service(web::resource("/").to(index)) }) - .bind("127.0.0.1:8080")? + .bind("127.0.0.1:8088") + .unwrap() .run() + .unwrap(); } // From 0934b77762bded88f763d759e6b3193a87e415eb Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Wed, 26 Jun 2019 03:11:05 -0400 Subject: [PATCH 60/68] updates a few links. --- content/docs/handlers.md | 4 ++-- content/docs/http2.md | 2 +- content/docs/request.md | 10 +++++----- content/docs/response.md | 2 +- content/docs/server.md | 14 +++++++------- content/docs/testing.md | 2 +- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/content/docs/handlers.md b/content/docs/handlers.md index ac00ffd..c571190 100644 --- a/content/docs/handlers.md +++ b/content/docs/handlers.md @@ -91,5 +91,5 @@ different responder types into a single type. [implfromrequest]: https://docs.rs/actix-web/1.0.2/actix_web/trait.FromRequest.html [implresponder]: https://docs.rs/actix-web/1.0.2/actix_web/trait.Responder.html [respondertrait]: https://docs.rs/actix-web/1.0.2/actix_web/trait.Responder.html -[responderimpls]: ../../actix-web/actix_web/trait.Responder.html#foreign-impls -[either]: ../../actix-web/actix_web/enum.Either.html +[responderimpls]: https://docs.rs/actix-web/1.0.2/actix_web/trait.Responder.html#foreign-impls +[either]: https://docs.rs/actix-web/1.0.2/actix_web/enum.Either.html diff --git a/content/docs/http2.md b/content/docs/http2.md index 3c257c9..d64e395 100644 --- a/content/docs/http2.md +++ b/content/docs/http2.md @@ -30,6 +30,6 @@ connection and tls connection. [rfc section 3.4][rfcsection34]. [rfcsection32]: https://http2.github.io/http2-spec/#rfc.section.3.2 [rfcsection34]: https://http2.github.io/http2-spec/#rfc.section.3.4 -[bindssl]: ../../actix-web/actix_web/server/struct.HttpServer.html#method.serve_tls +[bindssl]: https://docs.rs/actix-web/1.0.2/actix_web/struct.HttpServer.html#method.bind_ssl [tlsalpn]: https://tools.ietf.org/html/rfc7301 [examples]: https://github.com/actix/examples/tree/master/tls diff --git a/content/docs/request.md b/content/docs/request.md index f2cfcec..4c93f0c 100644 --- a/content/docs/request.md +++ b/content/docs/request.md @@ -58,7 +58,7 @@ The following demonstrates multipart stream handling for a simple form: # Urlencoded body Actix-web provides support for *application/x-www-form-urlencoded* encoded bodies with -the [`web::Form`][urlencoded] extractor which resolves to the deserialized instance. The +the [`web::Form`][formencoded] extractor 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: @@ -80,10 +80,10 @@ In the following example, we read and print the request payload chunk by chunk: {{< include-example example="requests" file="streaming.rs" section="streaming" >}} [examples]: https://github.com/actix/examples/tree/master/json/ -[multipartstruct]: ../../actix-web/actix_web/multipart/struct.Multipart.html -[fieldstruct]: ../../actix-web/actix_web/multipart/struct.Field.html +[multipartstruct]: https://docs.rs/actix-multipart/0.1.2/actix_multipart/struct.Multipart.html +[fieldstruct]: https://docs.rs/actix-multipart/0.1.2/actix_multipart/struct.Field.html [multipartexample]: https://github.com/actix/examples/tree/master/multipart/ -[urlencoder]: ../../actix-web/actix_web/dev/struct.UrlEncoded.html +[urlencoded]: https://docs.rs/actix-web/1.0.2/actix_web/dev/struct.UrlEncoded.html [payloadextractor]: https://docs.rs/actix-web/1.0.2/actix_web/web/struct.Payload.html [multipartcrate]: https://crates.io/crates/actix-multipart -[urlencoded]:Jhttps://docs.rs/actix-web/1.0.2/actix_web/web/struct.Form.html +[formencoded]:Jhttps://docs.rs/actix-web/1.0.2/actix_web/web/struct.Form.html diff --git a/content/docs/response.md b/content/docs/response.md index 54a62b7..32d9f36 100644 --- a/content/docs/response.md +++ b/content/docs/response.md @@ -75,4 +75,4 @@ is enabled automatically. {{< include-example example="responses" file="chunked.rs" section="chunked" >}} -[responsebuilder]: ../../actix-web/actix_web/dev/struct.HttpResponseBuilder.html +[responsebuilder]: https://docs.rs/actix-web/1.0.2/actix_web/dev/struct.HttpResponseBuilder.html diff --git a/content/docs/server.md b/content/docs/server.md index 6e65f69..fb2a558 100644 --- a/content/docs/server.md +++ b/content/docs/server.md @@ -117,12 +117,12 @@ are available on unix systems. [`HttpServer::disable_signals()`][disablesignals] method. [httpserverstruct]: https://docs.rs/actix-web/1.0.2/actix_web/struct.HttpServer.html -[bindmethod]: ../../actix-web/actix_web/server/struct.HttpServer.html#method.bind -[bindsslmethod]: ../../actix-web/actix_web/server/struct.HttpServer.html#method.bind_ssl -[bindrusttls]: ../../actix-web/1.0.0/actix_web/struct.HttpServer.html#method.bind_rustls -[startmethod]: ../../actix-web/actix_web/server/struct.HttpServer.html#method.start -[workers]: ../../actix-web/actix_web/server/struct.HttpServer.html#method.workers +[bindmethod]: https://docs.rs/actix-web/1.0.2/actix_web/struct.HttpServer.html#method.bind +[bindsslmethod]: https://docs.rs/actix-web/1.0.2/actix_web/struct.HttpServer.html#method.bind_ssl +[bindrusttls]: https://docs.rs/actix-web/1.0.2/actix_web/struct.HttpServer.html#method.bind_rustls +[startmethod]: https://docs.rs/actix-web/1.0.2/actix_web/struct.HttpServer.html#method.start +[workers]: https://docs.rs/actix-web/1.0.2/actix_web/struct.HttpServer.html#method.workers [tlsalpn]: https://tools.ietf.org/html/rfc7301 [exampletls]: https://github.com/actix/examples/tree/master/tls -[shutdowntimeout]: ../../actix-web/actix_web/server/struct.HttpServer.html#method.shutdown_timeout -[disablesignals]: (../../actix-web/actix_web/server/struct.HttpServer.html#method.disable_signals) +[shutdowntimeout]: https://docs.rs/actix-web/1.0.2/actix_web/struct.HttpServer.html#method.shutdown_timeout +[disablesignals]: https://docs.rs/actix-web/1.0.2/actix_web/struct.HttpServer.html#method.disable_signals diff --git a/content/docs/testing.md b/content/docs/testing.md index 2441ef0..68bf7f8 100644 --- a/content/docs/testing.md +++ b/content/docs/testing.md @@ -48,6 +48,6 @@ For example of testing [*Server Sent Events*][serversentevents]. {{< include-example example="testing" file="stream_response.rs" section="stream-response" >}} [serversentevents]: https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events -[clientresponse]: ../../actix-web/actix_web/client/struct.ClientResponse.html +[clientresponse]: https://docs.rs/actix-web/1.0.2/actix_web/client/struct.ClientResponse.html [actixdocs]: (https://docs.rs/actix-web/1.0.2/actix_web/test/index.html) [testrequest]: https://docs.rs/actix-web/1.0.2/actix_web/error/trait.ResponseError.html#foreign-impls From 4436eff7def08ccc946ad838aee63cd8b1d67138 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Wed, 26 Jun 2019 04:27:25 -0400 Subject: [PATCH 61/68] Static Files is done-ish. --- content/docs/static-files.md | 16 +++---- examples/static-files/src/configuration.rs | 43 +++++++++---------- .../static-files/src/configuration_two.rs | 38 +++++++--------- examples/static-files/src/directory.rs | 10 ++++- examples/static-files/src/main.rs | 11 +++-- 5 files changed, 58 insertions(+), 60 deletions(-) diff --git a/content/docs/static-files.md b/content/docs/static-files.md index 2038286..f3512d5 100644 --- a/content/docs/static-files.md +++ b/content/docs/static-files.md @@ -29,20 +29,18 @@ index file. Use the [*Files::index_file()*][indexfile] method to configure this # Configuration -Generic trait `StaticFileConfig` can be used to specify various options -for serving files: +`NamedFiles` can specify various options for serving files: -- `content_disposition_map` - function to be used for mapping file's mime to corresponding `Content-Disposition` type -- `is_use_etag` - specifies whether `ETag` shall be calculated and included in headers. -- `is_use_last_modifier` - specifies whether file modified timestamp should be used and added to `Last-Modified` header. -- `is_method_allowed` - allows to control which HTTP methods are allowed to be used when accessing file. +- `set_content_dispostion` - function to be used for mapping file's mime to corresponding `Content-Disposition` type +- `use_etag` - specifies whether `ETag` shall be calculated and included in headers. +- `use_last_modifier` - specifies whether file modified timestamp should be used and added to `Last-Modified` header. -All of the above methods are optional and provided with the best defaults. -But it is possible to customize any of them by implementing the trait onto own struct. +All of the above methods are optional and provided with the best defaults, But it is +possible to customize any of them. {{< include-example example="static-files" file="configuration.rs" section="config-one" >}} -The Configuration cal also be applied to directory service: +The Configuration can also be applied to directory service: {{< include-example example="static-files" file="configuration_two.rs" section="config-two" >}} diff --git a/examples/static-files/src/configuration.rs b/examples/static-files/src/configuration.rs index b608e0c..54b5d2a 100644 --- a/examples/static-files/src/configuration.rs +++ b/examples/static-files/src/configuration.rs @@ -1,27 +1,24 @@ // -// extern crate actix_web; -// extern crate mime; -// use actix_files::{FileConfig, NamedFile}; -// use actix_web::http::header::DispositionType; -// use actix_web::{http::Method, App, HttpRequest, Result}; +use actix_files as fs; +use actix_web::http::header::{ContentDisposition, DispositionType}; +use actix_web::{web, App, Error, HttpRequest, HttpServer}; -// use std::path::PathBuf; +fn index(req: HttpRequest) -> Result { + let path: std::path::PathBuf = req.match_info().query("filename").parse().unwrap(); + let file = fs::NamedFile::open(path)?; + Ok(file + .use_last_modified(true) + .set_content_disposition(ContentDisposition { + disposition: DispositionType::Attachment, + parameters: vec![], + })) +} -// #[derive(Default)] -// struct MyConfig; - -// impl FileConfig for MyConfig { -// fn content_disposition_map(typ: mime::Name) -> DispositionType { -// DispositionType::Attachment -// } -// } - -// fn index(req: &HttpRequest) -> Result> { -// let path: PathBuf = req.match_info().query("tail")?; -// Ok(NamedFile::open_with_config(path, MyConfig)?) -// } - -// fn main() { -// App::new().resource(r"/a/{tail:.*}", |r| r.method(Method::GET).f(index)); -// } +pub fn main() { + HttpServer::new(|| App::new().route("/{filename:.*}", web::get().to(index))) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); +} // diff --git a/examples/static-files/src/configuration_two.rs b/examples/static-files/src/configuration_two.rs index c9c0850..669e625 100644 --- a/examples/static-files/src/configuration_two.rs +++ b/examples/static-files/src/configuration_two.rs @@ -1,26 +1,18 @@ // -// use actix_files::{FileConfig, Files}; -// use actix_web::App; +use actix_files as fs; +use actix_web::{App, HttpServer}; -// #[derive(Default)] -// struct MyConfig; - -// impl FileConfig for MyConfig { -// fn is_use_etag() -> bool { -// false -// } - -// fn is_use_last_modifier() -> bool { -// false -// } -// } - -// fn main() { -// App::new().service( -// "/static", -// Files::with_config(".", MyConfig) -// .unwrap() -// .show_files_listing(), -// ); -// } +pub fn main() { + HttpServer::new(|| { + App::new().service( + fs::Files::new("/static", ".") + .show_files_listing() + .use_last_modified(true), + ) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); +} // diff --git a/examples/static-files/src/directory.rs b/examples/static-files/src/directory.rs index 3fcbbe4..6da7ea4 100644 --- a/examples/static-files/src/directory.rs +++ b/examples/static-files/src/directory.rs @@ -1,8 +1,14 @@ // use actix_files as fs; -use actix_web::App; +use actix_web::{App, HttpServer}; pub fn main() { - App::new().service(fs::Files::new("/static", ".").show_files_listing()); + HttpServer::new(|| { + App::new().service(fs::Files::new("/static", ".").show_files_listing()) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // diff --git a/examples/static-files/src/main.rs b/examples/static-files/src/main.rs index 907afff..1e06d23 100644 --- a/examples/static-files/src/main.rs +++ b/examples/static-files/src/main.rs @@ -1,17 +1,22 @@ pub mod configuration; pub mod configuration_two; pub mod directory; + // use actix_files::NamedFile; -use actix_web::{web, App, HttpRequest, Result}; +use actix_web::{web, App, HttpRequest, HttpServer, Result}; use std::path::PathBuf; fn index(req: HttpRequest) -> Result { - let path: PathBuf = req.match_info().query("tail").parse().unwrap(); + let path: PathBuf = req.match_info().query("filename").parse().unwrap(); Ok(NamedFile::open(path)?) } fn main() { - App::new().route("/", web::get().to(index)); + HttpServer::new(|| App::new().route("/{filename:.*}", web::get().to(index))) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // From 387807ee6e00ad4b661c91516961b72b13a8bc4c Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Wed, 26 Jun 2019 12:55:12 -0400 Subject: [PATCH 62/68] Websockets chapter done-ish. --- content/docs/websockets.md | 12 +++---- examples/websockets/Cargo.toml | 5 +-- examples/websockets/src/main.rs | 61 ++++++++++++++++++++------------- 3 files changed, 47 insertions(+), 31 deletions(-) diff --git a/content/docs/websockets.md b/content/docs/websockets.md index 664a8ee..d7e0f20 100644 --- a/content/docs/websockets.md +++ b/content/docs/websockets.md @@ -4,10 +4,10 @@ menu: docs_proto weight: 240 --- -Actix supports WebSockets out-of-the-box. It is possible to convert a request's `Payload` -to a stream of [*ws::Message*][message] with a [*ws::WsStream*][wsstream] and then use stream -combinators to handle actual messages, but it is simpler to handle websocket communications -with an http actor. +Actix-web supports WebSockets with the `actix-web-actors` crate. It is possible to convert a +request's `Payload` to a stream of [*ws::Message*][message] with a [*web::Payload*][payload] +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: @@ -18,7 +18,7 @@ The following is an example of a simple websocket echo server: > An example chat server with the ability to chat over a websocket or tcp connection > is available in [websocket-chat directory][chat] -[message]: ../../actix-web/actix_web/ws/enum.Message.html -[wsstream]: ../../actix-web/actix_web/ws/struct.WsStream.html +[message]: https://docs.rs/actix-web-actors/1.0.0/actix_web_actors/ws/enum.Message.html +[payload]: https://docs.rs/actix-web/1.0.2/actix_web/web/struct.Payload.html [examples]: https://github.com/actix/examples/tree/master/websocket/ [chat]: https://github.com/actix/examples/tree/master/websocket-chat/ diff --git a/examples/websockets/Cargo.toml b/examples/websockets/Cargo.toml index fca0541..e8f5b50 100644 --- a/examples/websockets/Cargo.toml +++ b/examples/websockets/Cargo.toml @@ -1,8 +1,9 @@ [package] name = "websockets" -version = "0.7.0" +version = "1.0.0" edition = "2018" [dependencies] -actix = "0.7" +actix = "0.8" actix-web = "1.0" +actix-web-actors = "1.0" diff --git a/examples/websockets/src/main.rs b/examples/websockets/src/main.rs index 6cec49d..fd49c5c 100644 --- a/examples/websockets/src/main.rs +++ b/examples/websockets/src/main.rs @@ -1,29 +1,44 @@ // -// use actix::*; -// use actix_web::*; +use actix::{Actor, StreamHandler}; +use actix_web::{web, App, Error, HttpRequest, HttpResponse, HttpServer}; +use actix_web_actors::ws; -// /// Define http actor -// struct Ws; +/// Define http actor +struct MyWs; -// impl Actor for Ws { -// type Context = ws::WebsocketContext; -// } +impl Actor for MyWs { + type Context = ws::WebsocketContext; +} -// /// Handler for ws::Message message -// impl StreamHandler 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), -// _ => (), -// } -// } -// } +/// Handler for ws::Message message +impl StreamHandler for MyWs { + 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))) -// .finish(); -// } +fn index(req: HttpRequest, stream: web::Payload) -> Result { + let resp = ws::start(MyWs {}, &req, stream); + println!("{:?}", resp); + resp +} + +fn main() { + HttpServer::new(|| App::new().route("/ws/", web::get().to(index))) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); +} // + +// testing requires specific headers: +// Upgrade: websocket +// Connection: Upgrade +// Sec-WebSocket-Key: SOME_KEY +// Sec-WebSocket-Version: 13 From 0601997b41050e341466f573fbabd8d05fc4171e Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Wed, 26 Jun 2019 14:15:03 -0400 Subject: [PATCH 63/68] Updates Compression section. --- content/docs/response.md | 20 ++++++++++++++------ examples/responses/src/auto.rs | 3 +-- examples/responses/src/brotli.rs | 18 +++++++++++------- examples/responses/src/brotli_two.rs | 21 +++++++++++++++++++++ examples/responses/src/compress.rs | 21 +++++++++++++++++++++ examples/responses/src/identity.rs | 20 +++++++++++++------- examples/responses/src/identity_two.rs | 17 +++++++++++------ examples/responses/src/main.rs | 1 + examples/url-dispatch/Cargo.toml | 2 +- 9 files changed, 94 insertions(+), 29 deletions(-) create mode 100644 examples/responses/src/brotli_two.rs create mode 100644 examples/responses/src/compress.rs diff --git a/content/docs/response.md b/content/docs/response.md index 32d9f36..79681a1 100644 --- a/content/docs/response.md +++ b/content/docs/response.md @@ -20,32 +20,39 @@ instance multiple times, the builder will panic. # Content encoding -Actix-web automatically *compresses* payloads. The following codecs are supported: +Actix-web can automatically *compresses* payloads with the [*Compress middleware*][compressmidddleware]. +The following codecs are supported: * Brotli * Gzip * Deflate * Identity +{{< include-example example="responses" file="compress.rs" section="compress" >}} + Response payload is compressed based on the *encoding* parameter from the -`middleware::BodyEncoding` trait. By default, `ContentEncoding::Auto` is -used. If `ContentEncoding::Auto` is selected, then the compression depends -on the request's `Accept-Encoding` header. +`middleware::BodyEncoding` trait. 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`: +For example, to enable `brotli` for a single handler use `ContentEncoding::Br`: {{< include-example example="responses" file="brotli.rs" section="brotli" >}} +or for the entire application: + +{{< include-example example="responses" file="brotli_two.rs" section="brotli-two" >}} + In this case we explicitly disable content compression by setting content encoding to an `Identity` value: {{< include-example example="responses" file="identity.rs" section="identity" >}} When dealing with an already compressed body (for example when serving assets), -set the content encoding to `Identity` to avoid compressing the already compressed +set the content encoding to `Identity` to avoid compressing the already compressed data and set the `content-encoding` header manually: {{< include-example example="responses" file="identity_two.rs" section="identity-two" >}} @@ -76,3 +83,4 @@ is enabled automatically. {{< include-example example="responses" file="chunked.rs" section="chunked" >}} [responsebuilder]: https://docs.rs/actix-web/1.0.2/actix_web/dev/struct.HttpResponseBuilder.html +[compressmidddleware]: https://docs.rs/actix-web/1.0.2/actix_web/middleware/struct.Compress.html diff --git a/examples/responses/src/auto.rs b/examples/responses/src/auto.rs index bd0f14e..1af1078 100644 --- a/examples/responses/src/auto.rs +++ b/examples/responses/src/auto.rs @@ -10,8 +10,7 @@ pub fn main() { HttpServer::new(|| { App::new() - // v- disable compression for all routes - .wrap(middleware::Compress::new(ContentEncoding::Identity)) + .wrap(middleware::Compress::new(ContentEncoding::Br)) .route("/", web::get().to(index)) }) .bind("127.0.0.1:8088") diff --git a/examples/responses/src/brotli.rs b/examples/responses/src/brotli.rs index 5694b28..ebdf7e2 100644 --- a/examples/responses/src/brotli.rs +++ b/examples/responses/src/brotli.rs @@ -6,14 +6,18 @@ fn index_br() -> HttpResponse { .encoding(ContentEncoding::Br) .body("data") } -// pub fn main() { - use actix_web::{web, App, HttpServer}; + use actix_web::{middleware, web, App, HttpServer}; - HttpServer::new(|| App::new().route("/", web::get().to(index_br))) - .bind("127.0.0.1:8088") - .unwrap() - .run() - .unwrap(); + HttpServer::new(|| { + App::new() + .wrap(middleware::Compress::default()) + .route("/", web::get().to(index_br)) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } +// diff --git a/examples/responses/src/brotli_two.rs b/examples/responses/src/brotli_two.rs new file mode 100644 index 0000000..cdd79f4 --- /dev/null +++ b/examples/responses/src/brotli_two.rs @@ -0,0 +1,21 @@ +// +use actix_web::{http::ContentEncoding, middleware::BodyEncoding, HttpResponse}; + +fn index_br() -> HttpResponse { + HttpResponse::Ok().body("data") +} + +pub fn main() { + use actix_web::{middleware, web, App, HttpServer}; + + HttpServer::new(|| { + App::new() + .wrap(middleware::Compress::new(ContentEncoding::Br)) + .route("/", web::get().to(index_br)) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); +} +// diff --git a/examples/responses/src/compress.rs b/examples/responses/src/compress.rs new file mode 100644 index 0000000..4bd40d9 --- /dev/null +++ b/examples/responses/src/compress.rs @@ -0,0 +1,21 @@ +// +use actix_web::{http::ContentEncoding, middleware, HttpResponse}; + +fn index_br() -> HttpResponse { + HttpResponse::Ok().body("data") +} + +pub fn main() { + use actix_web::{web, App, HttpServer}; + + HttpServer::new(|| { + App::new() + .wrap(middleware::Compress::default()) + .route("/", web::get().to(index_br)) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); +} +// diff --git a/examples/responses/src/identity.rs b/examples/responses/src/identity.rs index 63fb968..2d759d1 100644 --- a/examples/responses/src/identity.rs +++ b/examples/responses/src/identity.rs @@ -1,5 +1,7 @@ // -use actix_web::{http::ContentEncoding, middleware::BodyEncoding, HttpResponse}; +use actix_web::{ + http::ContentEncoding, middleware, middleware::BodyEncoding, HttpResponse, +}; fn index() -> HttpResponse { HttpResponse::Ok() @@ -7,14 +9,18 @@ fn index() -> HttpResponse { .encoding(ContentEncoding::Identity) .body("data") } -// pub fn main() { use actix_web::{web, App, HttpServer}; - HttpServer::new(|| App::new().route("/", web::get().to(index))) - .bind("127.0.0.1:8088") - .unwrap() - .run() - .unwrap(); + HttpServer::new(|| { + App::new() + .wrap(middleware::Compress::default()) + .route("/", web::get().to(index)) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } +// diff --git a/examples/responses/src/identity_two.rs b/examples/responses/src/identity_two.rs index 8e6020f..494e9d9 100644 --- a/examples/responses/src/identity_two.rs +++ b/examples/responses/src/identity_two.rs @@ -1,6 +1,7 @@ // use actix_web::{ - http::ContentEncoding, middleware::BodyEncoding, HttpRequest, HttpResponse, + http::ContentEncoding, middleware, middleware::BodyEncoding, HttpRequest, + HttpResponse, }; static HELLO_WORLD: &[u8] = &[ @@ -20,9 +21,13 @@ pub fn index(_req: HttpRequest) -> HttpResponse { pub fn main() { use actix_web::{web, App, HttpServer}; - HttpServer::new(|| App::new().route("/", web::get().to(index))) - .bind("127.0.0.1:8088") - .unwrap() - .run() - .unwrap(); + HttpServer::new(|| { + App::new() + .wrap(middleware::Compress::default()) + .route("/", web::get().to(index)) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } diff --git a/examples/responses/src/main.rs b/examples/responses/src/main.rs index 1d63343..61e4679 100644 --- a/examples/responses/src/main.rs +++ b/examples/responses/src/main.rs @@ -1,6 +1,7 @@ pub mod auto; pub mod brotli; pub mod chunked; +pub mod compress; pub mod identity; pub mod identity_two; pub mod json_resp; diff --git a/examples/url-dispatch/Cargo.toml b/examples/url-dispatch/Cargo.toml index 761a7b6..b7914ca 100644 --- a/examples/url-dispatch/Cargo.toml +++ b/examples/url-dispatch/Cargo.toml @@ -5,7 +5,7 @@ edition = "2018" workspace = "../" [dependencies] -actix = "0.7" +actix = "0.8" actix-web = "1.0" futures = "0.1" openssl = "0.10" From 4833874c5da64e9beffd07e7a60881fb19f2d75c Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Wed, 26 Jun 2019 19:18:43 -0400 Subject: [PATCH 64/68] Moves everything into the cargo workspace. --- examples/Cargo.toml | 4 ++-- examples/errors/src/main.rs | 13 ++++++------- examples/responses/src/compress.rs | 2 +- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/examples/Cargo.toml b/examples/Cargo.toml index b5dc000..a9d2fb1 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -19,12 +19,12 @@ members = [ "middleware", "static-files", "http2", -] -exclude = [ "testing", "async-handlers", "websockets", "request-handlers", +] +exclude = [ "og_databases", "sentry", ] diff --git a/examples/errors/src/main.rs b/examples/errors/src/main.rs index 0f46d09..97c55c3 100644 --- a/examples/errors/src/main.rs +++ b/examples/errors/src/main.rs @@ -22,12 +22,11 @@ fn index(_req: HttpRequest) -> Result<&'static str, MyError> { // pub fn main() { - // use actix_web::{web, App, HttpServer}; + use actix_web::{web, App, HttpServer}; - // HttpServer::new(|| App::new().route("/", web::get().to(index))) - // .bind("127.0.0.1:8088") - // .unwrap() - // .run() - // .unwrap(); - recommend_two::main(); + HttpServer::new(|| App::new().route("/", web::get().to(index))) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } diff --git a/examples/responses/src/compress.rs b/examples/responses/src/compress.rs index 4bd40d9..105b76b 100644 --- a/examples/responses/src/compress.rs +++ b/examples/responses/src/compress.rs @@ -1,5 +1,5 @@ // -use actix_web::{http::ContentEncoding, middleware, HttpResponse}; +use actix_web::{middleware, HttpResponse}; fn index_br() -> HttpResponse { HttpResponse::Ok().body("data") From cbf046b1f05da061abfbc64905d97c60553c6b77 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Fri, 28 Jun 2019 12:09:51 -0400 Subject: [PATCH 65/68] updates flexible responders. --- examples/flexible-responders/src/main.rs | 2 +- layouts/index.html | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/flexible-responders/src/main.rs b/examples/flexible-responders/src/main.rs index dbe8e28..1459ca1 100644 --- a/examples/flexible-responders/src/main.rs +++ b/examples/flexible-responders/src/main.rs @@ -11,7 +11,7 @@ fn hello_world() -> impl Responder { "Hello World!" } -fn current_temperature(_req: HttpRequest) -> impl Responder { +fn current_temperature() -> impl Responder { web::Json(Measurement { temperature: 42.3 }) } diff --git a/layouts/index.html b/layouts/index.html index 4b0fd05..53c147c 100644 --- a/layouts/index.html +++ b/layouts/index.html @@ -70,6 +70,7 @@ fn main() { to return consistent responses from your APIs.

{{ highlight `#[derive(Serialize)] +#[derive(Serialize)] struct Measurement { temperature: f32, } @@ -78,7 +79,7 @@ fn hello_world() -> impl Responder { "Hello World!" } -fn current_temperature(_req: HttpRequest) -> impl Responder { +fn current_temperature() -> impl Responder { web::Json(Measurement { temperature: 42.3 }) }` "rust" "" }}
From 5133ab874df2a7075d8e781241a727e9012cb80e Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Fri, 28 Jun 2019 13:31:30 -0400 Subject: [PATCH 66/68] Final fixes before requesting review. --- content/docs/application.md | 2 +- content/docs/errors.md | 2 +- content/docs/handlers.md | 6 +++--- content/docs/request.md | 4 +--- content/docs/url-dispatch.md | 2 +- examples/application/src/app.rs | 4 ++-- examples/async-handlers/src/async_stream.rs | 8 ++++---- examples/async-handlers/src/main.rs | 20 +++++++++++++------ examples/async-handlers/src/stream.rs | 6 ++++-- examples/either/src/main.rs | 12 ++++++++--- examples/errors/src/helpers.rs | 4 ++-- examples/errors/src/main.rs | 2 +- examples/errors/src/override_error.rs | 8 ++++---- examples/extractors/src/form.rs | 4 +++- examples/extractors/src/json_one.rs | 4 +++- examples/extractors/src/json_two.rs | 4 +++- examples/extractors/src/multiple.rs | 4 +++- examples/extractors/src/path_one.rs | 4 +++- examples/extractors/src/path_three.rs | 4 +++- examples/extractors/src/path_two.rs | 4 +++- examples/extractors/src/query.rs | 4 +++- examples/getting-started/src/main.rs | 4 ++-- examples/request-handlers/src/handlers_arc.rs | 4 +++- examples/request-handlers/src/main.rs | 4 +++- examples/responder-trait/src/main.rs | 4 +++- examples/responses/src/chunked.rs | 4 ++-- examples/responses/src/identity_two.rs | 5 ++--- examples/responses/src/main.rs | 3 +-- examples/static-files/src/main.rs | 4 +++- examples/url-dispatch/src/guard.rs | 6 +++--- examples/url-dispatch/src/minfo.rs | 6 +++--- examples/url-dispatch/src/norm.rs | 4 ++-- examples/url-dispatch/src/norm2.rs | 12 +++++------ examples/url-dispatch/src/path.rs | 4 ++-- examples/url-dispatch/src/path2.rs | 4 ++-- examples/url-dispatch/src/pbuf.rs | 4 ++-- examples/url-dispatch/src/scope.rs | 4 ++-- examples/url-dispatch/src/url_ext.rs | 4 ++-- examples/url-dispatch/src/urls.rs | 4 ++-- layouts/index.html | 1 - 40 files changed, 116 insertions(+), 81 deletions(-) diff --git a/content/docs/application.md b/content/docs/application.md index 9da0f0c..95df909 100644 --- a/content/docs/application.md +++ b/content/docs/application.md @@ -43,7 +43,7 @@ as the first application, it would match all incoming requests. ## State Application state is shared with all routes and resources within the same scope. State -can be accessed with `web::Data` as read-only, but interior mutability with +can be accessed with the `web::Data` extractor as read-only, but interior mutability with `Cell` can be used to achieve state mutability. State is also available for route matching guards and middlewares. diff --git a/content/docs/errors.md b/content/docs/errors.md index 25c30d1..50c5baf 100644 --- a/content/docs/errors.md +++ b/content/docs/errors.md @@ -40,7 +40,7 @@ converted into an `HttpInternalServerError`: ```rust use std::io; -fn index(req: &HttpRequest) -> io::Result { +fn index(_req: HttpRequest) -> io::Result { Ok(fs::NamedFile::open("static/index.html")?) } ``` diff --git a/content/docs/handlers.md b/content/docs/handlers.md index c571190..d67cb33 100644 --- a/content/docs/handlers.md +++ b/content/docs/handlers.md @@ -22,13 +22,13 @@ such as `&'static str`, `String`, etc. Examples of valid handlers: ```rust -fn index(req: &HttpRequest) -> &'static str { +fn index(_req: HttpRequest) -> &'static str { "Hello world!" } ``` ```rust -fn index(req: HttpRequest) -> String { +fn index(_req: HttpRequest) -> String { "Hello world!".to_owned() } ``` @@ -37,7 +37,7 @@ You can also change the signature to return `impl Responder` which works well if complex types are involved. ```rust -fn index(req: HttpRequest) -> impl Responder { +fn index(_req: HttpRequest) -> impl Responder { Bytes::from_static("Hello world!") } ``` diff --git a/content/docs/request.md b/content/docs/request.md index 4c93f0c..ad71c29 100644 --- a/content/docs/request.md +++ b/content/docs/request.md @@ -49,9 +49,7 @@ is decompressed. # Multipart body -Actix provides multipart stream support with an external crate, [`actix-multipart`][multipartcrate]. - -The following demonstrates multipart stream handling for a simple form: +Actix-web provides multipart stream support with an external crate, [`actix-multipart`][multipartcrate]. > A full example is available in the [examples directory][multipartexample]. diff --git a/content/docs/url-dispatch.md b/content/docs/url-dispatch.md index 0a0f5e3..c7f40e1 100644 --- a/content/docs/url-dispatch.md +++ b/content/docs/url-dispatch.md @@ -83,7 +83,7 @@ against a URL path pattern. `path` represents the path portion of the URL that w The way that *actix-web* 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 routes were declared via `App::service()` 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 guard arguments. All route diff --git a/examples/application/src/app.rs b/examples/application/src/app.rs index 1f53cd3..7dadc5c 100644 --- a/examples/application/src/app.rs +++ b/examples/application/src/app.rs @@ -1,7 +1,7 @@ // -use actix_web::{web, App, HttpRequest, Responder}; +use actix_web::{web, App, Responder}; -fn index(_req: HttpRequest) -> impl Responder { +fn index() -> impl Responder { "Hello world!" } diff --git a/examples/async-handlers/src/async_stream.rs b/examples/async-handlers/src/async_stream.rs index b954cb0..ddc6ad6 100644 --- a/examples/async-handlers/src/async_stream.rs +++ b/examples/async-handlers/src/async_stream.rs @@ -3,12 +3,10 @@ fn is_error() -> bool { } // -use actix_web::{error, web, App, Error, HttpRequest, HttpResponse, HttpServer}; +use actix_web::{error, Error, HttpResponse}; use futures::future::{result, Future}; -fn index( - _req: HttpRequest, -) -> Result>, Error> { +fn index() -> Result>, Error> { if is_error() { Err(error::ErrorBadRequest("bad request")) } else { @@ -20,6 +18,8 @@ fn index( // pub fn main() { + use actix_web::{web, App, HttpServer}; + HttpServer::new(|| App::new().route("/", web::to_async(index))) .bind("127.0.0.1:8088") .unwrap() diff --git a/examples/async-handlers/src/main.rs b/examples/async-handlers/src/main.rs index f86d286..05a4ff4 100644 --- a/examples/async-handlers/src/main.rs +++ b/examples/async-handlers/src/main.rs @@ -1,22 +1,30 @@ pub mod async_stream; pub mod stream; // -use actix_web::{web, App, Error, HttpRequest, HttpResponse}; +use actix_web::{Error, HttpResponse}; use futures::future::{ok, Future}; -fn index(_req: HttpRequest) -> Box> { +fn index() -> Box> { Box::new(ok::<_, Error>( HttpResponse::Ok().content_type("text/html").body("Hello!"), )) } -fn index2(_req: HttpRequest) -> Box> { +fn index2() -> Box> { Box::new(ok::<_, Error>("Welcome!")) } fn main() { - App::new() - .route("/async", web::to_async(index)) - .route("/", web::to_async(index2)); + use actix_web::{web, App, HttpServer}; + + HttpServer::new(|| { + App::new() + .route("/async", web::to_async(index)) + .route("/", web::to_async(index2)) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // diff --git a/examples/async-handlers/src/stream.rs b/examples/async-handlers/src/stream.rs index abcefb1..79424cd 100644 --- a/examples/async-handlers/src/stream.rs +++ b/examples/async-handlers/src/stream.rs @@ -1,9 +1,9 @@ // -use actix_web::{web, App, Error, HttpRequest, HttpResponse, HttpServer}; +use actix_web::{Error, HttpResponse}; use bytes::Bytes; use futures::stream::once; -fn index(_req: HttpRequest) -> HttpResponse { +fn index() -> HttpResponse { let body = once::(Ok(Bytes::from_static(b"test"))); HttpResponse::Ok() @@ -12,6 +12,8 @@ fn index(_req: HttpRequest) -> HttpResponse { } pub fn main() { + use actix_web::{web, App, HttpServer}; + HttpServer::new(|| App::new().route("/async", web::to_async(index))) .bind("127.0.0.1:8088") .unwrap() diff --git a/examples/either/src/main.rs b/examples/either/src/main.rs index 3ecd892..3c6af05 100644 --- a/examples/either/src/main.rs +++ b/examples/either/src/main.rs @@ -1,11 +1,11 @@ // -use actix_web::{web, App, Either, Error, HttpRequest, HttpResponse}; +use actix_web::{Either, Error, HttpResponse}; use futures::future::{ok, Future}; type RegisterResult = Either>>; -fn index(_req: HttpRequest) -> RegisterResult { +fn index() -> RegisterResult { if is_a_variant() { // <- choose variant A Either::A(HttpResponse::BadRequest().body("Bad data")) @@ -20,7 +20,13 @@ fn index(_req: HttpRequest) -> RegisterResult { } fn main() { - App::new().route("/", web::get().to(index)); + use actix_web::{web, App, HttpServer}; + + HttpServer::new(|| App::new().route("/", web::get().to(index))) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); } // diff --git a/examples/errors/src/helpers.rs b/examples/errors/src/helpers.rs index 17da403..6dc01fd 100644 --- a/examples/errors/src/helpers.rs +++ b/examples/errors/src/helpers.rs @@ -1,13 +1,13 @@ use actix_web::{web, App}; // -use actix_web::{error, HttpRequest, Result}; +use actix_web::{error, Result}; #[derive(Debug)] struct MyError { name: &'static str, } -pub fn index(_req: HttpRequest) -> Result<&'static str> { +pub fn index() -> Result<&'static str> { let result: Result<&'static str, MyError> = Err(MyError { name: "test error" }); Ok(result.map_err(|e| error::ErrorBadRequest(e.name))?) diff --git a/examples/errors/src/main.rs b/examples/errors/src/main.rs index 97c55c3..5c5a69a 100644 --- a/examples/errors/src/main.rs +++ b/examples/errors/src/main.rs @@ -16,7 +16,7 @@ pub struct MyError { // Use default implementation for `error_response()` method impl error::ResponseError for MyError {} -fn index(_req: HttpRequest) -> Result<&'static str, MyError> { +fn index() -> Result<&'static str, MyError> { Err(MyError { name: "test" }) } // diff --git a/examples/errors/src/override_error.rs b/examples/errors/src/override_error.rs index 10da432..0f354cd 100644 --- a/examples/errors/src/override_error.rs +++ b/examples/errors/src/override_error.rs @@ -1,6 +1,6 @@ use actix_web::{web, App}; // -use actix_web::{error, http, HttpRequest, HttpResponse}; +use actix_web::{error, http, HttpResponse}; use failure::Fail; #[derive(Fail, Debug)] @@ -25,16 +25,16 @@ impl error::ResponseError for MyError { } } -fn index(_req: HttpRequest) -> Result<&'static str, MyError> { +fn index() -> Result<&'static str, MyError> { Err(MyError::BadClientData) } // -fn error2(_req: HttpRequest) -> Result<&'static str, MyError> { +fn error2() -> Result<&'static str, MyError> { Err(MyError::InternalError) } -fn error3(_req: HttpRequest) -> Result<&'static str, MyError> { +fn error3() -> Result<&'static str, MyError> { Err(MyError::Timeout) } diff --git a/examples/extractors/src/form.rs b/examples/extractors/src/form.rs index 394a255..daf58cf 100644 --- a/examples/extractors/src/form.rs +++ b/examples/extractors/src/form.rs @@ -1,5 +1,5 @@ //
-use actix_web::{web, App, HttpServer, Result}; +use actix_web::{web, Result}; use serde::Deserialize; #[derive(Deserialize)] @@ -16,6 +16,8 @@ fn index(form: web::Form) -> Result { // pub fn main() { + use actix_web::{App, HttpServer}; + HttpServer::new(|| App::new().route("/", web::post().to(index))) .bind("127.0.0.1:8088") .unwrap() diff --git a/examples/extractors/src/json_one.rs b/examples/extractors/src/json_one.rs index 255959d..d1600ce 100644 --- a/examples/extractors/src/json_one.rs +++ b/examples/extractors/src/json_one.rs @@ -1,5 +1,5 @@ // -use actix_web::{web, App, HttpServer, Result}; +use actix_web::{web, Result}; use serde::Deserialize; #[derive(Deserialize)] @@ -14,6 +14,8 @@ fn index(info: web::Json) -> Result { // pub fn main() { + use actix_web::{App, HttpServer}; + HttpServer::new(|| App::new().route("/", web::post().to(index))) .bind("127.0.0.1:8088") .unwrap() diff --git a/examples/extractors/src/json_two.rs b/examples/extractors/src/json_two.rs index e5e8a22..a61a6cf 100644 --- a/examples/extractors/src/json_two.rs +++ b/examples/extractors/src/json_two.rs @@ -1,5 +1,5 @@ // -use actix_web::{error, web, App, FromRequest, HttpResponse, HttpServer, Responder}; +use actix_web::{error, web, FromRequest, HttpResponse, Responder}; use serde::Deserialize; #[derive(Deserialize)] @@ -13,6 +13,8 @@ fn index(info: web::Json) -> impl Responder { } pub fn main() { + use actix_web::{App, HttpServer}; + HttpServer::new(|| { App::new().service( web::resource("/") diff --git a/examples/extractors/src/multiple.rs b/examples/extractors/src/multiple.rs index 118dd5c..ed9cad1 100644 --- a/examples/extractors/src/multiple.rs +++ b/examples/extractors/src/multiple.rs @@ -1,5 +1,5 @@ // -use actix_web::{web, App, HttpServer}; +use actix_web::web; use serde::Deserialize; #[derive(Deserialize)] @@ -15,6 +15,8 @@ fn index((path, query): (web::Path<(u32, String)>, web::Query)) -> String } pub fn main() { + use actix_web::{App, HttpServer}; + HttpServer::new(|| { App::new().route( "/users/{userid}/{friend}", // <- define path parameters diff --git a/examples/extractors/src/path_one.rs b/examples/extractors/src/path_one.rs index 0b83de8..1440b8e 100644 --- a/examples/extractors/src/path_one.rs +++ b/examples/extractors/src/path_one.rs @@ -1,5 +1,5 @@ // -use actix_web::{web, App, HttpServer, Result}; +use actix_web::{web, Result}; /// extract path info from "/users/{userid}/{friend}" url /// {userid} - - deserializes to a u32 @@ -9,6 +9,8 @@ fn index(info: web::Path<(u32, String)>) -> Result { } pub fn main() { + use actix_web::{App, HttpServer}; + HttpServer::new(|| { App::new().route( "/users/{userid}/{friend}", // <- define path parameters diff --git a/examples/extractors/src/path_three.rs b/examples/extractors/src/path_three.rs index 9ca71c9..68badaa 100644 --- a/examples/extractors/src/path_three.rs +++ b/examples/extractors/src/path_three.rs @@ -1,4 +1,4 @@ -use actix_web::{web, App, HttpRequest, HttpServer, Result}; +use actix_web::{web, HttpRequest, Result}; // fn index(req: HttpRequest) -> Result { @@ -9,6 +9,8 @@ fn index(req: HttpRequest) -> Result { } pub fn main() { + use actix_web::{App, HttpServer}; + HttpServer::new(|| { App::new().route( "/users/{userid}/{friend}", // <- define path parameters diff --git a/examples/extractors/src/path_two.rs b/examples/extractors/src/path_two.rs index aa836d6..ee5e357 100644 --- a/examples/extractors/src/path_two.rs +++ b/examples/extractors/src/path_two.rs @@ -1,5 +1,5 @@ // -use actix_web::{web, App, HttpServer, Result}; +use actix_web::{web, Result}; use serde::Deserialize; #[derive(Deserialize)] @@ -14,6 +14,8 @@ fn index(info: web::Path) -> Result { } pub fn main() { + use actix_web::{App, HttpServer}; + HttpServer::new(|| { App::new().route( "/users/{userid}/{friend}", // <- define path parameters diff --git a/examples/extractors/src/query.rs b/examples/extractors/src/query.rs index 10af0ce..74575ab 100644 --- a/examples/extractors/src/query.rs +++ b/examples/extractors/src/query.rs @@ -1,5 +1,5 @@ // -use actix_web::{web, App, HttpServer}; +use actix_web::web; use serde::Deserialize; #[derive(Deserialize)] @@ -14,6 +14,8 @@ fn index(info: web::Query) -> String { // pub fn main() { + use actix_web::{App, HttpServer}; + HttpServer::new(|| App::new().route("/", web::get().to(index))) .bind("127.0.0.1:8088") .unwrap() diff --git a/examples/getting-started/src/main.rs b/examples/getting-started/src/main.rs index 821e428..4b2cfa6 100644 --- a/examples/getting-started/src/main.rs +++ b/examples/getting-started/src/main.rs @@ -1,11 +1,11 @@ // -use actix_web::{web, App, HttpRequest, HttpResponse, HttpServer, Responder}; +use actix_web::{web, App, HttpResponse, HttpServer, Responder}; fn index() -> impl Responder { HttpResponse::Ok().body("Hello world!") } -fn index2(_req: HttpRequest) -> impl Responder { +fn index2() -> impl Responder { HttpResponse::Ok().body("Hello world again!") } // diff --git a/examples/request-handlers/src/handlers_arc.rs b/examples/request-handlers/src/handlers_arc.rs index f3002d8..cd9acbe 100644 --- a/examples/request-handlers/src/handlers_arc.rs +++ b/examples/request-handlers/src/handlers_arc.rs @@ -1,5 +1,5 @@ // -use actix_web::{web, App, HttpServer, Responder}; +use actix_web::{web, Responder}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; @@ -19,6 +19,8 @@ fn add_one(data: web::Data) -> impl Responder { } pub fn main() { + use actix_web::{App, HttpServer}; + let data = AppState { count: Arc::new(AtomicUsize::new(0)), }; diff --git a/examples/request-handlers/src/main.rs b/examples/request-handlers/src/main.rs index 48d7842..9fb1734 100644 --- a/examples/request-handlers/src/main.rs +++ b/examples/request-handlers/src/main.rs @@ -1,6 +1,6 @@ pub mod handlers_arc; // -use actix_web::{web, App, HttpServer, Responder}; +use actix_web::{web, Responder}; use std::cell::Cell; #[derive(Clone)] @@ -20,6 +20,8 @@ fn add_one(data: web::Data) -> impl Responder { } fn main() { + use actix_web::{App, HttpServer}; + let data = AppState { count: Cell::new(0), }; diff --git a/examples/responder-trait/src/main.rs b/examples/responder-trait/src/main.rs index 869ea54..5b199b3 100644 --- a/examples/responder-trait/src/main.rs +++ b/examples/responder-trait/src/main.rs @@ -1,5 +1,5 @@ // -use actix_web::{web, App, Error, HttpRequest, HttpResponse, HttpServer, Responder}; +use actix_web::{Error, HttpRequest, HttpResponse, Responder}; use serde::Serialize; #[derive(Serialize)] @@ -28,6 +28,8 @@ fn index() -> impl Responder { // fn main() { + use actix_web::{web, App, HttpServer}; + HttpServer::new(|| App::new().route("/", web::get().to(index))) .bind("127.0.0.1:8088") .unwrap() diff --git a/examples/responses/src/chunked.rs b/examples/responses/src/chunked.rs index 50899cb..0c80ed4 100644 --- a/examples/responses/src/chunked.rs +++ b/examples/responses/src/chunked.rs @@ -1,4 +1,4 @@ -// +// // // use actix_web::{web, HttpRequest, HttpResponse}; // use bytes::Bytes; // use futures::stream::once; @@ -10,7 +10,7 @@ // b"data", // )))))) // } -// +// // // pub fn main() { // use actix_web::{web, App, HttpServer}; diff --git a/examples/responses/src/identity_two.rs b/examples/responses/src/identity_two.rs index 494e9d9..62839ff 100644 --- a/examples/responses/src/identity_two.rs +++ b/examples/responses/src/identity_two.rs @@ -1,7 +1,6 @@ // use actix_web::{ - http::ContentEncoding, middleware, middleware::BodyEncoding, HttpRequest, - HttpResponse, + http::ContentEncoding, middleware, middleware::BodyEncoding, HttpResponse, }; static HELLO_WORLD: &[u8] = &[ @@ -10,7 +9,7 @@ static HELLO_WORLD: &[u8] = &[ 0x0c, 0x00, 0x00, 0x00, ]; -pub fn index(_req: HttpRequest) -> HttpResponse { +pub fn index() -> HttpResponse { HttpResponse::Ok() .encoding(ContentEncoding::Identity) .header("content-encoding", "gzip") diff --git a/examples/responses/src/main.rs b/examples/responses/src/main.rs index 61e4679..d41f2b7 100644 --- a/examples/responses/src/main.rs +++ b/examples/responses/src/main.rs @@ -7,11 +7,10 @@ pub mod identity_two; pub mod json_resp; // -use actix_web::{http::ContentEncoding, middleware::BodyEncoding, HttpResponse}; +use actix_web::HttpResponse; fn index() -> HttpResponse { HttpResponse::Ok() - .encoding(ContentEncoding::Br) .content_type("plain/text") .header("X-Hdr", "sample") .body("data") diff --git a/examples/static-files/src/main.rs b/examples/static-files/src/main.rs index 1e06d23..a30d5db 100644 --- a/examples/static-files/src/main.rs +++ b/examples/static-files/src/main.rs @@ -4,7 +4,7 @@ pub mod directory; // use actix_files::NamedFile; -use actix_web::{web, App, HttpRequest, HttpServer, Result}; +use actix_web::{HttpRequest, Result}; use std::path::PathBuf; fn index(req: HttpRequest) -> Result { @@ -13,6 +13,8 @@ fn index(req: HttpRequest) -> Result { } fn main() { + use actix_web::{web, App, HttpServer}; + HttpServer::new(|| App::new().route("/{filename:.*}", web::get().to(index))) .bind("127.0.0.1:8088") .unwrap() diff --git a/examples/url-dispatch/src/guard.rs b/examples/url-dispatch/src/guard.rs index 19bd514..1ef5d6b 100644 --- a/examples/url-dispatch/src/guard.rs +++ b/examples/url-dispatch/src/guard.rs @@ -1,7 +1,5 @@ // -use actix_web::{ - dev::RequestHead, guard::Guard, http, web, App, HttpResponse, HttpServer, -}; +use actix_web::{dev::RequestHead, guard::Guard, http, HttpResponse}; struct ContentTypeHeader; @@ -12,6 +10,8 @@ impl Guard for ContentTypeHeader { } pub fn main() { + use actix_web::{web, App, HttpServer}; + HttpServer::new(|| { App::new().route( "/", diff --git a/examples/url-dispatch/src/minfo.rs b/examples/url-dispatch/src/minfo.rs index 920611a..7c993d7 100644 --- a/examples/url-dispatch/src/minfo.rs +++ b/examples/url-dispatch/src/minfo.rs @@ -1,5 +1,5 @@ // -use actix_web::{web, App, HttpRequest, Result}; +use actix_web::{HttpRequest, HttpResponse, Result}; fn index(req: HttpRequest) -> Result { let v1: u8 = req.match_info().get("v1").unwrap().parse().unwrap(); @@ -9,12 +9,12 @@ fn index(req: HttpRequest) -> Result { } pub fn main() { - use actix_web::HttpServer; + use actix_web::{web, App, HttpServer}; HttpServer::new(|| { App::new() .route("/a/{v1}/{v2}/", web::get().to(index)) - .route("", web::get().to(|| actix_web::HttpResponse::Ok())) + .route("", web::get().to(|| HttpResponse::Ok())) }) .bind("127.0.0.1:8088") .unwrap() diff --git a/examples/url-dispatch/src/norm.rs b/examples/url-dispatch/src/norm.rs index 75723d0..4d1abf7 100644 --- a/examples/url-dispatch/src/norm.rs +++ b/examples/url-dispatch/src/norm.rs @@ -1,12 +1,12 @@ // -use actix_web::{middleware, web, App, HttpResponse}; +use actix_web::{middleware, HttpResponse}; fn index() -> HttpResponse { HttpResponse::Ok().body("Hello") } pub fn main() { - use actix_web::HttpServer; + use actix_web::{web, App, HttpServer}; HttpServer::new(|| { App::new() diff --git a/examples/url-dispatch/src/norm2.rs b/examples/url-dispatch/src/norm2.rs index bd0f019..a704fa7 100644 --- a/examples/url-dispatch/src/norm2.rs +++ b/examples/url-dispatch/src/norm2.rs @@ -1,3 +1,9 @@ +use actix_web::HttpResponse; + +fn index() -> HttpResponse { + HttpResponse::Ok().body("Hello") +} + // use actix_web::{http::Method, middleware, web, App, HttpServer}; @@ -14,9 +20,3 @@ pub fn main() { .unwrap(); } // - -use actix_web::HttpResponse; - -fn index() -> HttpResponse { - HttpResponse::Ok().body("Hello") -} diff --git a/examples/url-dispatch/src/path.rs b/examples/url-dispatch/src/path.rs index 1c84400..11e2a99 100644 --- a/examples/url-dispatch/src/path.rs +++ b/examples/url-dispatch/src/path.rs @@ -1,12 +1,12 @@ // -use actix_web::{web, App, Result}; +use actix_web::{web, Result}; fn index(info: web::Path<(String, u32)>) -> Result { Ok(format!("Welcome {}! id: {}", info.0, info.1)) } pub fn main() { - use actix_web::HttpServer; + use actix_web::{App, HttpServer}; HttpServer::new(|| { App::new().route( diff --git a/examples/url-dispatch/src/path2.rs b/examples/url-dispatch/src/path2.rs index 783949f..799a412 100644 --- a/examples/url-dispatch/src/path2.rs +++ b/examples/url-dispatch/src/path2.rs @@ -1,5 +1,5 @@ // -use actix_web::{web, App, Result}; +use actix_web::{web, Result}; use serde::Deserialize; #[derive(Deserialize)] @@ -13,7 +13,7 @@ fn index(info: web::Path) -> Result { } pub fn main() { - use actix_web::HttpServer; + use actix_web::{App, HttpServer}; HttpServer::new(|| { App::new().route( diff --git a/examples/url-dispatch/src/pbuf.rs b/examples/url-dispatch/src/pbuf.rs index 1319ad0..36b7e7c 100644 --- a/examples/url-dispatch/src/pbuf.rs +++ b/examples/url-dispatch/src/pbuf.rs @@ -1,5 +1,5 @@ // -use actix_web::{web, App, HttpRequest, Result}; +use actix_web::{HttpRequest, Result}; use std::path::PathBuf; fn index(req: HttpRequest) -> Result { @@ -8,7 +8,7 @@ fn index(req: HttpRequest) -> Result { } pub fn main() { - use actix_web::HttpServer; + use actix_web::{web, App, HttpServer}; HttpServer::new(|| App::new().route(r"/a/{tail:.*}", web::get().to(index))) .bind("127.0.0.1:8088") diff --git a/examples/url-dispatch/src/scope.rs b/examples/url-dispatch/src/scope.rs index 388acef..11ac91e 100644 --- a/examples/url-dispatch/src/scope.rs +++ b/examples/url-dispatch/src/scope.rs @@ -5,8 +5,8 @@ fn show_users() -> HttpResponse { HttpResponse::Ok().body("Show users") } -fn user_detail(_path: web::Path<(u32,)>) -> HttpResponse { - HttpResponse::Ok().body("User detail") +fn user_detail(path: web::Path<(u32,)>) -> HttpResponse { + HttpResponse::Ok().body(format!("User detail: {}", path.0)) } pub fn main() { diff --git a/examples/url-dispatch/src/url_ext.rs b/examples/url-dispatch/src/url_ext.rs index fafb66d..7de8e6e 100644 --- a/examples/url-dispatch/src/url_ext.rs +++ b/examples/url-dispatch/src/url_ext.rs @@ -1,5 +1,5 @@ // -use actix_web::{web, App, HttpRequest, Responder}; +use actix_web::{HttpRequest, Responder}; fn index(req: HttpRequest) -> impl Responder { let url = req.url_for("youtube", &["oHg5SJYRHA0"]).unwrap(); @@ -9,7 +9,7 @@ fn index(req: HttpRequest) -> impl Responder { } pub fn main() { - use actix_web::HttpServer; + use actix_web::{web, App, HttpServer}; HttpServer::new(|| { App::new() diff --git a/examples/url-dispatch/src/urls.rs b/examples/url-dispatch/src/urls.rs index 24cff65..8fc03fb 100644 --- a/examples/url-dispatch/src/urls.rs +++ b/examples/url-dispatch/src/urls.rs @@ -1,5 +1,5 @@ // -use actix_web::{guard, http::header, web, App, HttpRequest, HttpResponse, Result}; +use actix_web::{guard, http::header, HttpRequest, HttpResponse, Result}; fn index(req: HttpRequest) -> Result { let url = req.url_for("foo", &["1", "2", "3"])?; // <- generate url for "foo" resource @@ -10,7 +10,7 @@ fn index(req: HttpRequest) -> Result { } pub fn main() { - use actix_web::HttpServer; + use actix_web::{web, App, HttpServer}; HttpServer::new(|| { App::new() diff --git a/layouts/index.html b/layouts/index.html index 53c147c..d0e1648 100644 --- a/layouts/index.html +++ b/layouts/index.html @@ -70,7 +70,6 @@ fn main() { to return consistent responses from your APIs.

{{ highlight `#[derive(Serialize)] -#[derive(Serialize)] struct Measurement { temperature: f32, } From eb58a8692c7cc043391c119947bb9b7ae485007b Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Fri, 28 Jun 2019 14:22:51 -0400 Subject: [PATCH 67/68] Makes clippy happy. --- examples/errors/src/main.rs | 2 +- examples/flexible-responders/src/main.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/errors/src/main.rs b/examples/errors/src/main.rs index 5c5a69a..f2d1762 100644 --- a/examples/errors/src/main.rs +++ b/examples/errors/src/main.rs @@ -4,7 +4,7 @@ pub mod recommend_one; pub mod recommend_two; // -use actix_web::{error, HttpRequest, Result}; +use actix_web::{error, Result}; use failure::Fail; #[derive(Fail, Debug)] diff --git a/examples/flexible-responders/src/main.rs b/examples/flexible-responders/src/main.rs index 1459ca1..fd56f1e 100644 --- a/examples/flexible-responders/src/main.rs +++ b/examples/flexible-responders/src/main.rs @@ -1,4 +1,4 @@ -use actix_web::{web, App, HttpRequest, HttpServer, Responder}; +use actix_web::{web, App, HttpServer, Responder}; use serde::Serialize; // From 6f95771c34f6892aab0a5f607f341e0c11c411c4 Mon Sep 17 00:00:00 2001 From: Cameron Dershem Date: Fri, 28 Jun 2019 14:50:15 -0400 Subject: [PATCH 68/68] Adds logging example to errors chapter. --- content/docs/errors.md | 6 ++++++ examples/errors/Cargo.toml | 2 +- examples/errors/src/logging.rs | 38 ++++++++++++++++++++++++++++++++++ examples/errors/src/main.rs | 1 + 4 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 examples/errors/src/logging.rs diff --git a/content/docs/errors.md b/content/docs/errors.md index 50c5baf..6dd697a 100644 --- a/content/docs/errors.md +++ b/content/docs/errors.md @@ -128,6 +128,12 @@ By dividing errors into those which are user facing and those which are not, we can ensure that we don't accidentally expose users to errors thrown by application internals which they weren't meant to see. +# Error Logging + +This is a basic example using `middleware::Logger`: + +{{< include-example example="errors" file="logging.rs" section="logging" >}} + [actixerror]: https://docs.rs/actix-web/1.0.2/actix_web/error/struct.Error.html [errorhelpers]: https://docs.rs/actix-web/1.0.2/actix_web/trait.ResponseError.html [failure]: https://github.com/rust-lang-nursery/failure diff --git a/examples/errors/Cargo.toml b/examples/errors/Cargo.toml index 6fcbcbd..0b605e2 100644 --- a/examples/errors/Cargo.toml +++ b/examples/errors/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "errors" +name = "my_errors" version = "1.0.0" edition = "2018" diff --git a/examples/errors/src/logging.rs b/examples/errors/src/logging.rs new file mode 100644 index 0000000..9f5b880 --- /dev/null +++ b/examples/errors/src/logging.rs @@ -0,0 +1,38 @@ +// +use actix_web::{error, Result}; +use failure::Fail; +use log::debug; + +#[derive(Fail, Debug)] +#[fail(display = "my error")] +pub struct MyError { + name: &'static str, +} + +// Use default implementation for `error_response()` method +impl error::ResponseError for MyError {} + +pub fn index() -> Result<&'static str, MyError> { + let err = MyError { name: "test error" }; + debug!("{}", err); + Err(err) +} + +pub fn main() { + use actix_web::{middleware::Logger, web, App, HttpServer}; + + std::env::set_var("RUST_LOG", "my_errors=debug,actix_web=info"); + std::env::set_var("RUST_BACKTRACE", "1"); + env_logger::init(); + + HttpServer::new(|| { + App::new() + .wrap(Logger::default()) + .route("/", web::get().to(index)) + }) + .bind("127.0.0.1:8088") + .unwrap() + .run() + .unwrap(); +} +// diff --git a/examples/errors/src/main.rs b/examples/errors/src/main.rs index f2d1762..c9e4984 100644 --- a/examples/errors/src/main.rs +++ b/examples/errors/src/main.rs @@ -1,4 +1,5 @@ pub mod helpers; +pub mod logging; pub mod override_error; pub mod recommend_one; pub mod recommend_two;