Skip to content

Commit

Permalink
feat(openapi): added example value support for param/schema (#717)
Browse files Browse the repository at this point in the history
* feat(openapi): added implementation for example schema

* fix formatting
  • Loading branch information
chirag-droid authored Jan 21, 2024
1 parent e2a7c6e commit 934e27c
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 1 deletion.
29 changes: 28 additions & 1 deletion poem-openapi-derive/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ use syn::{
};

use crate::{
common_args::{APIMethod, CodeSample, DefaultValue, ExternalDocument, ExtraHeader},
common_args::{
APIMethod, CodeSample, DefaultValue, ExampleValue, ExternalDocument, ExtraHeader,
},
error::GeneratorResult,
utils::{
convert_oai_path, get_crate_name, get_description, get_summary_and_description,
Expand Down Expand Up @@ -68,6 +70,8 @@ struct APIOperationParam {
#[darling(default)]
default: Option<DefaultValue>,
#[darling(default)]
example: Option<ExampleValue>,
#[darling(default)]
validator: Option<Validators>,
#[darling(default)]
explode: Option<bool>,
Expand Down Expand Up @@ -306,6 +310,27 @@ fn generate_operation(
None => quote!(::std::option::Option::None),
};

// example value for parameter
let example_value = match &operation_param.example {
Some(ExampleValue::Default) => {
quote!(::std::option::Option::Some(<<#arg_ty as #crate_name::ApiExtractor>::ParamType as std::default::Default>::default))
}
Some(ExampleValue::Function(func_name)) => {
quote!(::std::option::Option::Some(#func_name))
}
None => quote!(::std::option::Option::None),
};

let param_meta_example = match &operation_param.example {
Some(ExampleValue::Default) => {
quote!(#crate_name::types::ToJSON::to_json(&<<#arg_ty as #crate_name::ApiExtractor>::ParamType as std::default::Default>::default()))
}
Some(ExampleValue::Function(func_name)) => {
quote!(#crate_name::types::ToJSON::to_json(&#func_name()))
}
None => quote!(::std::option::Option::None),
};

// validator
let validator = operation_param.validator.clone().unwrap_or_default();
let param_checker = validator.create_param_checker(crate_name, &res_ty, &param_name)?.map(|stream| {
Expand All @@ -326,6 +351,7 @@ fn generate_operation(
let mut param_opts = #crate_name::ExtractParamOptions {
name: #param_name,
default_value: #default_value,
example_value: #example_value,
explode: #explode,
};

Expand All @@ -351,6 +377,7 @@ fn generate_operation(
let mut patch_schema = {
let mut schema = #crate_name::registry::MetaSchema::ANY;
schema.default = #param_meta_default;
schema.example = #param_meta_example;
#validators_update_meta
schema
};
Expand Down
19 changes: 19 additions & 0 deletions poem-openapi-derive/src/common_args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,25 @@ impl FromMeta for DefaultValue {
}
}

#[derive(Debug)]
pub(crate) enum ExampleValue {
Default,
Function(Path),
}

impl FromMeta for ExampleValue {
fn from_word() -> darling::Result<Self> {
Ok(ExampleValue::Default)
}

fn from_value(value: &Lit) -> darling::Result<Self> {
match value {
Lit::Str(str) => Ok(ExampleValue::Function(syn::parse_str(&str.value())?)),
_ => Err(darling::Error::unexpected_lit_type(value).with_span(value)),
}
}
}

#[derive(FromMeta, Clone)]
pub(crate) struct MaximumValidator {
pub(crate) value: f64,
Expand Down
4 changes: 4 additions & 0 deletions poem-openapi/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ pub struct ExtractParamOptions<T> {
/// The default value of this parameter.
pub default_value: Option<fn() -> T>,

/// The example value of this parameter.
pub example_value: Option<fn() -> T>,

/// When this is `true`, parameter values of type array or object generate
/// separate parameters for each value of the array or key-value pair of the
/// map.
Expand All @@ -77,6 +80,7 @@ impl<T> Default for ExtractParamOptions<T> {
Self {
name: "",
default_value: None,
example_value: None,
explode: true,
}
}
Expand Down
46 changes: 46 additions & 0 deletions poem-openapi/tests/operation_param.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,52 @@ async fn default_opt() {
.assert_status_is_ok();
}

#[tokio::test]
async fn example() {
struct Api;

#[OpenApi]
#[allow(unused_variables)]
impl Api {
#[oai(path = "/", method = "get")]
async fn test(
&self,
#[oai(example = "example_value")] a: Query<Option<i32>>,
#[oai(example)] b: Query<i32>,
) {
todo!();
}
}

fn example_value() -> Option<i32> {
Some(88)
}

let meta: MetaApi = Api::meta().remove(0);
assert_eq!(
meta.paths[0].operations[0].params[0].in_type,
MetaParamIn::Query
);

assert_eq!(meta.paths[0].operations[0].params[0].name, "a");
assert_eq!(
meta.paths[0].operations[0].params[0]
.schema
.unwrap_inline()
.example,
Some(json!(88))
);

assert_eq!(meta.paths[0].operations[0].params[1].name, "b");
assert_eq!(
meta.paths[0].operations[0].params[1]
.schema
.unwrap_inline()
.example,
Some(json!(0))
);
}

#[tokio::test]
async fn required_params() {
struct Api;
Expand Down

0 comments on commit 934e27c

Please sign in to comment.