mirror of
https://github.com/tokio-rs/axum.git
synced 2026-08-12 00:00:15 +02:00
Instead rely on `tower-service` and `tower-layer`. `tower` itself is only used internally. Fixes https://github.com/tokio-rs/axum/issues/186
168 lines
4.1 KiB
Rust
168 lines
4.1 KiB
Rust
use crate::BoxError;
|
|
use crate::{
|
|
extract::{has_content_type, rejection::*, take_body, FromRequest, RequestParts},
|
|
response::IntoResponse,
|
|
};
|
|
use async_trait::async_trait;
|
|
use bytes::Bytes;
|
|
use http::{
|
|
header::{self, HeaderValue},
|
|
StatusCode,
|
|
};
|
|
use http_body::Full;
|
|
use hyper::Response;
|
|
use serde::{de::DeserializeOwned, Serialize};
|
|
use std::{
|
|
convert::Infallible,
|
|
ops::{Deref, DerefMut},
|
|
};
|
|
|
|
/// JSON Extractor/Response
|
|
///
|
|
/// When used as an extractor, it can deserialize request bodies into some type that
|
|
/// implements [`serde::Serialize`]. If the request body cannot be parsed, or it does not contain
|
|
/// the `Content-Type: application/json` header, it will reject the request and return a
|
|
/// `400 Bad Request` response.
|
|
///
|
|
/// # Extractor example
|
|
///
|
|
/// ```rust,no_run
|
|
/// use axum::{
|
|
/// extract,
|
|
/// handler::post,
|
|
/// Router,
|
|
/// };
|
|
/// use serde::Deserialize;
|
|
///
|
|
/// #[derive(Deserialize)]
|
|
/// struct CreateUser {
|
|
/// email: String,
|
|
/// password: String,
|
|
/// }
|
|
///
|
|
/// async fn create_user(extract::Json(payload): extract::Json<CreateUser>) {
|
|
/// // payload is a `CreateUser`
|
|
/// }
|
|
///
|
|
/// let app = Router::new().route("/users", post(create_user));
|
|
/// # async {
|
|
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
|
/// # };
|
|
/// ```
|
|
///
|
|
/// When used as a response, it can serialize any type that implements [`serde::Serialize`] to `JSON`,
|
|
/// and will automatically set `Content-Type: application/json` header.
|
|
///
|
|
/// # Response example
|
|
///
|
|
/// ```
|
|
/// use axum::{
|
|
/// extract::Path,
|
|
/// handler::get,
|
|
/// Router,
|
|
/// Json,
|
|
/// };
|
|
/// use serde::Serialize;
|
|
/// use uuid::Uuid;
|
|
///
|
|
/// #[derive(Serialize)]
|
|
/// struct User {
|
|
/// id: Uuid,
|
|
/// username: String,
|
|
/// }
|
|
///
|
|
/// async fn get_user(Path(user_id) : Path<Uuid>) -> Json<User> {
|
|
/// let user = find_user(user_id).await;
|
|
/// Json(user)
|
|
/// }
|
|
///
|
|
/// async fn find_user(user_id: Uuid) -> User {
|
|
/// // ...
|
|
/// # unimplemented!()
|
|
/// }
|
|
///
|
|
/// let app = Router::new().route("/users/:id", get(get_user));
|
|
/// # async {
|
|
/// # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
|
/// # };
|
|
/// ```
|
|
#[derive(Debug, Clone, Copy, Default)]
|
|
pub struct Json<T>(pub T);
|
|
|
|
#[async_trait]
|
|
impl<T, B> FromRequest<B> for Json<T>
|
|
where
|
|
T: DeserializeOwned,
|
|
B: http_body::Body + Send,
|
|
B::Data: Send,
|
|
B::Error: Into<BoxError>,
|
|
{
|
|
type Rejection = JsonRejection;
|
|
|
|
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
|
use bytes::Buf;
|
|
|
|
if has_content_type(req, "application/json")? {
|
|
let body = take_body(req)?;
|
|
|
|
let buf = hyper::body::aggregate(body)
|
|
.await
|
|
.map_err(InvalidJsonBody::from_err)?;
|
|
|
|
let value = serde_json::from_reader(buf.reader()).map_err(InvalidJsonBody::from_err)?;
|
|
|
|
Ok(Json(value))
|
|
} else {
|
|
Err(MissingJsonContentType.into())
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T> Deref for Json<T> {
|
|
type Target = T;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
&self.0
|
|
}
|
|
}
|
|
|
|
impl<T> DerefMut for Json<T> {
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
&mut self.0
|
|
}
|
|
}
|
|
|
|
impl<T> From<T> for Json<T> {
|
|
fn from(inner: T) -> Self {
|
|
Self(inner)
|
|
}
|
|
}
|
|
|
|
impl<T> IntoResponse for Json<T>
|
|
where
|
|
T: Serialize,
|
|
{
|
|
type Body = Full<Bytes>;
|
|
type BodyError = Infallible;
|
|
|
|
fn into_response(self) -> Response<Self::Body> {
|
|
let bytes = match serde_json::to_vec(&self.0) {
|
|
Ok(res) => res,
|
|
Err(err) => {
|
|
return Response::builder()
|
|
.status(StatusCode::INTERNAL_SERVER_ERROR)
|
|
.header(header::CONTENT_TYPE, "text/plain")
|
|
.body(Full::from(err.to_string()))
|
|
.unwrap();
|
|
}
|
|
};
|
|
|
|
let mut res = Response::new(Full::from(bytes));
|
|
res.headers_mut().insert(
|
|
header::CONTENT_TYPE,
|
|
HeaderValue::from_static("application/json"),
|
|
);
|
|
res
|
|
}
|
|
}
|