@@ -108,29 +108,74 @@ function getDecoderForResponse(status: string, type: string): string {
108108 }
109109}
110110
111- // Get a schema from a request or response body
111+ /** Get the first schema from an OAS3 request or response body
112+ */
112113function getSchemaFromBody (
113- item : any , // OpenAPIV3.RequestBodyObject |
114- preferred_media_type : string | undefined
115- ) : string | undefined {
114+ item : any ,
115+ ) : OpenAPIV3 . BaseSchemaObject | string | undefined {
116116
117117 try {
118118 const content = item . content ;
119- if ( preferred_media_type in content ) {
120- return item . content [ preferred_media_type ] . schema . $ref ;
119+ const media_types = Object . keys ( content ) ;
120+
121+ if ( media_types . length == 0 ) {
122+ console . warn ( `Missing media-type in ${ JSON . stringify ( item ) } ` ) ;
123+ return undefined ;
121124 }
122- // FIXME if there's more than one property then console.warn
123- const first_content = content [ Object . keys ( content ) [ 0 ] ]
124- if ( $ref in first_content . schema ) {
125- return first_content . schema . $ref ;
125+
126+ if ( media_types . length > 1 ) {
127+ console . warn ( `Multiple media-types in ${ JSON . stringify ( item ) } ` ) ;
128+ return undefined ;
126129 }
127- return first_content . schema ;
130+
131+ const media_type = content [ media_types [ 0 ] ] ;
132+ return "$ref" in media_type . schema ? media_type . schema . $ref : media_type . schema ;
133+
128134 } catch {
129- console . warn ( `f ${ media_type } ${ JSON . stringify ( item ) } ` ) ;
135+ console . warn ( `Cannot get schema from body: ${ JSON . stringify ( item ) } ` ) ;
130136 return undefined ;
131137 }
132138}
133139
140+ /**
141+ * Convert an OAS3 Object to typescript.
142+ * This function supports only one level of schema properties:
143+ * for nested schemas define a schema object.
144+ */
145+ function specObjectToTs (
146+ item : any
147+ ) : string | undefined {
148+
149+ if ( ( item . properties || item . type ) == false ) {
150+ return undefined ;
151+ }
152+
153+ if ( item . properties ) {
154+ item = item . properties ;
155+
156+ // File upload implementation used in io-utils.
157+ const file_upload_schema = { "file" : { "type" : "string" , "format" : "binary" } }
158+ if ( JSON . stringify ( item ) == JSON . stringify ( file_upload_schema ) ) {
159+ console . warn ( `Found file upload pattern` ) ;
160+ return specTypeToTs ( "file" ) ;
161+ }
162+
163+ for ( let p in item ) {
164+ item [ p ] = item [ p ] . type ;
165+ }
166+ return JSON . stringify ( item ) . replace ( / " / g, " " ) ;
167+ }
168+
169+ if ( item . type ) {
170+ // Support for generic OAS3 binary file upload
171+ // see https://swagger.io/docs/specification/describing-request-body/file-upload/
172+ if ( item . type == "string" && item . format == "binary" ) {
173+ return specTypeToTs ( "file" ) ;
174+ }
175+ return specTypeToTs ( item . type ) ;
176+ }
177+ }
178+
134179export function renderOperation (
135180 method : string ,
136181 operationId : string ,
@@ -152,39 +197,46 @@ export function renderOperation(
152197 const importedTypes = new Set < string > ( ) ;
153198
154199 // Eventually process requestBody
155- if ( ( operation as any ) . requestBody !== undefined ) {
156- const item = ( operation as any ) . requestBody ;
157- const application_json = "application/json"
158-
159- console . warn ( `requestBody ${ JSON . stringify ( item ) } ` ) ;
160- const typeRef = getSchemaFromBody ( item , application_json ) ;
161-
162- const parsedRef = typeRef ? typeFromRef ( typeRef ) : undefined ;
163- console . warn ( `requestBody.typeRef ${ JSON . stringify ( { '1' : parsedRef , '2' : typeRef } ) } ` ) ;
164- if ( parsedRef ) {
165- const refType = parsedRef . e1 ; // "definition"
166-
167- // TODO implement if required...
168- const isParamRequired = false ;
200+ if ( isV3OperationWithBody ( operation ) && operation . requestBody !== undefined ) {
201+ const item = operation . requestBody ;
202+ const typeRefOrSchema = getSchemaFromBody ( item ) ;
203+ const isParamRequired = ( item as OpenAPIV3 . RequestBodyObject ) . required === true ;
204+ console . warn ( `Required: ${ isParamRequired } ` ) ;
205+ if ( typeRefOrSchema ) {
206+ const inlineRequestBody = specObjectToTs ( typeRefOrSchema ) ;
207+
208+ // inline parameter definition
209+ if ( inlineRequestBody ) {
210+ const schema = ( typeRefOrSchema as OpenAPIV3 . BaseSchemaObject ) ;
211+ const parameterName = schema . properties
212+ ? schema . properties . file
213+ ? "file"
214+ : "body"
215+ : "body" ;
216+ params [ `${ parameterName } ${ isParamRequired ? "" : "?" } ` ] = inlineRequestBody ;
217+ } else { // referenced parameter
218+ const schema = ( typeRefOrSchema as string ) ;
219+ const parsedRef = typeRefOrSchema ? typeFromRef ( schema ) : undefined ;
220+ console . debug ( `requestBody.typeRef ${ JSON . stringify ( { '1' : parsedRef , '2' : typeRefOrSchema } ) } ` ) ;
221+
222+ if ( parsedRef ) {
223+ const refType = parsedRef . e1 ;
169224 const paramName = `${ uncapitalize ( parsedRef . e2 ) } ${
170225 isParamRequired ? "" : "?"
171226 } `;
172227
173- console . warn ( `requestBody.paramName ${ JSON . stringify ( paramName ) } ` ) ;
174-
228+ console . debug ( `requestBody.paramName ${ JSON . stringify ( paramName ) } ` ) ;
175229 params [ paramName ] = parsedRef . e2 ;
176230 if ( refType === "definition" ) {
177231 importedTypes . add ( parsedRef . e2 ) ;
178232 }
179-
180-
181- } else {
182- console . warn ( `Cannot extract type from ref [${ typeRef } ]` ) ;
233+ }
183234 }
184-
235+ } else {
236+ console . warn ( `Cannot extract type from ref [${ typeRefOrSchema } ]` ) ;
237+ }
185238 }
186239
187-
188240 // Process ordinary parameters
189241 if ( operation . parameters !== undefined ) {
190242 const parameters = operation . parameters as Array <
@@ -453,6 +505,12 @@ export function isOpenAPIV3(
453505 return specs . hasOwnProperty ( "openapi" ) ;
454506}
455507
508+ export function isV3OperationWithBody (
509+ item : any
510+ ) : item is OpenAPIV3 . OperationObject {
511+ return item . hasOwnProperty ( "requestBody" ) ;
512+ }
513+
456514export async function generateApi (
457515 env : nunjucks . Environment ,
458516 specFilePath : string ,
0 commit comments