diff --git a/poem-openapi-derive/src/utils.rs b/poem-openapi-derive/src/utils.rs index 2fe6de43a9..959ccc1f97 100644 --- a/poem-openapi-derive/src/utils.rs +++ b/poem-openapi-derive/src/utils.rs @@ -191,13 +191,12 @@ pub(crate) fn create_object_name( use ::std::convert::From; let mut name = ::std::string::String::from(#name); - name.push('<'); + name.push('_'); name.push_str(&<#first as #crate_name::types::Type>::name()); #( - name.push_str(", "); + name.push_str("_"); name.push_str(&<#tail as #crate_name::types::Type>::name()); )* - name.push('>'); name }) diff --git a/poem-openapi/src/types/base64_type.rs b/poem-openapi/src/types/base64_type.rs index 80bb798608..fcaa0b005e 100644 --- a/poem-openapi/src/types/base64_type.rs +++ b/poem-openapi/src/types/base64_type.rs @@ -38,7 +38,7 @@ impl + Send + Sync> Type for Base64 { type RawElementValueType = Self; fn name() -> Cow<'static, str> { - "string(bytes)".into() + "string_bytes".into() } fn schema_ref() -> MetaSchemaRef { diff --git a/poem-openapi/src/types/binary.rs b/poem-openapi/src/types/binary.rs index 5be5f949af..e8f3eb2f41 100644 --- a/poem-openapi/src/types/binary.rs +++ b/poem-openapi/src/types/binary.rs @@ -37,7 +37,7 @@ impl + Send + Sync> Type for Binary { type RawElementValueType = Self; fn name() -> Cow<'static, str> { - "string(binary)".into() + "string_binary".into() } fn schema_ref() -> MetaSchemaRef { diff --git a/poem-openapi/src/types/external/array.rs b/poem-openapi/src/types/external/array.rs index 37277e6c9e..25436b85a9 100644 --- a/poem-openapi/src/types/external/array.rs +++ b/poem-openapi/src/types/external/array.rs @@ -15,7 +15,7 @@ impl Type for [T; LEN] { type RawElementValueType = T::RawValueType; fn name() -> Cow<'static, str> { - format!("[{}]", T::name()).into() + format!("array_{}", T::name()).into() } fn schema_ref() -> MetaSchemaRef { diff --git a/poem-openapi/src/types/external/bson.rs b/poem-openapi/src/types/external/bson.rs index cec396ff3f..bbddacb226 100644 --- a/poem-openapi/src/types/external/bson.rs +++ b/poem-openapi/src/types/external/bson.rs @@ -20,7 +20,7 @@ impl Type for ObjectId { type RawElementValueType = Self; fn name() -> Cow<'static, str> { - "string(oid)".into() + "string_oid".into() } fn schema_ref() -> MetaSchemaRef { diff --git a/poem-openapi/src/types/external/btreemap.rs b/poem-openapi/src/types/external/btreemap.rs index e4adbb2c91..97b0023df5 100644 --- a/poem-openapi/src/types/external/btreemap.rs +++ b/poem-openapi/src/types/external/btreemap.rs @@ -19,7 +19,7 @@ where type RawElementValueType = V::RawValueType; fn name() -> Cow<'static, str> { - format!("map", V::name()).into() + format!("map_{}", V::name()).into() } fn schema_ref() -> MetaSchemaRef { diff --git a/poem-openapi/src/types/external/btreeset.rs b/poem-openapi/src/types/external/btreeset.rs index 76a239887e..baccccbd02 100644 --- a/poem-openapi/src/types/external/btreeset.rs +++ b/poem-openapi/src/types/external/btreeset.rs @@ -19,7 +19,7 @@ impl Type for BTreeSet { type RawElementValueType = T::RawValueType; fn name() -> Cow<'static, str> { - format!("[{}]", T::name()).into() + format!("set_{}", T::name()).into() } fn schema_ref() -> MetaSchemaRef { diff --git a/poem-openapi/src/types/external/chrono.rs b/poem-openapi/src/types/external/chrono.rs index 5e80eda550..63642f536a 100644 --- a/poem-openapi/src/types/external/chrono.rs +++ b/poem-openapi/src/types/external/chrono.rs @@ -22,7 +22,7 @@ macro_rules! impl_datetime_types { type RawElementValueType = Self; fn name() -> Cow<'static, str> { - concat!($type_name, "(", $format, ")").into() + concat!($type_name, "_", $format).into() } fn schema_ref() -> MetaSchemaRef { @@ -88,7 +88,7 @@ macro_rules! impl_naive_datetime_types { type RawElementValueType = Self; fn name() -> Cow<'static, str> { - concat!($type_name, "(", $format, ")").into() + concat!($type_name, "_", $format).into() } fn schema_ref() -> MetaSchemaRef { diff --git a/poem-openapi/src/types/external/decimal.rs b/poem-openapi/src/types/external/decimal.rs index 4cf675f1b0..2f50b8a63c 100644 --- a/poem-openapi/src/types/external/decimal.rs +++ b/poem-openapi/src/types/external/decimal.rs @@ -20,7 +20,7 @@ impl Type for Decimal { type RawElementValueType = Self; fn name() -> Cow<'static, str> { - "string(decimal)".into() + "string_decimal".into() } fn schema_ref() -> MetaSchemaRef { diff --git a/poem-openapi/src/types/external/floats.rs b/poem-openapi/src/types/external/floats.rs index 7f80cfe5f1..19c945b026 100644 --- a/poem-openapi/src/types/external/floats.rs +++ b/poem-openapi/src/types/external/floats.rs @@ -22,7 +22,7 @@ macro_rules! impl_type_for_floats { type RawElementValueType = Self; fn name() -> Cow<'static, str> { - format!("number({})", $format).into() + format!("number_{}", $format).into() } fn schema_ref() -> MetaSchemaRef { diff --git a/poem-openapi/src/types/external/geo.rs b/poem-openapi/src/types/external/geo.rs index cbab0afc41..fe38d15073 100644 --- a/poem-openapi/src/types/external/geo.rs +++ b/poem-openapi/src/types/external/geo.rs @@ -18,7 +18,7 @@ macro_rules! impl_geojson_types { type RawElementValueType = Self; fn name() -> ::std::borrow::Cow<'static, str> { - concat!("GeoJSON<", $name, ">").into() + concat!("GeoJSON_", $name).into() } fn schema_ref() -> crate::registry::MetaSchemaRef { diff --git a/poem-openapi/src/types/external/hashmap.rs b/poem-openapi/src/types/external/hashmap.rs index 32a01b849b..a07d3759a7 100644 --- a/poem-openapi/src/types/external/hashmap.rs +++ b/poem-openapi/src/types/external/hashmap.rs @@ -26,7 +26,7 @@ where type RawElementValueType = V::RawValueType; fn name() -> Cow<'static, str> { - format!("map", V::name()).into() + format!("map_{}", V::name()).into() } fn schema_ref() -> MetaSchemaRef { diff --git a/poem-openapi/src/types/external/hashset.rs b/poem-openapi/src/types/external/hashset.rs index 627fa2ee16..afc46b86ba 100644 --- a/poem-openapi/src/types/external/hashset.rs +++ b/poem-openapi/src/types/external/hashset.rs @@ -23,7 +23,7 @@ impl Type for HashSet { type RawElementValueType = T::RawValueType; fn name() -> Cow<'static, str> { - format!("[{}]", T::name()).into() + format!("set_{}", T::name()).into() } fn schema_ref() -> MetaSchemaRef { diff --git a/poem-openapi/src/types/external/humantime.rs b/poem-openapi/src/types/external/humantime.rs index 2c4d0e2a85..f7cd79fa48 100644 --- a/poem-openapi/src/types/external/humantime.rs +++ b/poem-openapi/src/types/external/humantime.rs @@ -19,7 +19,7 @@ impl Type for Duration { type RawElementValueType = Self; fn name() -> Cow<'static, str> { - "string(duration)".into() + "string_duration".into() } fn schema_ref() -> MetaSchemaRef { diff --git a/poem-openapi/src/types/external/humantime_wrapper.rs b/poem-openapi/src/types/external/humantime_wrapper.rs index 7619f09049..d8a722e341 100644 --- a/poem-openapi/src/types/external/humantime_wrapper.rs +++ b/poem-openapi/src/types/external/humantime_wrapper.rs @@ -20,7 +20,7 @@ impl Type for Duration { type RawElementValueType = Self; fn name() -> Cow<'static, str> { - "string(duration)".into() + "string_duration".into() } fn schema_ref() -> MetaSchemaRef { diff --git a/poem-openapi/src/types/external/integers.rs b/poem-openapi/src/types/external/integers.rs index 547366bba0..b575e04ca2 100644 --- a/poem-openapi/src/types/external/integers.rs +++ b/poem-openapi/src/types/external/integers.rs @@ -22,7 +22,7 @@ macro_rules! impl_type_for_integers { type RawElementValueType = Self; fn name() -> Cow<'static, str> { - format!("integer({})", $format).into() + format!("integer_{}", $format).into() } fn schema_ref() -> MetaSchemaRef { diff --git a/poem-openapi/src/types/external/ip.rs b/poem-openapi/src/types/external/ip.rs index 490d9e0d36..c7d38d5720 100644 --- a/poem-openapi/src/types/external/ip.rs +++ b/poem-openapi/src/types/external/ip.rs @@ -37,7 +37,7 @@ macro_rules! impl_type_for_ip { type RawElementValueType = Self; fn name() -> Cow<'static, str> { - format!("string({})", $format).into() + format!("string_{}", $format).into() } fn schema_ref() -> MetaSchemaRef { diff --git a/poem-openapi/src/types/external/optional.rs b/poem-openapi/src/types/external/optional.rs index a841daebd6..ca5d272611 100644 --- a/poem-openapi/src/types/external/optional.rs +++ b/poem-openapi/src/types/external/optional.rs @@ -19,7 +19,7 @@ impl Type for Option { type RawElementValueType = T::RawElementValueType; fn name() -> Cow<'static, str> { - format!("optional<{}>", T::name()).into() + format!("optional_{}", T::name()).into() } fn schema_ref() -> MetaSchemaRef { diff --git a/poem-openapi/src/types/external/prost_wkt_types/struct.rs b/poem-openapi/src/types/external/prost_wkt_types/struct.rs index 29c7461265..55379d8791 100644 --- a/poem-openapi/src/types/external/prost_wkt_types/struct.rs +++ b/poem-openapi/src/types/external/prost_wkt_types/struct.rs @@ -15,7 +15,7 @@ impl Type for prost_wkt_types::Struct { type RawElementValueType = ::RawValueType; fn name() -> Cow<'static, str> { - "Protobuf Struct".into() + "Protobuf_Struct".into() } fn schema_ref() -> MetaSchemaRef { diff --git a/poem-openapi/src/types/external/prost_wkt_types/value.rs b/poem-openapi/src/types/external/prost_wkt_types/value.rs index 7bd4972433..e76cb99733 100644 --- a/poem-openapi/src/types/external/prost_wkt_types/value.rs +++ b/poem-openapi/src/types/external/prost_wkt_types/value.rs @@ -15,7 +15,7 @@ impl Type for prost_wkt_types::Value { type RawElementValueType = prost_wkt_types::Value; fn name() -> Cow<'static, str> { - "Protobuf Value".into() + "Protobuf_Value".into() } fn schema_ref() -> MetaSchemaRef { diff --git a/poem-openapi/src/types/external/regex.rs b/poem-openapi/src/types/external/regex.rs index c1cd1ad7ce..8fcda1cd5b 100644 --- a/poem-openapi/src/types/external/regex.rs +++ b/poem-openapi/src/types/external/regex.rs @@ -20,7 +20,7 @@ impl Type for Regex { type RawElementValueType = Self; fn name() -> Cow<'static, str> { - "string(regex)".into() + "string_regex".into() } fn schema_ref() -> MetaSchemaRef { diff --git a/poem-openapi/src/types/external/slice.rs b/poem-openapi/src/types/external/slice.rs index 82076e0f45..d98aca9d59 100644 --- a/poem-openapi/src/types/external/slice.rs +++ b/poem-openapi/src/types/external/slice.rs @@ -15,7 +15,7 @@ impl Type for &[T] { type RawElementValueType = T::RawValueType; fn name() -> Cow<'static, str> { - format!("[{}]", T::name()).into() + format!("slice_{}", T::name()).into() } fn schema_ref() -> MetaSchemaRef { diff --git a/poem-openapi/src/types/external/time.rs b/poem-openapi/src/types/external/time.rs index 1d34d19006..c9949ada29 100644 --- a/poem-openapi/src/types/external/time.rs +++ b/poem-openapi/src/types/external/time.rs @@ -23,7 +23,7 @@ impl Type for OffsetDateTime { type RawElementValueType = Self; fn name() -> Cow<'static, str> { - "string(date-time)".into() + "string_date-time".into() } fn schema_ref() -> MetaSchemaRef { @@ -83,7 +83,7 @@ macro_rules! impl_naive_datetime_types { type RawElementValueType = Self; fn name() -> Cow<'static, str> { - concat!($type_name, "(", $format, ")").into() + concat!($type_name, "_", $format).into() } fn schema_ref() -> MetaSchemaRef { diff --git a/poem-openapi/src/types/external/uri.rs b/poem-openapi/src/types/external/uri.rs index e83e9c0e4e..44b09eede8 100644 --- a/poem-openapi/src/types/external/uri.rs +++ b/poem-openapi/src/types/external/uri.rs @@ -22,7 +22,7 @@ impl Type for Uri { type RawElementValueType = Self; fn name() -> Cow<'static, str> { - "string(uri)".into() + "string_uri".into() } fn schema_ref() -> MetaSchemaRef { diff --git a/poem-openapi/src/types/external/url.rs b/poem-openapi/src/types/external/url.rs index 3d7904e872..e7085651ff 100644 --- a/poem-openapi/src/types/external/url.rs +++ b/poem-openapi/src/types/external/url.rs @@ -20,7 +20,7 @@ impl Type for Url { type RawElementValueType = Self; fn name() -> Cow<'static, str> { - "string(url)".into() + "string_url".into() } fn schema_ref() -> MetaSchemaRef { diff --git a/poem-openapi/src/types/external/uuid.rs b/poem-openapi/src/types/external/uuid.rs index e1d228f2ef..93552d608e 100644 --- a/poem-openapi/src/types/external/uuid.rs +++ b/poem-openapi/src/types/external/uuid.rs @@ -20,7 +20,7 @@ impl Type for Uuid { type RawElementValueType = Self; fn name() -> Cow<'static, str> { - "string(uuid)".into() + "string_uuid".into() } fn schema_ref() -> MetaSchemaRef { diff --git a/poem-openapi/src/types/external/vec.rs b/poem-openapi/src/types/external/vec.rs index 13458d8d84..3a4ed71588 100644 --- a/poem-openapi/src/types/external/vec.rs +++ b/poem-openapi/src/types/external/vec.rs @@ -19,7 +19,7 @@ impl Type for Vec { type RawElementValueType = T::RawValueType; fn name() -> Cow<'static, str> { - format!("[{}]", T::name()).into() + format!("list_{}", T::name()).into() } fn schema_ref() -> MetaSchemaRef { diff --git a/poem-openapi/src/types/maybe_undefined.rs b/poem-openapi/src/types/maybe_undefined.rs index 48eda7755e..f2388fac8a 100644 --- a/poem-openapi/src/types/maybe_undefined.rs +++ b/poem-openapi/src/types/maybe_undefined.rs @@ -316,7 +316,7 @@ impl Type for MaybeUndefined { type RawElementValueType = T::RawElementValueType; fn name() -> Cow<'static, str> { - format!("optional<{}>", T::name()).into() + format!("optional_{}", T::name()).into() } fn schema_ref() -> MetaSchemaRef { diff --git a/poem-openapi/src/types/mod.rs b/poem-openapi/src/types/mod.rs index 07e9834866..d7cbcf4b2f 100644 --- a/poem-openapi/src/types/mod.rs +++ b/poem-openapi/src/types/mod.rs @@ -441,7 +441,7 @@ mod tests { #[allow(clippy::assertions_on_constants)] fn arc_type() { assert!(Arc::::IS_REQUIRED); - assert_eq!(Arc::::name(), "integer(int32)"); + assert_eq!(Arc::::name(), "integer_int32"); assert_eq!(Arc::new(100).as_raw_value(), Some(&100)); let value: Arc = @@ -472,7 +472,7 @@ mod tests { #[allow(unused_allocation)] fn box_type() { assert!(Box::::IS_REQUIRED); - assert_eq!(Box::::name(), "integer(int32)"); + assert_eq!(Box::::name(), "integer_int32"); assert_eq!(Box::new(100).as_raw_value(), Some(&100)); let value: Box = diff --git a/poem-openapi/src/types/multipart/upload.rs b/poem-openapi/src/types/multipart/upload.rs index 2a3e5774fe..b0dc753470 100644 --- a/poem-openapi/src/types/multipart/upload.rs +++ b/poem-openapi/src/types/multipart/upload.rs @@ -92,7 +92,7 @@ impl Type for Upload { type RawElementValueType = Self; fn name() -> Cow<'static, str> { - "string(binary)".into() + "string_binary".into() } fn schema_ref() -> MetaSchemaRef { diff --git a/poem-openapi/src/types/string_types.rs b/poem-openapi/src/types/string_types.rs index c1df2c67b7..436d29dc39 100644 --- a/poem-openapi/src/types/string_types.rs +++ b/poem-openapi/src/types/string_types.rs @@ -48,7 +48,7 @@ macro_rules! impl_string_types { type RawElementValueType = Self; fn name() -> Cow<'static, str> { - concat!($type_name, "(", $format, ")").into() + concat!($type_name, "_", $format).into() } fn schema_ref() -> MetaSchemaRef { diff --git a/poem-openapi/tests/object.rs b/poem-openapi/tests/object.rs index 975f7badb7..578c1705e5 100644 --- a/poem-openapi/tests/object.rs +++ b/poem-openapi/tests/object.rs @@ -45,7 +45,7 @@ fn generics() { assert_eq!( >::name(), - "Obj" + "Obj_integer_int32_integer_int64" ); let meta = get_meta::>(); assert_eq!(meta.properties[0].1.unwrap_inline().ty, "integer"); @@ -56,7 +56,7 @@ fn generics() { assert_eq!( >::name(), - "Obj" + "Obj_number_float_number_double" ); let meta = get_meta::>(); assert_eq!(meta.properties[0].1.unwrap_inline().ty, "number"); diff --git a/poem-openapi/tests/query.rs b/poem-openapi/tests/query.rs new file mode 100644 index 0000000000..2dbe336891 --- /dev/null +++ b/poem-openapi/tests/query.rs @@ -0,0 +1,68 @@ +use poem::{ + http::{Method, StatusCode}, + test::TestClient, + Error, +}; +use poem_openapi::{ + param::Query, + payload::{Json, PlainText}, + registry::MetaApi, + types::{MaybeUndefined, ToJSON}, + ApiResponse, OpenApi, OpenApiService, +}; +use serde_json::Value; + +#[tokio::test] +async fn query_explode_false() { + #[derive(ApiResponse)] + #[oai(bad_request_handler = "bad_request_handler")] + enum MyResponse { + /// Ok + #[oai(status = 200)] + Ok(Json>), + /// Bad Request + #[oai(status = 400)] + BadRequest(PlainText), + } + + fn bad_request_handler(err: Error) -> MyResponse { + MyResponse::BadRequest(PlainText(format!("!!! {err}"))) + } + + const fn none() -> MaybeUndefined { + MaybeUndefined::Undefined + } + + struct Api; + + #[OpenApi] + impl Api { + #[oai(path = "/abc", method = "post")] + async fn test( + &self, + #[oai(explode = false, default = "none::>")] fields: Query< + MaybeUndefined>, + >, + ) -> MyResponse { + MyResponse::Ok(Json(fields.0.to_json())) + } + } + + let meta: MetaApi = Api::meta().remove(0); + assert_eq!(meta.paths[0].path, "/abc"); + assert_eq!(meta.paths[0].operations[0].method, Method::POST); + + let ep = OpenApiService::new(Api, "test", "1.0"); + let cli = TestClient::new(ep); + + let resp = cli.post("/abc").query("fields", &"1,2,3").send().await; + resp.assert_status_is_ok(); + resp.assert_json(&[1, 2, 3]).await; + + let resp = cli.post("/abc").query("fields", &"").send().await; + resp.assert_status(StatusCode::BAD_REQUEST); + + let resp = cli.post("/abc").send().await; + resp.assert_status_is_ok(); + resp.assert_json(Value::Null).await; +} diff --git a/poem-openapi/tests/union.rs b/poem-openapi/tests/union.rs index a784d3756f..7ce78d4506 100644 --- a/poem-openapi/tests/union.rs +++ b/poem-openapi/tests/union.rs @@ -514,11 +514,11 @@ async fn generics() { assert_eq!( >::schema_ref(), - MetaSchemaRef::Reference("MyObj".to_string()) + MetaSchemaRef::Reference("MyObj_integer_int32_integer_int64".to_string()) ); assert_eq!( >::schema_ref(), - MetaSchemaRef::Reference("MyObj".to_string()) + MetaSchemaRef::Reference("MyObj_number_float_number_double".to_string()) ); assert_eq!(schema_i32_i64.any_of[0], i32::schema_ref());