@@ -9,6 +9,7 @@ use crate::error::ValidationError;
99use once_cell:: sync:: Lazy ;
1010use paperclip_macros:: api_v2_schema_struct;
1111use regex:: { Captures , Regex } ;
12+ use serde:: ser:: { SerializeMap , Serializer } ;
1213
1314#[ cfg( feature = "actix-base" ) ]
1415use actix_web:: http:: Method ;
@@ -135,6 +136,36 @@ pub type ResolvableApi<S> = Api<ResolvableParameter<S>, ResolvableResponse<S>, R
135136/// OpenAPI v2 spec with defaults.
136137pub type DefaultApiRaw = Api < DefaultParameterRaw , DefaultResponseRaw , DefaultSchemaRaw > ;
137138
139+ fn strip_templates_from_paths < P : serde:: ser:: Serialize , R : serde:: ser:: Serialize , S : Serializer > (
140+ tree : & BTreeMap < String , PathItem < P , R > > ,
141+ serializer : S ,
142+ ) -> Result < S :: Ok , S :: Error > {
143+ let len = tree. len ( ) ;
144+ let mut map = serializer. serialize_map ( Some ( len) ) ?;
145+ for ( k, v) in tree {
146+ let path = strip_pattern_from_template ( k) ;
147+ map. serialize_entry ( & path, v) ?;
148+ }
149+ map. end ( )
150+ }
151+
152+ fn strip_pattern_from_template ( path : & str ) -> String {
153+ let mut clean_path = path. to_string ( ) ;
154+ for cap in PATH_TEMPLATE_REGEX . captures_iter ( path) {
155+ let name_only = cap[ 1 ]
156+ . split_once ( ':' )
157+ . map ( |t| t. 0 . to_string ( ) )
158+ . unwrap_or_else ( || cap[ 1 ] . to_string ( ) ) ;
159+ if cap[ 1 ] != name_only {
160+ clean_path = clean_path. replace (
161+ format ! ( "{{{}}}" , & cap[ 1 ] ) . as_str ( ) ,
162+ format ! ( "{{{}}}" , name_only) . as_str ( ) ,
163+ ) ;
164+ }
165+ }
166+ clean_path
167+ }
168+
138169/// OpenAPI v2 (swagger) spec generic over parameter and schema.
139170///
140171/// <https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#swagger-object>
@@ -143,6 +174,7 @@ pub struct Api<P, R, S> {
143174 pub swagger : Version ,
144175 #[ serde( default = "BTreeMap::new" ) ]
145176 pub definitions : BTreeMap < String , S > ,
177+ #[ serde( serialize_with = "strip_templates_from_paths" ) ]
146178 pub paths : BTreeMap < String , PathItem < P , R > > ,
147179 #[ serde( skip_serializing_if = "Option::is_none" ) ]
148180 pub host : Option < String > ,
@@ -706,7 +738,12 @@ impl<S> Operation<Parameter<S>, Response<S>> {
706738 . rev ( )
707739 {
708740 if let Some ( n) = names. pop ( ) {
709- p. name = n. split_once ( ':' ) . map ( |t| t. 0 . to_string ( ) ) . unwrap_or ( n) ;
741+ if let Some ( ( name, pattern) ) = n. split_once ( ':' ) {
742+ p. name = name. to_string ( ) ;
743+ p. pattern = Some ( pattern. to_string ( ) ) ;
744+ } else {
745+ p. name = n;
746+ }
710747 } else {
711748 break ;
712749 }
0 commit comments