Standardize 'response::status' responders.

This commit modifies all of the non-empty responders in the
`response::status` module so that they look like `Status<R>(pub R)`.
Prior to this commit, some responders looked like this, while others
contained an `Option<R>`.

Resolves #2351.
This commit is contained in:
Sergio Benitez 2023-04-05 10:51:05 -07:00
parent 07ea3df0c2
commit c48ce64a77
2 changed files with 71 additions and 231 deletions

View File

@ -33,7 +33,7 @@ use crate::request::Request;
use crate::response::{self, Responder, Response}; use crate::response::{self, Responder, Response};
use crate::http::Status; use crate::http::Status;
/// Sets the status of the response to 201 (Created). /// Sets the status of the response to 201 Created.
/// ///
/// Sets the `Location` header and optionally the `ETag` header in the response. /// Sets the `Location` header and optionally the `ETag` header in the response.
/// The body of the response, which identifies the created resource, can be set /// The body of the response, which identifies the created resource, can be set
@ -179,47 +179,7 @@ impl<'r, 'o: 'r, R: Responder<'r, 'o>> Responder<'r, 'o> for Created<R> {
} }
} }
/// Sets the status of the response to 202 (Accepted). /// Sets the status of the response to 204 No Content.
///
/// If a responder is supplied, the remainder of the response is delegated to
/// it. If there is no responder, the body of the response will be empty.
///
/// # Examples
///
/// A 202 Accepted response without a body:
///
/// ```rust
/// use rocket::response::status;
///
/// # #[allow(unused_variables)]
/// let response = status::Accepted::<()>(None);
/// ```
///
/// A 202 Accepted response _with_ a body:
///
/// ```rust
/// use rocket::response::status;
///
/// # #[allow(unused_variables)]
/// let response = status::Accepted(Some("processing"));
/// ```
#[derive(Debug, Clone, PartialEq)]
pub struct Accepted<R>(pub Option<R>);
/// Sets the status code of the response to 202 Accepted. If the responder is
/// `Some`, it is used to finalize the response.
impl<'r, 'o: 'r, R: Responder<'r, 'o>> Responder<'r, 'o> for Accepted<R> {
fn respond_to(self, req: &'r Request<'_>) -> response::Result<'o> {
let mut build = Response::build();
if let Some(responder) = self.0 {
build.merge(responder.respond_to(req)?);
}
build.status(Status::Accepted).ok()
}
}
/// Sets the status of the response to 204 (No Content).
/// ///
/// The response body will be empty. /// The response body will be empty.
/// ///
@ -228,10 +188,13 @@ impl<'r, 'o: 'r, R: Responder<'r, 'o>> Responder<'r, 'o> for Accepted<R> {
/// A 204 No Content response: /// A 204 No Content response:
/// ///
/// ```rust /// ```rust
/// # use rocket::get;
/// use rocket::response::status; /// use rocket::response::status;
/// ///
/// # #[allow(unused_variables)] /// #[get("/")]
/// let response = status::NoContent; /// fn foo() -> status::NoContent {
/// status::NoContent
/// }
/// ``` /// ```
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct NoContent; pub struct NoContent;
@ -243,192 +206,9 @@ impl<'r> Responder<'r, 'static> for NoContent {
} }
} }
/// Sets the status of the response to 400 (Bad Request). /// Creates a response with a status code and underlying responder.
/// ///
/// If a responder is supplied, the remainder of the response is delegated to /// Note that this is equivalent to `(Status, R)`.
/// it. If there is no responder, the body of the response will be empty.
///
/// # Examples
///
/// A 400 Bad Request response without a body:
///
/// ```rust
/// use rocket::response::status;
///
/// # #[allow(unused_variables)]
/// let response = status::BadRequest::<()>(None);
/// ```
///
/// A 400 Bad Request response _with_ a body:
///
/// ```rust
/// use rocket::response::status;
///
/// # #[allow(unused_variables)]
/// let response = status::BadRequest(Some("error message"));
/// ```
#[derive(Debug, Clone, PartialEq)]
pub struct BadRequest<R>(pub Option<R>);
/// Sets the status code of the response to 400 Bad Request. If the responder is
/// `Some`, it is used to finalize the response.
impl<'r, 'o: 'r, R: Responder<'r, 'o>> Responder<'r, 'o> for BadRequest<R> {
fn respond_to(self, req: &'r Request<'_>) -> response::Result<'o> {
let mut build = Response::build();
if let Some(responder) = self.0 {
build.merge(responder.respond_to(req)?);
}
build.status(Status::BadRequest).ok()
}
}
/// Sets the status of the response to 401 (Unauthorized).
///
/// If a responder is supplied, the remainder of the response is delegated to
/// it. If there is no responder, the body of the response will be empty.
///
/// # Examples
///
/// A 401 Unauthorized response without a body:
///
/// ```rust
/// use rocket::response::status;
///
/// # #[allow(unused_variables)]
/// let response = status::Unauthorized::<()>(None);
/// ```
///
/// A 401 Unauthorized response _with_ a body:
///
/// ```rust
/// use rocket::response::status;
///
/// # #[allow(unused_variables)]
/// let response = status::Unauthorized(Some("error message"));
/// ```
#[derive(Debug, Clone, PartialEq)]
pub struct Unauthorized<R>(pub Option<R>);
/// Sets the status code of the response to 401 Unauthorized. If the responder is
/// `Some`, it is used to finalize the response.
impl<'r, 'o: 'r, R: Responder<'r, 'o>> Responder<'r, 'o> for Unauthorized<R> {
fn respond_to(self, req: &'r Request<'_>) -> response::Result<'o> {
let mut build = Response::build();
if let Some(responder) = self.0 {
build.merge(responder.respond_to(req)?);
}
build.status(Status::Unauthorized).ok()
}
}
/// Sets the status of the response to 403 (Forbidden).
///
/// If a responder is supplied, the remainder of the response is delegated to
/// it. If there is no responder, the body of the response will be empty.
///
/// # Examples
///
/// A 403 Forbidden response without a body:
///
/// ```rust
/// use rocket::response::status;
///
/// # #[allow(unused_variables)]
/// let response = status::Forbidden::<()>(None);
/// ```
///
/// A 403 Forbidden response _with_ a body:
///
/// ```rust
/// use rocket::response::status;
///
/// # #[allow(unused_variables)]
/// let response = status::Forbidden(Some("error message"));
/// ```
#[derive(Debug, Clone, PartialEq)]
pub struct Forbidden<R>(pub Option<R>);
/// Sets the status code of the response to 403 Forbidden. If the responder is
/// `Some`, it is used to finalize the response.
impl<'r, 'o: 'r, R: Responder<'r, 'o>> Responder<'r, 'o> for Forbidden<R> {
fn respond_to(self, req: &'r Request<'_>) -> response::Result<'o> {
let mut build = Response::build();
if let Some(responder) = self.0 {
build.merge(responder.respond_to(req)?);
}
build.status(Status::Forbidden).ok()
}
}
/// Sets the status of the response to 404 (Not Found).
///
/// The remainder of the response is delegated to the wrapped `Responder`.
///
/// # Example
///
/// ```rust
/// use rocket::response::status;
///
/// # #[allow(unused_variables)]
/// let response = status::NotFound("Sorry, I couldn't find it!");
/// ```
#[derive(Debug, Clone, PartialEq)]
pub struct NotFound<R>(pub R);
/// Sets the status code of the response to 404 Not Found.
impl<'r, 'o: 'r, R: Responder<'r, 'o>> Responder<'r, 'o> for NotFound<R> {
fn respond_to(self, req: &'r Request<'_>) -> response::Result<'o> {
Response::build_from(self.0.respond_to(req)?)
.status(Status::NotFound)
.ok()
}
}
/// Sets the status of the response to 409 (Conflict).
///
/// If a responder is supplied, the remainder of the response is delegated to
/// it. If there is no responder, the body of the response will be empty.
///
/// # Examples
///
/// A 409 Conflict response without a body:
///
/// ```rust
/// use rocket::response::status;
///
/// # #[allow(unused_variables)]
/// let response = status::Conflict::<()>(None);
/// ```
///
/// A 409 Conflict response _with_ a body:
///
/// ```rust
/// use rocket::response::status;
///
/// # #[allow(unused_variables)]
/// let response = status::Conflict(Some("error message"));
/// ```
#[derive(Debug, Clone, PartialEq)]
pub struct Conflict<R>(pub Option<R>);
/// Sets the status code of the response to 409 Conflict. If the responder is
/// `Some`, it is used to finalize the response.
impl<'r, 'o: 'r, R: Responder<'r, 'o>> Responder<'r, 'o> for Conflict<R> {
fn respond_to(self, req: &'r Request<'_>) -> response::Result<'o> {
let mut build = Response::build();
if let Some(responder) = self.0 {
build.merge(responder.respond_to(req)?);
}
build.status(Status::Conflict).ok()
}
}
/// Creates a response with the given status code and underlying responder.
/// ///
/// # Example /// # Example
/// ///
@ -437,11 +217,16 @@ impl<'r, 'o: 'r, R: Responder<'r, 'o>> Responder<'r, 'o> for Conflict<R> {
/// use rocket::response::status; /// use rocket::response::status;
/// use rocket::http::Status; /// use rocket::http::Status;
/// ///
/// # #[allow(unused_variables)]
/// #[get("/")] /// #[get("/")]
/// fn handler() -> status::Custom<&'static str> { /// fn handler() -> status::Custom<&'static str> {
/// status::Custom(Status::ImATeapot, "Hi!") /// status::Custom(Status::ImATeapot, "Hi!")
/// } /// }
///
/// // This is equivalent to the above.
/// #[get("/")]
/// fn handler2() -> (Status, &'static str) {
/// (Status::ImATeapot, "Hi!")
/// }
/// ``` /// ```
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct Custom<R>(pub Status, pub R); pub struct Custom<R>(pub Status, pub R);
@ -449,6 +234,7 @@ pub struct Custom<R>(pub Status, pub R);
/// Sets the status code of the response and then delegates the remainder of the /// Sets the status code of the response and then delegates the remainder of the
/// response to the wrapped responder. /// response to the wrapped responder.
impl<'r, 'o: 'r, R: Responder<'r, 'o>> Responder<'r, 'o> for Custom<R> { impl<'r, 'o: 'r, R: Responder<'r, 'o>> Responder<'r, 'o> for Custom<R> {
#[inline]
fn respond_to(self, req: &'r Request<'_>) -> response::Result<'o> { fn respond_to(self, req: &'r Request<'_>) -> response::Result<'o> {
Response::build_from(self.1.respond_to(req)?) Response::build_from(self.1.respond_to(req)?)
.status(self.0) .status(self.0)
@ -463,5 +249,59 @@ impl<'r, 'o: 'r, R: Responder<'r, 'o>> Responder<'r, 'o> for (Status, R) {
} }
} }
macro_rules! status_response {
($T:ident $kind:expr) => {
/// Sets the status of the response to
#[doc = concat!($kind, concat!(" ([`Status::", stringify!($T), "`])."))]
///
/// The remainder of the response is delegated to `self.0`.
/// # Examples
///
/// A
#[doc = $kind]
/// response without a body:
///
/// ```rust
/// # use rocket::get;
/// use rocket::response::status;
///
/// #[get("/")]
#[doc = concat!("fn handler() -> status::", stringify!($T), "<()> {")]
#[doc = concat!(" status::", stringify!($T), "(())")]
/// }
/// ```
///
/// A
#[doc = $kind]
/// response _with_ a body:
///
/// ```rust
/// # use rocket::get;
/// use rocket::response::status;
///
/// #[get("/")]
#[doc = concat!("fn handler() -> status::", stringify!($T), "<&'static str> {")]
#[doc = concat!(" status::", stringify!($T), "(\"body\")")]
/// }
/// ```
#[derive(Debug, Clone, PartialEq)]
pub struct $T<R>(pub R);
impl<'r, 'o: 'r, R: Responder<'r, 'o>> Responder<'r, 'o> for $T<R> {
#[inline(always)]
fn respond_to(self, req: &'r Request<'_>) -> response::Result<'o> {
Custom(Status::$T, self.0).respond_to(req)
}
}
}
}
status_response!(Accepted "202 Accepted");
status_response!(BadRequest "400 Bad Request");
status_response!(Unauthorized "401 Unauthorized");
status_response!(Forbidden "403 Forbidden");
status_response!(NotFound "404 NotFound");
status_response!(Conflict "409 Conflict");
// The following are unimplemented. // The following are unimplemented.
// 206 Partial Content (variant), 203 Non-Authoritative Information (headers). // 206 Partial Content (variant), 203 Non-Authoritative Information (headers).

View File

@ -43,7 +43,7 @@ use rocket::response::status;
#[post("/<id>")] #[post("/<id>")]
fn new(id: usize) -> status::Accepted<String> { fn new(id: usize) -> status::Accepted<String> {
status::Accepted(Some(format!("id: '{}'", id))) status::Accepted(format!("id: '{}'", id))
} }
``` ```