Skip to content

Commit

Permalink
Backport TypedPath::to_uri (#809)
Browse files Browse the repository at this point in the history
* axum-macros: use fully qualified Result type (#796)

* Easily convert typed paths into URIs (#790)

* Easily convert typed paths into URIs

`#[derive(TypedPath)]` will now also generate `TryFrom<_> for Uri` for
easily converting paths into URIs for use with `Redirect` and friends.

Fixes #789

* Use a method on the `TypedPath` trait to convert to `Uri`

* fix doc ref

* Update changelogs

* Remove out of date docs

These accidentally weren't removed in #790

Co-authored-by: Matthias Vogelgesang <matthias.vogelgesang@gmail.com>
  • Loading branch information
davidpdrsn and matze authored Mar 1, 2022
1 parent 558a4d0 commit 84cbb66
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 5 deletions.
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](https://semver.org/spec/v2.0.0

# Unreleased

- None.
- **added:** Add `TypedPath::to_uri` for converting the path into a `Uri` ([#790])

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

# 0.1.4 (22. February, 2022)

Expand Down
16 changes: 16 additions & 0 deletions axum-extra/src/routing/typed.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::sealed::Sealed;
use http::Uri;

/// A type safe path.
///
Expand Down Expand Up @@ -148,6 +149,21 @@ use super::sealed::Sealed;
pub trait TypedPath: std::fmt::Display {
/// The path with optional captures such as `/users/:id`.
const PATH: &'static str;

/// Convert the path into a `Uri`.
///
/// # Panics
///
/// The default implementation parses the required [`Display`] implemetation. If that fails it
/// will panic.
///
/// Using `#[derive(TypedPath)]` will never result in a panic since it percent-encodes
/// arguments.
///
/// [`Display`]: std::fmt::Display
fn to_uri(&self) -> Uri {
self.to_string().parse().unwrap()
}
}

/// Utility trait used with [`RouterExt`] to ensure the first element of a tuple type is a
Expand Down
8 changes: 4 additions & 4 deletions axum-macros/src/typed_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub(crate) fn expand(item_struct: ItemStruct) -> syn::Result<TokenStream> {
let segments = parse_path(&path)?;
expand_unnamed_fields(fields, ident, path, &segments)
}
syn::Fields::Unit => Ok(expand_unit_fields(ident, path)?),
syn::Fields::Unit => expand_unit_fields(ident, path),
}
}

Expand Down Expand Up @@ -97,7 +97,7 @@ fn expand_named_fields(ident: &syn::Ident, path: LitStr, segments: &[Segment]) -
{
type Rejection = <::axum::extract::Path<Self> as ::axum::extract::FromRequest<B>>::Rejection;

async fn from_request(req: &mut ::axum::extract::RequestParts<B>) -> Result<Self, Self::Rejection> {
async fn from_request(req: &mut ::axum::extract::RequestParts<B>) -> ::std::result::Result<Self, Self::Rejection> {
::axum::extract::Path::from_request(req).await.map(|path| path.0)
}
}
Expand Down Expand Up @@ -186,7 +186,7 @@ fn expand_unnamed_fields(
{
type Rejection = <::axum::extract::Path<Self> as ::axum::extract::FromRequest<B>>::Rejection;

async fn from_request(req: &mut ::axum::extract::RequestParts<B>) -> Result<Self, Self::Rejection> {
async fn from_request(req: &mut ::axum::extract::RequestParts<B>) -> ::std::result::Result<Self, Self::Rejection> {
::axum::extract::Path::from_request(req).await.map(|path| path.0)
}
}
Expand Down Expand Up @@ -245,7 +245,7 @@ fn expand_unit_fields(ident: &syn::Ident, path: LitStr) -> syn::Result<TokenStre
{
type Rejection = ::axum::http::StatusCode;

async fn from_request(req: &mut ::axum::extract::RequestParts<B>) -> Result<Self, Self::Rejection> {
async fn from_request(req: &mut ::axum::extract::RequestParts<B>) -> ::std::result::Result<Self, Self::Rejection> {
if req.uri().path() == <Self as ::axum_extra::routing::TypedPath>::PATH {
Ok(Self)
} else {
Expand Down
23 changes: 23 additions & 0 deletions axum-macros/tests/typed_path/pass/into_uri.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use axum_extra::routing::TypedPath;
use axum::http::Uri;
use serde::Deserialize;

#[derive(TypedPath, Deserialize)]
#[typed_path("/:id")]
struct Named {
id: u32,
}

#[derive(TypedPath, Deserialize)]
#[typed_path("/:id")]
struct Unnamed(u32);

#[derive(TypedPath, Deserialize)]
#[typed_path("/")]
struct Unit;

fn main() {
let _: Uri = Named { id: 1 }.to_uri();
let _: Uri = Unnamed(1).to_uri();
let _: Uri = Unit.to_uri();
}
2 changes: 2 additions & 0 deletions axum-macros/tests/typed_path/pass/tuple_struct.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use axum_extra::routing::TypedPath;
use serde::Deserialize;

pub type Result<T> = std::result::Result<T, ()>;

#[derive(TypedPath, Deserialize)]
#[typed_path("/users/:user_id/teams/:team_id")]
struct MyPath(u32, u32);
Expand Down

0 comments on commit 84cbb66

Please sign in to comment.