Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions axum/src/response/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,71 @@ impl IntoResponse for NoContent {
}
}

/// A response with a 201 CREATED status
///
/// As 201 is recommended to come with a `Location` header referring to the location of the created
/// object according to the RFC7231, using this struct can remind a user to do so.
/// Remember that any IntoResponse struct used as an `inner` here may override the headers and status
/// code set by this struct.
#[derive(Clone, Debug)]
pub struct Created<T: IntoResponse = ()> {
/// The value set for the `Location` header.
/// Existing location headers are not overwritten
location: Option<HeaderValue>,
inner: T,
}
impl Created {
#[must_use]
/// Creates a CREATED response with an empty body and no `Location` header
pub fn empty() -> Self {
Self {
location: None,
inner: (),
}
}
/// Creates a new `Created` with an empty body
pub fn empty_with_location(location: HeaderValue) -> Self {
Self {
location: Some(location),
inner: (),
}
}
/// Attaches a body to an empty `Created` response
pub fn with_body<T: IntoResponse>(self, body: T) -> Created<T> {
let Self {
location,
inner: (),
} = self;
Created {
location,
inner: body,
}
}
}
impl<T: IntoResponse> Created<T> {
/// Sets status and `Location` header along with the inner type's `IntoResponse` implementation.
/// Remember that the inner type may override headers and the status code.
pub fn new_with_location_header(body: T, location: HeaderValue) -> Self {
Self {
location: Some(location),
inner: body,
}
}
}
impl<T: IntoResponse> IntoResponse for Created<T> {
fn into_response(self) -> Response {
match self.location {
Some(l) => (
StatusCode::CREATED,
AppendHeaders([(http::header::LOCATION, l)]),
self.inner,
)
.into_response(),
None => (StatusCode::CREATED, self.inner).into_response(),
}
}
}

#[cfg(test)]
mod tests {
use crate::extract::Extension;
Expand Down
Loading