Update more API documentation to mention futures and async.

This commit is contained in:
Jeb Rosen 2019-12-19 18:11:32 -08:00 committed by Sergio Benitez
parent 9a16aeb2e0
commit e41abc09e5
10 changed files with 123 additions and 51 deletions

View File

@ -126,7 +126,7 @@ impl Data {
self.is_complete
}
/// A helper method to write the body of the request to any `Write` type.
/// A helper method to write the body of the request to any `AsyncWrite` type.
///
/// This method is identical to `tokio::io::copy(&mut data.open(), &mut writer)`.
///
@ -152,7 +152,7 @@ impl Data {
/// determined by `path`.
///
/// This method is identical to
/// `io::copy(&mut self.open(), &mut File::create(path)?)`.
/// `tokio::io::copy(&mut self.open(), &mut File::create(path).await?)`.
///
/// # Example
///

View File

@ -10,7 +10,7 @@ use crate::ext::AsyncReadBody;
/// This stream can only be obtained by calling
/// [`Data::open()`](crate::data::Data::open()). The stream contains all of the data
/// in the body of the request. It exposes no methods directly. Instead, it must
/// be used as an opaque [`Read`] structure.
/// be used as an opaque [`AsyncRead`] structure.
pub struct DataStream(pub(crate) Vec<u8>, pub(crate) AsyncReadBody);
// TODO.async: Consider implementing `AsyncBufRead`

View File

@ -112,7 +112,10 @@ pub type Transformed<'a, T> =
Outcome<&'a <T as FromData<'a>>::Borrowed, <T as FromData<'a>>::Error>
>;
/// Type alias to the `Future` returned by [`FromData::transform`].
pub type TransformFuture<'fut, T, E> = BoxFuture<'fut, Transform<Outcome<T, E>>>;
/// Type alias to the `Future` returned by [`FromData::from_data`].
pub type FromDataFuture<'fut, T, E> = BoxFuture<'fut, Outcome<T, E>>;
/// Trait implemented by data guards to derive a value from request body data.
@ -161,14 +164,15 @@ pub type FromDataFuture<'fut, T, E> = BoxFuture<'fut, Outcome<T, E>>;
/// implement `FromDataSimple` automatically implement `FromData`.
///
/// When exercising a data guard, Rocket first calls the guard's
/// [`FromData::transform()`] method and then subsequently calls the guard's
/// [`FromData::from_data()`] method. Rocket stores data returned by
/// [`FromData::transform()`] on the stack. If `transform` returns a
/// [`Transform::Owned`], Rocket moves the data back to the data guard in the
/// subsequent `from_data` call as a `Transform::Owned`. If instead `transform`
/// returns a [`Transform::Borrowed`] variant, Rocket calls `borrow()` on the
/// owned value, producing a borrow of the associated [`FromData::Borrowed`]
/// type and passing it as a `Transform::Borrowed`.
/// [`FromData::transform()`] method and awaits on the returned future, then
/// calls the guard's [`FromData::from_data()`] method and awaits on that
/// returned future. Rocket stores data returned by [`FromData::transform()`] on
/// the stack. If `transform` returns a [`Transform::Owned`], Rocket moves the
/// data back to the data guard in the subsequent `from_data` call as a
/// `Transform::Owned`. If instead `transform` returns a [`Transform::Borrowed`]
/// variant, Rocket calls `borrow()` on the owned value, producing a borrow of
/// the associated [`FromData::Borrowed`] type and passing it as a
/// `Transform::Borrowed`.
///
/// ## Example
///
@ -349,11 +353,11 @@ pub trait FromData<'a>: Sized {
/// associated type should be set to `Self::Owned`.
type Borrowed: ?Sized;
/// Transforms `data` into a value of type `Self::Owned`.
/// Asynchronously transforms `data` into a value of type `Self::Owned`.
///
/// If this method returns a `Transform::Owned(Self::Owned)`, then
/// If the returned future resolves to `Transform::Owned(Self::Owned)`, then
/// `from_data` should subsequently be called with a `data` value of
/// `Transform::Owned(Self::Owned)`. If this method returns a
/// `Transform::Owned(Self::Owned)`. If the future resolves to
/// `Transform::Borrowed(Self::Owned)`, `from_data` should subsequently be
/// called with a `data` value of `Transform::Borrowed(&Self::Borrowed)`. In
/// other words, the variant of `Transform` returned from this method is
@ -369,8 +373,8 @@ pub trait FromData<'a>: Sized {
/// returned. On failure, `Failure` is returned.
fn transform<'r>(request: &'r Request<'_>, data: Data) -> TransformFuture<'r, Self::Owned, Self::Error>;
/// Validates, parses, and converts the incoming request body data into an
/// instance of `Self`.
/// Asynchronously validates, parses, and converts the incoming request body
/// data into an instance of `Self`.
///
/// If validation and parsing succeeds, an outcome of `Success` is returned.
/// If the data is not appropriate given the type of `Self`, `Forward` is
@ -512,12 +516,11 @@ impl<'a> FromData<'a> for Data {
/// # fn main() { }
/// ```
pub trait FromDataSimple: Sized {
// TODO.async: Can/should we relax this 'static? And how?
/// The associated error to be returned when the guard fails.
type Error: Send + 'static;
/// Validates, parses, and converts an instance of `Self` from the incoming
/// request body data.
/// Asynchronously validates, parses, and converts an instance of `Self`
/// from the incoming request body data.
///
/// If validation and parsing succeeds, an outcome of `Success` is returned.
/// If the data is not appropriate given the type of `Self`, `Forward` is

View File

@ -94,7 +94,8 @@ impl AdHoc {
}
/// Constructs an `AdHoc` request fairing named `name`. The function `f`
/// will be called by Rocket when a new request is received.
/// will be called and the returned `Future` will be `await`ed by Rocket
/// when a new request is received.
///
/// # Example
///
@ -116,7 +117,8 @@ impl AdHoc {
}
/// Constructs an `AdHoc` response fairing named `name`. The function `f`
/// will be called by Rocket when a response is ready to be sent.
/// will be called and the returned `Future` will be `await`ed by Rocket
/// when a response is ready to be sent.
///
/// # Example
///

View File

@ -140,13 +140,13 @@ pub trait Handler: Cloneable + Send + Sync + 'static {
/// Called by Rocket when a `Request` with its associated `Data` should be
/// handled by this handler.
///
/// The variant of `Outcome` returned determines what Rocket does next. If
/// the return value is a `Success(Response)`, the wrapped `Response` is
/// used to respond to the client. If the return value is a
/// `Failure(Status)`, the error catcher for `Status` is invoked to generate
/// a response. Otherwise, if the return value is `Forward(Data)`, the next
/// matching route is attempted. If there are no other matching routes, the
/// `404` error catcher is invoked.
/// The variant of `Outcome` returned by the returned `Future` determines
/// what Rocket does next. If the return value is a `Success(Response)`, the
/// wrapped `Response` is used to respond to the client. If the return value
/// is a `Failure(Status)`, the error catcher for `Status` is invoked to
/// generate a response. Otherwise, if the return value is `Forward(Data)`,
/// the next matching route is attempted. If there are no other matching
/// routes, the `404` error catcher is invoked.
fn handle<'r>(&self, request: &'r Request<'_>, data: Data) -> HandlerFuture<'r>;
}
@ -186,6 +186,7 @@ impl<F: Clone + Sync + Send + 'static> Handler for F
/// The type of an error handler.
pub type ErrorHandler = for<'r> fn(&'r Request<'_>) -> ErrorHandlerFuture<'r>;
/// Type type of `Future` returned by an error handler.
pub type ErrorHandlerFuture<'r> = BoxFuture<'r, response::Result<'r>>;
impl<'r> Outcome<'r> {

View File

@ -37,6 +37,68 @@ impl<S, E> IntoOutcome<S, (Status, E), ()> for Result<S, E> {
/// Type alias for the future returned by [`FromRequestAsync::from_request`].
pub type FromRequestFuture<'fut, T, E> = BoxFuture<'fut, Outcome<T, E>>;
/// Trait implemented by asynchronous request guards to derive a value from
/// incoming requests.
///
/// For more information on request guards in general, see the [`FromRequest`]
/// trait.
///
/// ## Example
///
/// Imagine you're running an authenticated service backed by a database. You
/// want to ensure that certain handlers will only run if a valid API key is
/// present in the request, and you need to make a database request in order to
/// determine if the key is valid or not.
///
/// ```rust
/// # #![feature(proc_macro_hygiene)]
/// # #[macro_use] extern crate rocket;
/// #
/// # struct Database;
/// # impl Database {
/// # async fn check_key(&self, key: &str) -> bool {
/// # true
/// # }
/// # }
/// #
/// use rocket::Outcome;
/// use rocket::http::Status;
/// use rocket::request::{self, Request, State, FromRequestAsync};
///
/// struct ApiKey(String);
///
/// #[derive(Debug)]
/// enum ApiKeyError {
/// BadCount,
/// Missing,
/// Invalid,
/// }
///
/// impl<'a, 'r> FromRequestAsync<'a, 'r> for ApiKey {
/// type Error = ApiKeyError;
///
/// fn from_request(request: &'a Request<'r>) -> request::FromRequestFuture<'a, Self, Self::Error> {
/// Box::pin(async move {
/// let keys: Vec<_> = request.headers().get("x-api-key").collect();
/// let database: State<'_, Database> = request.guard().expect("get database connection");
/// match keys.len() {
/// 0 => Outcome::Failure((Status::BadRequest, ApiKeyError::Missing)),
/// 1 if database.check_key(keys[0]).await => Outcome::Success(ApiKey(keys[0].to_string())),
/// 1 => Outcome::Failure((Status::BadRequest, ApiKeyError::Invalid)),
/// _ => Outcome::Failure((Status::BadRequest, ApiKeyError::BadCount)),
/// }
/// })
/// }
/// }
///
/// #[get("/sensitive")]
/// fn sensitive(key: ApiKey) -> &'static str {
/// # let _key = key;
/// "Sensitive data."
/// }
///
/// # fn main() { }
/// ```
pub trait FromRequestAsync<'a, 'r>: Sized {
/// The associated error to be returned if derivation fails.
type Error: Debug;
@ -65,6 +127,10 @@ pub trait FromRequestAsync<'a, 'r>: Sized {
/// the handler. Rocket only dispatches requests to a handler when all of its
/// guards pass.
///
/// Request guards can be made *asynchronous* by implementing
/// [`FromRequestAsync`] instead of `FromRequest`. This is useful when the
/// validation requires working with a database or performing other I/O.
///
/// ## Example
///
/// The following dummy handler makes use of three request guards, `A`, `B`, and

View File

@ -48,5 +48,6 @@ pub use self::debug::Debug;
/// Type alias for the `Result` of a `Responder::respond` call.
pub type Result<'r> = std::result::Result<self::Response<'r>, crate::http::Status>;
/// Type alias for the `Result` of a `Responder::respond` call.
/// Type alias for the `Future` returned by a `Responder::respond` call.
pub type ResultFuture<'r> = futures_util::future::BoxFuture<'r, Result<'r>>;

View File

@ -26,7 +26,8 @@ use crate::request::Request;
///
/// # Return Value
///
/// A `Responder` returns an `Ok(Response)` or an `Err(Status)`:
/// A `Responder` returns a `Future` whose output type is an `Ok(Response)` or
/// an `Err(Status)`:
///
/// * An `Ok` variant means that the `Responder` was successful in generating
/// a `Response`. The `Response` will be written out to the client.
@ -84,14 +85,7 @@ use crate::request::Request;
/// the client. Otherwise, an `Err` with status **404 Not Found** is
/// returned and a warning is printed to the console.
///
/// * **Result&lt;T, E>** _where_ **E: Debug**
///
/// If the `Result` is `Ok`, the wrapped responder is used to respond to the
/// client. Otherwise, an `Err` with status **500 Internal Server Error** is
/// returned and the error is printed to the console using the `Debug`
/// implementation.
///
/// * **Result&lt;T, E>** _where_ **E: Debug + Responder**
/// * **Result&lt;T, E>**
///
/// If the `Result` is `Ok`, the wrapped `Ok` responder is used to respond
/// to the client. If the `Result` is `Err`, the wrapped `Err` responder is
@ -102,13 +96,6 @@ use crate::request::Request;
/// This section describes a few best practices to take into account when
/// implementing `Responder`.
///
/// ## Debug
///
/// A type implementing `Responder` should implement the `Debug` trait when
/// possible. This is because the `Responder` implementation for `Result`
/// requires its `Err` type to implement `Debug`. Therefore, a type implementing
/// `Debug` can more easily be composed.
///
/// ## Joining and Merging
///
/// When chaining/wrapping other `Responder`s, use the
@ -277,7 +264,7 @@ impl Responder<'_> for () {
/// If `self` is `Some`, responds with the wrapped `Responder`. Otherwise prints
/// a warning message and returns an `Err` of `Status::NotFound`.
impl<'r, R: Responder<'r> + Send + 'r> Responder<'r> for Option<R> {
impl<'r, R: Responder<'r>> Responder<'r> for Option<R> {
fn respond_to(self, req: &'r Request<'_>) -> response::ResultFuture<'r> {
match self {
Some(r) => r.respond_to(req),
@ -291,7 +278,7 @@ impl<'r, R: Responder<'r> + Send + 'r> Responder<'r> for Option<R> {
/// Responds with the wrapped `Responder` in `self`, whether it is `Ok` or
/// `Err`.
impl<'r, R: Responder<'r> + Send + 'r, E: Responder<'r> + Send + 'r> Responder<'r> for Result<R, E> {
impl<'r, R: Responder<'r>, E: Responder<'r>> Responder<'r> for Result<R, E> {
fn respond_to(self, req: &'r Request<'_>) -> response::ResultFuture<'r> {
match self {
Ok(responder) => responder.respond_to(req),

View File

@ -772,9 +772,9 @@ impl Rocket {
.map_err(crate::error::Error::Run)
}
/// Returns a `Future` that completes when the server is shut down or
/// errors. If the `ctrl_c_shutdown` feature is enabled, `Ctrl-C` will be
/// handled as a shutdown signal.
/// Returns a `Future` that drives the server and completes when the server
/// is shut down or errors. If the `ctrl_c_shutdown` feature is enabled,
/// the server will shut down gracefully once `Ctrl-C` is pressed.
///
/// # Example
///
@ -870,6 +870,10 @@ impl Rocket {
/// unless a shutdown is requested via a [`ShutdownHandle`] or there is an
/// error.
///
/// This is a convenience function that creates a suitable default runtime
/// and launches the server on that runtime. If you already have a runtime,
/// use the [`Rocket::serve`] method instead.
///
/// # Error
///
/// If there is a problem starting the application, a [`LaunchError`] is

View File

@ -1,6 +1,12 @@
use crate::request::{FromRequest, Outcome, Request};
use tokio::sync::mpsc;
/// A `ShutdownHandle` can be used to instruct a Rocket server to gracefully
/// shut down. Once a server shutdown has been requested manually by calling
/// [`ShutdownHandle::shutdown()`] or automatically by `Ctrl-C` being pressed
/// (if enabled), Rocket will finish handling any pending requests and return to
/// the caller of [`Rocket::serve`] or [`Rocket::launch`].
///
/// # Example
///
/// ```rust
@ -28,7 +34,9 @@ use tokio::sync::mpsc;
pub struct ShutdownHandle(pub(crate) mpsc::Sender<()>);
impl ShutdownHandle {
/// Notify Rocket to shut down gracefully.
/// Notify Rocket to shut down gracefully. This function returns
/// immediately; pending requests will continue to run until completion
/// before the actual shutdown occurs.
#[inline]
pub fn shutdown(mut self) {
// Intentionally ignore any error, as the only scenarios this can happen