-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Also rename request_body attribute to body and axum-integration feature to axum
- Loading branch information
Showing
14 changed files
with
265 additions
and
106 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
use std::collections::HashSet; | ||
|
||
use syn::{PatType, Type}; | ||
|
||
use super::{RequestBody, RequestBodyAttrs}; | ||
use crate::error::Error; | ||
|
||
lazy_static::lazy_static! { | ||
static ref KNOWN_BODY_TYPES: HashSet<&'static str> = [ | ||
"Json", | ||
].into_iter().collect(); | ||
} | ||
|
||
impl RequestBody { | ||
pub(super) fn try_find_axum(pt: &PatType) -> Result<Option<Self>, Error> { | ||
let Type::Path(ref path) = *pt.ty else { | ||
return Ok(None); | ||
}; | ||
for pat_seg in path.path.segments.iter().rev() { | ||
if KNOWN_BODY_TYPES.contains(pat_seg.ident.to_string().as_str()) { | ||
return Ok(Some(Self { | ||
argument_type: *pt.ty.clone(), | ||
attrs: RequestBodyAttrs::default(), | ||
})); | ||
} | ||
} | ||
|
||
Ok(None) | ||
} | ||
} |
122 changes: 122 additions & 0 deletions
122
okapi-operation-macro/src/operation/request_body/mod.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
use darling::FromMeta; | ||
use proc_macro2::TokenStream; | ||
use quote::{quote, ToTokens}; | ||
use syn::{FnArg, ItemFn, PatType, Path, Type}; | ||
|
||
use crate::{ | ||
error::Error, | ||
utils::{attribute_to_args, quote_option}, | ||
}; | ||
|
||
#[cfg(feature = "axum")] | ||
mod axum; | ||
|
||
static REQUEST_BODY_ATTRIBUTE_NAME_DEPRECATED: &str = "request_body"; | ||
static REQUEST_BODY_ATTRIBUTE_NAME: &str = "body"; | ||
|
||
/// Request body definition for inline attribute. | ||
#[derive(Debug, FromMeta, Default)] | ||
struct RequestBodyAttrs { | ||
#[darling(default)] | ||
description: Option<String>, | ||
#[darling(default)] | ||
required: bool, | ||
#[darling(default)] | ||
content: Option<Path>, | ||
} | ||
|
||
#[derive(Debug)] | ||
pub(super) struct RequestBody { | ||
attrs: RequestBodyAttrs, | ||
argument_type: Type, | ||
} | ||
|
||
impl RequestBody { | ||
/// Create body definition from function signature. | ||
pub(super) fn from_item_fn(item_fn: &mut ItemFn) -> Result<Option<Self>, Error> { | ||
for pt in item_fn.sig.inputs.iter_mut().filter_map(|x| match x { | ||
FnArg::Receiver(_) => None, | ||
FnArg::Typed(y) => Some(y), | ||
}) { | ||
if let Some(x) = Self::try_find_in_arg_attrs(pt)? { | ||
return Ok(Some(x)); | ||
} | ||
|
||
if let Some(x) = Self::try_find_framework_specific(pt)? { | ||
return Ok(Some(x)); | ||
} | ||
} | ||
|
||
Ok(None) | ||
} | ||
|
||
// NOTE: also removes all related attributes | ||
fn try_find_in_arg_attrs(pt: &mut PatType) -> Result<Option<Self>, Error> { | ||
let mut non_matched_attrs = vec![]; | ||
let mut matched_attrs = vec![]; | ||
|
||
// Check attributes, removing matching | ||
for attr in pt.attrs.drain(..) { | ||
if attr.path.get_ident().map_or(false, |x| { | ||
x == REQUEST_BODY_ATTRIBUTE_NAME || x == REQUEST_BODY_ATTRIBUTE_NAME_DEPRECATED | ||
}) { | ||
matched_attrs.push(attr); | ||
} else { | ||
non_matched_attrs.push(attr); | ||
} | ||
} | ||
pt.attrs = non_matched_attrs; | ||
|
||
if matched_attrs.len() > 1 { | ||
return Err(Error::syn_spanned( | ||
pt, | ||
"Only single #[body] argument allowed", | ||
)); | ||
} | ||
let Some(attr) = matched_attrs.into_iter().next() else { | ||
return Ok(None); | ||
}; | ||
let parsed_attrs = RequestBodyAttrs::from_list(&attribute_to_args(&attr, true)?)?; | ||
|
||
Ok(Some(Self { | ||
attrs: parsed_attrs, | ||
argument_type: *pt.ty.clone(), | ||
})) | ||
} | ||
|
||
// TODO: allow disable this behaviour | ||
#[allow(unused)] | ||
fn try_find_framework_specific(pt: &PatType) -> Result<Option<Self>, Error> { | ||
#[cfg(feature = "axum")] | ||
if let Some(x) = Self::try_find_axum(pt)? { | ||
return Ok(Some(x)); | ||
} | ||
|
||
Ok(None) | ||
} | ||
} | ||
|
||
impl ToTokens for RequestBody { | ||
fn to_tokens(&self, tokens: &mut TokenStream) { | ||
let description = quote_option(&self.attrs.description); | ||
let required = self.attrs.required; | ||
let content_generator = if let Some(ref x) = self.attrs.content { | ||
quote! { | ||
<#x as ToMediaTypes>::generate | ||
} | ||
} else { | ||
let ty = &self.argument_type; | ||
quote! { | ||
<#ty as ToMediaTypes>::generate | ||
} | ||
}; | ||
tokens.extend(quote! { | ||
okapi::openapi3::RequestBody { | ||
description: #description, | ||
required: #required, | ||
content: #content_generator(components)?, | ||
..Default::default() | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.