From 250ea0cfeff905dabb04639810941e5800ecc49b Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sat, 2 Oct 2021 15:46:33 +0200 Subject: [PATCH] Make JSON and HTTP1 support optional (#286) * Make json support an optional feature * Fix Json type documentation * Make hyper's http1 feature optional --- Cargo.toml | 9 ++++++--- src/extract/mod.rs | 1 + src/extract/rejection.rs | 4 ++++ src/json.rs | 5 +++-- src/lib.rs | 9 ++++++++- src/response/mod.rs | 1 + src/response/sse.rs | 7 +++++-- 7 files changed, 28 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 43d2dfb3..40d950c9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,8 +15,10 @@ repository = "https://github.com/tokio-rs/axum" members = ["examples/*"] [features] -default = ["tower-log"] +default = ["http1", "json", "tower-log"] +http1 = ["hyper/http1"] http2 = ["hyper/http2"] +json = ["serde_json"] multipart = ["multer", "mime"] tower-log = ["tower/log"] ws = ["tokio-tungstenite", "sha-1", "base64"] @@ -28,11 +30,11 @@ bytes = "1.0" futures-util = { version = "0.3", default-features = false, features = ["alloc"] } http = "0.2" http-body = "0.4.3" -hyper = { version = "0.14", features = ["server", "tcp", "http1", "stream"] } +hyper = { version = "0.14", features = ["server", "tcp", "stream"] } pin-project-lite = "0.2.7" regex = "1.5" serde = "1.0" -serde_json = "1.0" +serde_json = { version = "1.0", optional = true } serde_urlencoded = "0.7" tokio = { version = "1", features = ["time"] } tokio-util = "0.6" @@ -54,6 +56,7 @@ mime = { optional = true, version = "0.3" } futures = "0.3" reqwest = { version = "0.11", features = ["json", "stream"] } serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" tokio = { version = "1.6.1", features = ["macros", "rt", "rt-multi-thread", "net"] } uuid = { version = "0.8", features = ["serde", "v4"] } tokio-stream = "0.1" diff --git a/src/extract/mod.rs b/src/extract/mod.rs index f6559e80..2a32291c 100644 --- a/src/extract/mod.rs +++ b/src/extract/mod.rs @@ -192,6 +192,7 @@ pub use self::{ request_parts::{BodyStream, RawBody}, }; #[doc(no_inline)] +#[cfg(feature = "json")] pub use crate::Json; #[cfg(feature = "multipart")] diff --git a/src/extract/rejection.rs b/src/extract/rejection.rs index 6a17f1dc..610773b1 100644 --- a/src/extract/rejection.rs +++ b/src/extract/rejection.rs @@ -25,9 +25,11 @@ define_rejection! { pub struct HeadersAlreadyExtracted; } +#[cfg(feature = "json")] define_rejection! { #[status = BAD_REQUEST] #[body = "Failed to parse the request body as JSON"] + #[cfg_attr(docsrs, doc(cfg(feature = "json")))] /// Rejection type for [`Json`](super::Json). pub struct InvalidJsonBody(Error); } @@ -199,11 +201,13 @@ composite_rejection! { } } +#[cfg(feature = "json")] composite_rejection! { /// Rejection used for [`Json`](super::Json). /// /// Contains one variant for each way the [`Json`](super::Json) extractor /// can fail. + #[cfg_attr(docsrs, doc(cfg(feature = "json")))] pub enum JsonRejection { InvalidJsonBody, MissingJsonContentType, diff --git a/src/json.rs b/src/json.rs index 56f1abfa..38d20593 100644 --- a/src/json.rs +++ b/src/json.rs @@ -17,10 +17,10 @@ use std::{ ops::{Deref, DerefMut}, }; -/// JSON Extractor/Response +/// 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 +/// implements [`serde::Deserialize`]. 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. /// @@ -87,6 +87,7 @@ use std::{ /// # }; /// ``` #[derive(Debug, Clone, Copy, Default)] +#[cfg_attr(docsrs, doc(cfg(feature = "json")))] pub struct Json(pub T); #[async_trait] diff --git a/src/lib.rs b/src/lib.rs index 6c212e7b..d2a7bf26 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1120,7 +1120,10 @@ //! The following optional features are available: //! //! - `headers`: Enables extracting typed headers via [`extract::TypedHeader`]. +//! - `http1`: Enables hyper's `http1` feature. Enabled by default. //! - `http2`: Enables hyper's `http2` feature. +//! - `json`: Enables the [`Json`] type and some similar convenience functionality. +//! Enabled by default. //! - `multipart`: Enables parsing `multipart/form-data` requests with [`extract::Multipart`]. //! - `tower-log`: Enables `tower`'s `log` feature. Enabled by default. //! - `ws`: Enables WebSockets support via [`extract::ws`]. @@ -1193,6 +1196,7 @@ pub(crate) mod macros; mod clone_box_service; mod error; +#[cfg(feature = "json")] mod json; mod util; @@ -1216,7 +1220,10 @@ pub use hyper::Server; pub use tower_http::add_extension::{AddExtension, AddExtensionLayer}; #[doc(inline)] -pub use self::{error::Error, json::Json, routing::Router}; +#[cfg(feature = "json")] +pub use self::json::Json; +#[doc(inline)] +pub use self::{error::Error, routing::Router}; /// Alias for a type-erased error type. pub type BoxError = Box; diff --git a/src/response/mod.rs b/src/response/mod.rs index e1eb9478..41e5299b 100644 --- a/src/response/mod.rs +++ b/src/response/mod.rs @@ -18,6 +18,7 @@ mod redirect; pub mod sse; #[doc(no_inline)] +#[cfg(feature = "json")] pub use crate::Json; #[doc(inline)] diff --git a/src/response/sse.rs b/src/response/sse.rs index c21496ee..c43332ed 100644 --- a/src/response/sse.rs +++ b/src/response/sse.rs @@ -37,7 +37,6 @@ use futures_util::{ use http::Response; use http_body::Body as HttpBody; use pin_project_lite::pin_project; -use serde::Serialize; use std::{ borrow::Cow, fmt, @@ -181,6 +180,7 @@ pub struct Event { #[derive(Debug)] enum DataType { Text(String), + #[cfg(feature = "json")] Json(String), } @@ -197,9 +197,11 @@ impl Event { /// Set Server-sent event data /// data field(s) ("data:") + #[cfg(feature = "json")] + #[cfg_attr(docsrs, doc(cfg(feature = "json")))] pub fn json_data(mut self, data: T) -> Result where - T: Serialize, + T: serde::Serialize, { self.data = Some(DataType::Json(serde_json::to_string(&data)?)); Ok(self) @@ -265,6 +267,7 @@ impl fmt::Display for Event { f.write_char('\n')?; } } + #[cfg(feature = "json")] Some(DataType::Json(data)) => { "data:".fmt(f)?; data.fmt(f)?;