Skip to content

Commit

Permalink
Move TypedHeader to axum-extra (#1850)
Browse files Browse the repository at this point in the history
Co-authored-by: Michael Scofield <mscofield0@tutanota.com>
Co-authored-by: Jonas Platte <jplatte+git@posteo.de>
  • Loading branch information
3 people authored Apr 11, 2023
1 parent 49183e4 commit ac09dd8
Show file tree
Hide file tree
Showing 46 changed files with 222 additions and 227 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ jobs:
- uses: dtolnay/rust-toolchain@stable
with:
# same as `axum-macros/rust-toolchain`
toolchain: nightly-2022-11-18
toolchain: nightly-2023-04-06
override: true
profile: minimal
- uses: Swatinem/rust-cache@v1
Expand Down
3 changes: 2 additions & 1 deletion axum-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ tower-http = { version = "0.4", optional = true, features = ["limit"] }
rustversion = "1.0.9"

[dev-dependencies]
axum = { path = "../axum", version = "0.6.0", features = ["headers"] }
axum = { path = "../axum", version = "0.6.0" }
axum-extra = { path = "../axum-extra", features = ["typed-header"] }
futures-util = { version = "0.3", default-features = false, features = ["alloc"] }
hyper = "0.14.24"
tokio = { version = "1.25.0", features = ["macros"] }
Expand Down
22 changes: 12 additions & 10 deletions axum-core/src/ext_traits/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,15 +139,19 @@ pub trait RequestExt: sealed::Sealed + Sized {
/// ```
/// use axum::{
/// async_trait,
/// extract::{Request, FromRequest},
/// headers::{authorization::Bearer, Authorization},
/// extract::{Path, Request, FromRequest},
/// response::{IntoResponse, Response},
/// body::Body,
/// Json, RequestExt, TypedHeader,
/// Json, RequestExt,
/// };
/// use axum_extra::{
/// TypedHeader,
/// headers::{authorization::Bearer, Authorization},
/// };
/// use std::collections::HashMap;
///
/// struct MyExtractor<T> {
/// bearer_token: String,
/// path_params: HashMap<String, String>,
/// payload: T,
/// }
///
Expand All @@ -161,20 +165,18 @@ pub trait RequestExt: sealed::Sealed + Sized {
/// type Rejection = Response;
///
/// async fn from_request(mut req: Request, _state: &S) -> Result<Self, Self::Rejection> {
/// let TypedHeader(auth_header) = req
/// .extract_parts::<TypedHeader<Authorization<Bearer>>>()
/// let path_params = req
/// .extract_parts::<Path<_>>()
/// .await
/// .map(|Path(path_params)| path_params)
/// .map_err(|err| err.into_response())?;
///
/// let Json(payload) = req
/// .extract::<Json<T>, _>()
/// .await
/// .map_err(|err| err.into_response())?;
///
/// Ok(Self {
/// bearer_token: auth_header.token().to_owned(),
/// payload,
/// })
/// Ok(Self { path_params, payload })
/// }
/// }
/// ```
Expand Down
13 changes: 6 additions & 7 deletions axum-core/src/ext_traits/request_parts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,16 @@ pub trait RequestPartsExt: sealed::Sealed + Sized {
///
/// ```
/// use axum::{
/// extract::{Query, TypedHeader, FromRequestParts},
/// extract::{Query, Path, FromRequestParts},
/// response::{Response, IntoResponse},
/// headers::UserAgent,
/// http::request::Parts,
/// RequestPartsExt,
/// async_trait,
/// };
/// use std::collections::HashMap;
///
/// struct MyExtractor {
/// user_agent: String,
/// path_params: HashMap<String, String>,
/// query_params: HashMap<String, String>,
/// }
///
Expand All @@ -39,10 +38,10 @@ pub trait RequestPartsExt: sealed::Sealed + Sized {
/// type Rejection = Response;
///
/// async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
/// let user_agent = parts
/// .extract::<TypedHeader<UserAgent>>()
/// let path_params = parts
/// .extract::<Path<HashMap<String, String>>>()
/// .await
/// .map(|user_agent| user_agent.as_str().to_owned())
/// .map(|Path(path_params)| path_params)
/// .map_err(|err| err.into_response())?;
///
/// let query_params = parts
Expand All @@ -51,7 +50,7 @@ pub trait RequestPartsExt: sealed::Sealed + Sized {
/// .map(|Query(params)| params)
/// .map_err(|err| err.into_response())?;
///
/// Ok(MyExtractor { user_agent, query_params })
/// Ok(MyExtractor { path_params, query_params })
/// }
/// }
/// ```
Expand Down
4 changes: 3 additions & 1 deletion axum-extra/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning].

# Unreleased

- None.
- **added:** Added `TypedHeader` which used to be in `axum` ([#1850])

[#1850]: https://github.com/tokio-rs/axum/pull/1850

# 0.7.2 (22. March, 2023)

Expand Down
10 changes: 7 additions & 3 deletions axum-extra/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ json-lines = [
multipart = ["dep:multer"]
protobuf = ["dep:prost"]
query = ["dep:serde", "dep:serde_html_form"]
typed-header = ["dep:headers"]
typed-routing = ["dep:axum-macros", "dep:serde", "dep:percent-encoding", "dep:serde_html_form", "dep:form_urlencoded"]

[dependencies]
Expand All @@ -52,6 +53,7 @@ tower-service = "0.3"
axum-macros = { path = "../axum-macros", version = "0.3.7", optional = true }
cookie = { package = "cookie", version = "0.17", features = ["percent-encode"], optional = true }
form_urlencoded = { version = "1.1.0", optional = true }
headers = { version = "0.3.8", optional = true }
multer = { version = "2.0.0", optional = true }
percent-encoding = { version = "2.1", optional = true }
prost = { version = "0.11", optional = true }
Expand All @@ -62,7 +64,8 @@ tokio-stream = { version = "0.1.9", optional = true }
tokio-util = { version = "0.7", optional = true }

[dev-dependencies]
axum = { path = "../axum", version = "0.6.0", features = ["headers"] }
axum = { path = "../axum", version = "0.6.0" }
futures = "0.3"
http-body = "0.4.4"
hyper = "0.14"
reqwest = { version = "0.11", default-features = false, features = ["json", "stream", "multipart"] }
Expand All @@ -80,14 +83,15 @@ rustdoc-args = ["--cfg", "docsrs"]
allowed = [
"axum",
"axum_core",
"axum_macros",
"bytes",
"cookie",
"futures_core",
"futures_util",
"headers",
"headers_core",
"http",
"http_body",
"hyper",
"percent_encoding",
"prost",
"serde",
"tokio",
Expand Down
8 changes: 5 additions & 3 deletions axum-extra/src/extract/cookie/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,14 @@ pub use cookie::Key;
/// use axum::{
/// Router,
/// routing::{post, get},
/// extract::TypedHeader,
/// response::{IntoResponse, Redirect},
/// headers::authorization::{Authorization, Bearer},
/// http::StatusCode,
/// };
/// use axum_extra::extract::cookie::{CookieJar, Cookie};
/// use axum_extra::{
/// TypedHeader,
/// headers::authorization::{Authorization, Bearer},
/// extract::cookie::{CookieJar, Cookie},
/// };
///
/// async fn create_session(
/// TypedHeader(auth): TypedHeader<Authorization<Bearer>>,
Expand Down
9 changes: 6 additions & 3 deletions axum-extra/src/extract/cookie/private.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,15 @@ use std::{convert::Infallible, fmt, marker::PhantomData};
/// use axum::{
/// Router,
/// routing::{post, get},
/// extract::{TypedHeader, FromRef},
/// extract::FromRef,
/// response::{IntoResponse, Redirect},
/// headers::authorization::{Authorization, Bearer},
/// http::StatusCode,
/// };
/// use axum_extra::extract::cookie::{PrivateCookieJar, Cookie, Key};
/// use axum_extra::{
/// TypedHeader,
/// headers::authorization::{Authorization, Bearer},
/// extract::cookie::{PrivateCookieJar, Cookie, Key},
/// };
///
/// async fn set_secret(
/// jar: PrivateCookieJar,
Expand Down
9 changes: 6 additions & 3 deletions axum-extra/src/extract/cookie/signed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,15 @@ use std::{convert::Infallible, fmt, marker::PhantomData};
/// use axum::{
/// Router,
/// routing::{post, get},
/// extract::{TypedHeader, FromRef},
/// extract::FromRef,
/// response::{IntoResponse, Redirect},
/// headers::authorization::{Authorization, Bearer},
/// http::StatusCode,
/// };
/// use axum_extra::extract::cookie::{SignedCookieJar, Cookie, Key};
/// use axum_extra::{
/// TypedHeader,
/// headers::authorization::{Authorization, Bearer},
/// extract::cookie::{SignedCookieJar, Cookie, Key},
/// };
///
/// async fn create_session(
/// TypedHeader(auth): TypedHeader<Authorization<Bearer>>,
Expand Down
4 changes: 4 additions & 0 deletions axum-extra/src/extract/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,8 @@ pub use self::multipart::Multipart;
#[doc(no_inline)]
pub use crate::json_lines::JsonLines;

#[cfg(feature = "typed-header")]
#[doc(no_inline)]
pub use crate::typed_header::TypedHeader;

pub use self::with_rejection::WithRejection;
12 changes: 12 additions & 0 deletions axum-extra/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
//! `protobuf` | Enables the `Protobuf` extractor and response | No
//! `query` | Enables the `Query` extractor | No
//! `typed-routing` | Enables the `TypedPath` routing utilities | No
//! `typed-header` | Enables the `TypedHeader` extractor and response | No
//!
//! [`axum`]: https://crates.io/crates/axum

Expand Down Expand Up @@ -79,6 +80,17 @@ pub mod routing;
#[cfg(feature = "json-lines")]
pub mod json_lines;

#[cfg(feature = "typed-header")]
pub mod typed_header;

#[cfg(feature = "typed-header")]
#[doc(no_inline)]
pub use headers;

#[cfg(feature = "typed-header")]
#[doc(inline)]
pub use typed_header::TypedHeader;

#[cfg(feature = "protobuf")]
pub mod protobuf;

Expand Down
4 changes: 4 additions & 0 deletions axum-extra/src/response/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,7 @@ pub use erased_json::ErasedJson;
#[cfg(feature = "json-lines")]
#[doc(no_inline)]
pub use crate::json_lines::JsonLines;

#[cfg(feature = "typed-header")]
#[doc(no_inline)]
pub use crate::typed_header::TypedHeader;
39 changes: 22 additions & 17 deletions axum/src/typed_header.rs → axum-extra/src/typed_header.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
use crate::extract::FromRequestParts;
use async_trait::async_trait;
use axum_core::response::{IntoResponse, IntoResponseParts, Response, ResponseParts};
use headers::HeaderMapExt;
//! Extractor and response for typed headers.

use axum::{
async_trait,
extract::FromRequestParts,
response::{IntoResponse, IntoResponseParts, Response, ResponseParts},
};
use headers::{Header, HeaderMapExt};
use http::request::Parts;
use std::{convert::Infallible, ops::Deref};

Expand All @@ -14,11 +18,11 @@ use std::{convert::Infallible, ops::Deref};
///
/// ```rust,no_run
/// use axum::{
/// TypedHeader,
/// headers::UserAgent,
/// routing::get,
/// Router,
/// };
/// use headers::UserAgent;
/// use axum_extra::TypedHeader;
///
/// async fn users_teams_show(
/// TypedHeader(user_agent): TypedHeader<UserAgent>,
Expand All @@ -34,10 +38,10 @@ use std::{convert::Infallible, ops::Deref};
///
/// ```rust
/// use axum::{
/// TypedHeader,
/// response::IntoResponse,
/// headers::ContentType,
/// };
/// use headers::ContentType;
/// use axum_extra::TypedHeader;
///
/// async fn handler() -> (TypedHeader<ContentType>, &'static str) {
/// (
Expand All @@ -46,15 +50,15 @@ use std::{convert::Infallible, ops::Deref};
/// )
/// }
/// ```
#[cfg(feature = "headers")]
#[cfg(feature = "typed-header")]
#[derive(Debug, Clone, Copy)]
#[must_use]
pub struct TypedHeader<T>(pub T);

#[async_trait]
impl<T, S> FromRequestParts<S> for TypedHeader<T>
where
T: headers::Header,
T: Header,
S: Send + Sync,
{
type Rejection = TypedHeaderRejection;
Expand Down Expand Up @@ -86,7 +90,7 @@ impl<T> Deref for TypedHeader<T> {

impl<T> IntoResponseParts for TypedHeader<T>
where
T: headers::Header,
T: Header,
{
type Error = Infallible;

Expand All @@ -98,7 +102,7 @@ where

impl<T> IntoResponse for TypedHeader<T>
where
T: headers::Header,
T: Header,
{
fn into_response(self) -> Response {
let mut res = ().into_response();
Expand All @@ -107,8 +111,8 @@ where
}
}

/// Rejection used for [`TypedHeader`](super::TypedHeader).
#[cfg(feature = "headers")]
/// Rejection used for [`TypedHeader`](TypedHeader).
#[cfg(feature = "typed-header")]
#[derive(Debug)]
pub struct TypedHeaderRejection {
name: &'static http::header::HeaderName,
Expand All @@ -128,7 +132,7 @@ impl TypedHeaderRejection {
}

/// Additional information regarding a [`TypedHeaderRejection`]
#[cfg(feature = "headers")]
#[cfg(feature = "typed-header")]
#[derive(Debug)]
#[non_exhaustive]
pub enum TypedHeaderRejectionReason {
Expand Down Expand Up @@ -169,9 +173,10 @@ impl std::error::Error for TypedHeaderRejection {
#[cfg(test)]
mod tests {
use super::*;
use crate::{response::IntoResponse, routing::get, test_helpers::*, Router};
use crate::test_helpers::*;
use axum::{response::IntoResponse, routing::get, Router};

#[crate::test]
#[tokio::test]
async fn typed_header() {
async fn handle(
TypedHeader(user_agent): TypedHeader<headers::UserAgent>,
Expand Down
4 changes: 2 additions & 2 deletions axum-macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ syn = { version = "2.0", features = [
] }

[dev-dependencies]
axum = { path = "../axum", version = "0.6.0", features = ["headers", "macros"] }
axum-extra = { path = "../axum-extra", version = "0.7.0", features = ["typed-routing", "cookie-private"] }
axum = { path = "../axum", version = "0.6.0", features = ["macros"] }
axum-extra = { path = "../axum-extra", version = "0.7.0", features = ["typed-routing", "cookie-private", "typed-header"] }
rustversion = "1.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
Expand Down
2 changes: 1 addition & 1 deletion axum-macros/rust-toolchain
Original file line number Diff line number Diff line change
@@ -1 +1 @@
nightly-2022-11-18
nightly-2023-04-06
Loading

0 comments on commit ac09dd8

Please sign in to comment.