Skip to content

Commit

Permalink
Path impl_for override. PathBuilder::path_from (#759)
Browse files Browse the repository at this point in the history
Add `impl_for = ...` attribute for `#[utoipa::path(...)]` macro. This allows 
users to use a custom type the `Path` trait will be implemented for 
instead of the default new type.
  • Loading branch information
wyatt-herkamp authored Dec 14, 2023
1 parent a968ced commit 1b9c39b
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 6 deletions.
4 changes: 4 additions & 0 deletions utoipa-gen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,10 @@ pub fn derive_to_schema(input: TokenStream) -> TokenStream {
///
/// * `path = "..."` Must be OpenAPI format compatible str with arguments within curly braces. E.g _`{id}`_
///
///
/// * `impl_for = ...` Optional type to implement the [`Path`][path] trait. By default a new type
/// is used for the implementation.
///
/// * `operation_id = ...` Unique operation id for the endpoint. By default this is mapped to function name.
/// The operation_id can be any valid expression (e.g. string literals, macro invocations, variables) so long
/// as its result can be converted to a `String` using `String::from`.
Expand Down
23 changes: 17 additions & 6 deletions utoipa-gen/src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ pub struct PathAttr<'p> {
params: Vec<Parameter<'p>>,
security: Option<Array<'p, SecurityRequirementsAttr>>,
context_path: Option<parse_utils::Value>,
impl_for: Option<Ident>,
}

impl<'p> PathAttr<'p> {
Expand Down Expand Up @@ -144,6 +145,10 @@ impl Parse for PathAttr<'_> {
path_attr.context_path =
Some(parse_utils::parse_next_literal_str_or_expr(input)?)
}
"impl_for" => {
path_attr.impl_for =
Some(parse_utils::parse_next(input, || input.parse::<Ident>())?);
}
_ => {
// any other case it is expected to be path operation
if let Some(path_operation) =
Expand Down Expand Up @@ -289,7 +294,6 @@ impl<'p> Path<'p> {

impl<'p> ToTokens for Path<'p> {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
let path_struct = format_ident!("{}{}", PATH_STRUCT_PREFIX, self.fn_name);
let operation_id = self
.path_attr
.operation_id
Expand Down Expand Up @@ -385,13 +389,20 @@ impl<'p> ToTokens for Path<'p> {
responses: self.path_attr.responses.as_ref(),
security: self.path_attr.security.as_ref(),
};

let impl_for = if let Some(impl_for) = &self.path_attr.impl_for {
impl_for.clone()
} else {
let path_struct = format_ident!("{}{}", PATH_STRUCT_PREFIX, self.fn_name);
tokens.extend(quote! {
#[allow(non_camel_case_types)]
#[doc(hidden)]
pub struct #path_struct;
});
path_struct
};
tokens.extend(quote! {
#[allow(non_camel_case_types)]
#[doc(hidden)]
pub struct #path_struct;

impl utoipa::Path for #path_struct {
impl utoipa::Path for #impl_for {
fn path() -> String {
#path_with_context_path
}
Expand Down
6 changes: 6 additions & 0 deletions utoipa/src/openapi/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
//! [paths]: https://spec.openapis.org/oas/latest.html#paths-object
use std::{collections::HashMap, iter};

use crate::Path;
use serde::{Deserialize, Serialize};
use serde_json::Value;

Expand Down Expand Up @@ -107,6 +108,11 @@ impl PathsBuilder {
pub fn extensions(mut self, extensions: Option<HashMap<String, serde_json::Value>>) -> Self {
set_value!(self extensions extensions)
}
/// Appends a [`Path`] to map of paths. By calling [`path`](PathsBuilder::path) method.
/// None will be passed into [Path::path_item] method.
pub fn path_from<P: Path>(self) -> Self {
self.path(P::path(), P::path_item(None))
}
}

builder! {
Expand Down

0 comments on commit 1b9c39b

Please sign in to comment.