From f2487ccec526d13c4ca238fb04a458fe24fffbd1 Mon Sep 17 00:00:00 2001 From: Jeb Rosen Date: Wed, 8 Jan 2020 08:03:05 -0800 Subject: [PATCH] Update the guide for async-related API changes. --- site/guide/10-pastebin.md | 5 +++-- site/guide/4-requests.md | 3 ++- site/guide/5-responses.md | 4 ++-- site/guide/6-state.md | 1 + site/guide/7-fairings.md | 34 ++++++++++++++++++---------------- site/guide/8-testing.md | 16 +++++++++++----- 6 files changed, 37 insertions(+), 26 deletions(-) diff --git a/site/guide/10-pastebin.md b/site/guide/10-pastebin.md index f8da2544..f58697c6 100644 --- a/site/guide/10-pastebin.md +++ b/site/guide/10-pastebin.md @@ -216,10 +216,11 @@ For the `upload` route, we'll need to `use` a few items: ```rust use std::io; -use std::path::Path; +use std::path::PathBuf; use rocket::Data; use rocket::http::RawStr; +use rocket::response::Debug; ``` The [Data](@api/rocket/data/struct.Data.html) structure is key @@ -279,7 +280,7 @@ fn upload(paste: Data) -> Result> { let url = format!("{host}/{id}\n", host = "http://localhost:8000", id = id); // Write the paste out to the file and return the URL. - paste.stream_to_file(Path::new(&filename))?; + paste.stream_to_file(PathBuf::from(filename)).await?; Ok(url) } ``` diff --git a/site/guide/4-requests.md b/site/guide/4-requests.md index 8ec65f91..ab259e2d 100644 --- a/site/guide/4-requests.md +++ b/site/guide/4-requests.md @@ -412,7 +412,7 @@ imply, a request guard protects a handler from being called erroneously based on information contained in an incoming request. More specifically, a request guard is a type that represents an arbitrary validation policy. The validation policy is implemented through the [`FromRequest`] trait. Every type that implements -`FromRequest` is a request guard. +`FromRequest` (or the related [`FromRequestAsync`]) is a request guard. Request guards appear as inputs to handlers. An arbitrary number of request guards can appear as arguments in a route handler. Rocket will automatically @@ -444,6 +444,7 @@ more about request guards and implementing them, see the [`FromRequest`] documentation. [`FromRequest`]: @api/rocket/request/trait.FromRequest.html +[`FromRequestAsync`]: @api/rocket/request/trait.FromRequestAsync.html [`Cookies`]: @api/rocket/http/enum.Cookies.html ### Custom Guards diff --git a/site/guide/5-responses.md b/site/guide/5-responses.md index 9fce85ae..b6861d9d 100644 --- a/site/guide/5-responses.md +++ b/site/guide/5-responses.md @@ -299,8 +299,8 @@ library. Among these are: The `Stream` type deserves special attention. When a large amount of data needs to be sent to the client, it is better to stream the data to the client to avoid consuming large amounts of memory. Rocket provides the [`Stream`] type, making -this easy. The `Stream` type can be created from any `Read` type. For example, -to stream from a local Unix stream, we might write: +this easy. The `Stream` type can be created from any `AsyncRead` type. For +example, to stream from a local Unix stream, we might write: ```rust # #[macro_use] extern crate rocket; diff --git a/site/guide/6-state.md b/site/guide/6-state.md index 61885c79..fdebdad2 100644 --- a/site/guide/6-state.md +++ b/site/guide/6-state.md @@ -203,6 +203,7 @@ request-local state to implement request timing. [`FromRequest` request-local state]: @api/rocket/request/trait.FromRequest.html#request-local-state [`Fairing`]: @api/rocket/fairing/trait.Fairing.html#request-local-state + ## Databases Rocket includes built-in, ORM-agnostic support for databases. In particular, diff --git a/site/guide/7-fairings.md b/site/guide/7-fairings.md index eefa477a..dcb09c07 100644 --- a/site/guide/7-fairings.md +++ b/site/guide/7-fairings.md @@ -175,22 +175,24 @@ impl Fairing for Counter { }; } - fn on_response(&self, request: &Request, response: &mut Response) { - // Don't change a successful user's response, ever. - if response.status() != Status::NotFound { - return - } + fn on_response<'a>(&'a self, request: &'a Request<'_>, response: &'a mut Response<'_>) -> BoxFuture<'a, ()> { + Box::pin(async move { + // Don't change a successful user's response, ever. + if response.status() != Status::NotFound { + return + } - // Rewrite the response to return the current counts. - if request.method() == Method::Get && request.uri().path() == "/counts" { - let get_count = self.get.load(Ordering::Relaxed); - let post_count = self.post.load(Ordering::Relaxed); - let body = format!("Get: {}\nPost: {}", get_count, post_count); + // Rewrite the response to return the current counts. + if request.method() == Method::Get && request.uri().path() == "/counts" { + let get_count = self.get.load(Ordering::Relaxed); + let post_count = self.post.load(Ordering::Relaxed); + let body = format!("Get: {}\nPost: {}", get_count, post_count); - response.set_status(Status::Ok); - response.set_header(ContentType::Plain); - response.set_sized_body(Cursor::new(body)); - } + response.set_status(Status::Ok); + response.set_header(ContentType::Plain); + response.set_sized_body(Cursor::new(body)); + } + }) } } ``` @@ -220,9 +222,9 @@ rocket::ignite() .attach(AdHoc::on_launch("Launch Printer", |_| { println!("Rocket is about to launch! Exciting! Here we go..."); })) - .attach(AdHoc::on_request("Put Rewriter", |req, _| { + .attach(AdHoc::on_request("Put Rewriter", |req, _| Box::pin(async move { req.set_method(Method::Put); - })); + }))); ``` [`AdHoc`]: @api/rocket/fairing/struct.AdHoc.html diff --git a/site/guide/8-testing.md b/site/guide/8-testing.md index 784684de..bfe3b6c8 100644 --- a/site/guide/8-testing.md +++ b/site/guide/8-testing.md @@ -103,7 +103,7 @@ use rocket::http::{ContentType, Status}; let rocket = rocket::ignite().mount("/", routes![hello]); let client = Client::new(rocket).expect("valid rocket instance"); -let mut response = client.get("/").dispatch(); +let mut response = client.get("/").dispatch().await; assert_eq!(response.status(), Status::Ok); assert_eq!(response.content_type(), Some(ContentType::Plain)); @@ -167,7 +167,13 @@ You can also move the body of the `test` module into its own file, say ### Testing -To test our "Hello, world!" application, we first create a `Client` for our +First, note the `#[rocket::async_test]` attribute. Rust does not support `async +fn` for tests, so an asynchronous runtime needs to be set up. In most +applications this is done by `launch()`, but we are deliberately not calling +that in tests! Instead, we use `#[rocket::async_test]`, which runs the test +inside a runtime. + +To test our "Hello, world!" application, we create a `Client` for our `Rocket` instance. It's okay to use methods like `expect` and `unwrap` during testing: we _want_ our tests to panic when something goes wrong. @@ -211,7 +217,7 @@ use rocket::http::{ContentType, Status}; # let mut response = client.get("/").dispatch(); assert_eq!(response.status(), Status::Ok); -assert_eq!(response.body_string(), Some("Hello, world!".into())); +assert_eq!(response.body_string().await, Some("Hello, world!".into())); ``` That's it! Altogether, this looks like: @@ -242,9 +248,9 @@ mod test { # */ pub fn hello_world() { let client = Client::new(rocket()).expect("valid rocket instance"); - let mut response = client.get("/").dispatch(); + let mut response = client.get("/").dispatch().await; assert_eq!(response.status(), Status::Ok); - assert_eq!(response.body_string(), Some("Hello, world!".into())); + assert_eq!(response.body_string().await, Some("Hello, world!".into())); } }