mirror of
https://github.com/tokio-rs/axum.git
synced 2024-12-27 15:00:31 +01:00
Add axum_extra::json!
(#2962)
This commit is contained in:
parent
64e6edac05
commit
4b4dac4d86
5 changed files with 91 additions and 2 deletions
|
@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog],
|
||||
and this project adheres to [Semantic Versioning].
|
||||
|
||||
# Unreleased
|
||||
|
||||
- **added:** Add `json!` for easy construction of JSON responses ([#2962])
|
||||
|
||||
[#2962]: https://github.com/tokio-rs/axum/pull/2962
|
||||
|
||||
# 0.10.0
|
||||
|
||||
# alpha.1
|
||||
|
|
|
@ -20,7 +20,7 @@ cookie = ["dep:cookie"]
|
|||
cookie-private = ["cookie", "cookie?/private"]
|
||||
cookie-signed = ["cookie", "cookie?/signed"]
|
||||
cookie-key-expansion = ["cookie", "cookie?/key-expansion"]
|
||||
erased-json = ["dep:serde_json"]
|
||||
erased-json = ["dep:serde_json", "dep:typed-json"]
|
||||
form = ["dep:serde_html_form"]
|
||||
json-deserializer = ["dep:serde_json", "dep:serde_path_to_error"]
|
||||
json-lines = [
|
||||
|
@ -69,9 +69,11 @@ tokio = { version = "1.19", optional = true }
|
|||
tokio-stream = { version = "0.1.9", optional = true }
|
||||
tokio-util = { version = "0.7", optional = true }
|
||||
tracing = { version = "0.1.37", default-features = false, optional = true }
|
||||
typed-json = { version = "0.1.1", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
axum = { path = "../axum" }
|
||||
axum = { path = "../axum", features = ["macros"] }
|
||||
axum-macros = { path = "../axum-macros", features = ["__private"] }
|
||||
hyper = "1.0.0"
|
||||
reqwest = { version = "0.12", default-features = false, features = ["json", "stream", "multipart"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
|
|
|
@ -12,6 +12,15 @@ use serde::Serialize;
|
|||
/// This allows returning a borrowing type from a handler, or returning different response
|
||||
/// types as JSON from different branches inside a handler.
|
||||
///
|
||||
/// Like [`axum::Json`],
|
||||
/// if the [`Serialize`] implementation fails
|
||||
/// or if a map with non-string keys is used,
|
||||
/// a 500 response will be issued
|
||||
/// whose body is the error message in UTF-8.
|
||||
///
|
||||
/// This can be constructed using [`new`](ErasedJson::new)
|
||||
/// or the [`json!`](crate::json) macro.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
|
@ -72,3 +81,65 @@ impl IntoResponse for ErasedJson {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct an [`ErasedJson`] response from a JSON literal.
|
||||
///
|
||||
/// A `Content-Type: application/json` header is automatically added.
|
||||
/// Any variable or expression implementing [`Serialize`]
|
||||
/// can be interpolated as a value in the literal.
|
||||
/// If the [`Serialize`] implementation fails,
|
||||
/// or if a map with non-string keys is used,
|
||||
/// a 500 response will be issued
|
||||
/// whose body is the error message in UTF-8.
|
||||
///
|
||||
/// Internally,
|
||||
/// this function uses the [`typed_json::json!`] macro,
|
||||
/// allowing it to perform far fewer allocations
|
||||
/// than a dynamic macro like [`serde_json::json!`] would –
|
||||
/// it's equivalent to if you had just written
|
||||
/// `derive(Serialize)` on a struct.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use axum::{
|
||||
/// Router,
|
||||
/// extract::Path,
|
||||
/// response::Response,
|
||||
/// routing::get,
|
||||
/// };
|
||||
/// use axum_extra::response::ErasedJson;
|
||||
///
|
||||
/// async fn get_user(Path(user_id) : Path<u64>) -> ErasedJson {
|
||||
/// let user_name = find_user_name(user_id).await;
|
||||
/// axum_extra::json!({ "name": user_name })
|
||||
/// }
|
||||
///
|
||||
/// async fn find_user_name(user_id: u64) -> String {
|
||||
/// // ...
|
||||
/// # unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// let app = Router::new().route("/users/{id}", get(get_user));
|
||||
/// # let _: Router = app;
|
||||
/// ```
|
||||
///
|
||||
/// Trailing commas are allowed in both arrays and objects.
|
||||
///
|
||||
/// ```
|
||||
/// let response = axum_extra::json!(["trailing",]);
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! json {
|
||||
($($t:tt)*) => {
|
||||
$crate::response::ErasedJson::new(
|
||||
$crate::response::__private_erased_json::typed_json::json!($($t)*)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Not public API. Re-exported as `crate::response::__private_erased_json`.
|
||||
#[doc(hidden)]
|
||||
pub mod private {
|
||||
pub use typed_json;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,11 @@ pub mod multiple;
|
|||
#[cfg(feature = "erased-json")]
|
||||
pub use erased_json::ErasedJson;
|
||||
|
||||
/// _not_ public API
|
||||
#[cfg(feature = "erased-json")]
|
||||
#[doc(hidden)]
|
||||
pub use erased_json::private as __private_erased_json;
|
||||
|
||||
#[cfg(feature = "json-lines")]
|
||||
#[doc(no_inline)]
|
||||
pub use crate::json_lines::JsonLines;
|
||||
|
|
|
@ -54,6 +54,11 @@ use serde::{de::DeserializeOwned, Serialize};
|
|||
/// 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.
|
||||
///
|
||||
/// If the [`Serialize`] implementation decides to fail
|
||||
/// or if a map with non-string keys is used,
|
||||
/// a 500 response will be issued
|
||||
/// whose body is the error message in UTF-8.
|
||||
///
|
||||
/// # Response example
|
||||
///
|
||||
/// ```
|
||||
|
|
Loading…
Reference in a new issue