@@ -5,7 +5,7 @@ import isArray from 'lodash/isArray'
55import btoa from 'btoa'
66import url from 'url'
77import http , { mergeInQueryOrForm } from './http'
8- import { getOperationRaw , idFromPathMethod , legacyIdFromPathMethod } from './helpers'
8+ import { getOperationRaw , idFromPathMethod , legacyIdFromPathMethod , isOAS3 } from './helpers'
99import createError from './specmap/lib/create-error'
1010
1111const arrayOrEmpty = ( ar ) => {
@@ -25,8 +25,7 @@ export const self = {
2525// These functions will update the request.
2626// They'll be given {req, value, paramter, spec, operation}.
2727
28- // TODO: OAS3: add builder for requestBody
29- // QUESTION: OAS3: how do we decide which media type to use from a requestBody?
28+
3029export const PARAMETER_BUILDERS = {
3130 body : bodyBuilder ,
3231 header : headerBuilder ,
@@ -69,13 +68,16 @@ export function execute({
6968export function buildRequest ( {
7069 spec, operationId, parameters, securities, requestContentType,
7170 responseContentType, parameterBuilders, scheme,
72- requestInterceptor, responseInterceptor, contextUrl, userFetch
71+ requestInterceptor, responseInterceptor, contextUrl, userFetch,
72+ requestBody, server, serverVariables
7373} ) {
74+ const specIsOAS3 = isOAS3 ( spec )
75+
7476 parameterBuilders = parameterBuilders || PARAMETER_BUILDERS
7577
7678 // Base Template
7779 let req = {
78- url : baseUrl ( { spec, scheme, contextUrl} ) ,
80+ url : baseUrl ( { spec, scheme, contextUrl, server , serverVariables } ) ,
7981 credentials : 'same-origin' ,
8082 headers : {
8183 // This breaks CORSs... removing this line... probably breaks oAuth. Need to address that
@@ -141,30 +143,54 @@ export function buildRequest({
141143 }
142144
143145 if ( builder ) {
144- builder ( { req, parameter, value, operation, spec} )
146+ builder ( { req, parameter, value, operation, spec, specIsOAS3 } )
145147 }
146148 } )
147149
150+ // for OAS3: add requestBody to request
151+ if ( specIsOAS3 && requestBody ) {
152+ if ( requestContentType ) {
153+ const requestBodyDef = operation . requestBody
154+ const requestBodyMediaTypes = Object . keys ( requestBodyDef . content || { } )
155+ if ( requestBodyMediaTypes . indexOf ( requestContentType ) > - 1 ) {
156+ // only attach body if the requestBody has a definition for the
157+ // contentType that has been explicitly set
158+ req . body = requestBody
159+ }
160+ }
161+ else {
162+ req . body = requestBody
163+ }
164+ }
165+
148166 // Add securities, which are applicable
149167 // REVIEW: OAS3: what changed in securities?
150168 req = applySecurities ( { request : req , securities, operation, spec} )
151169
152170 if ( req . body || req . form ) {
153171 if ( requestContentType ) {
154- req . headers [ 'content-type ' ] = requestContentType
172+ req . headers [ 'Content-Type ' ] = requestContentType
155173 }
174+ else if ( specIsOAS3 ) {
175+ const requestBodyDef = operation . requestBody
176+ const requestBodyMediaTypes = Object . keys ( requestBodyDef . content || { } )
177+ const firstMediaType = requestBodyMediaTypes [ 0 ]
178+ if ( firstMediaType ) {
179+ req . headers [ 'Content-Type' ] = firstMediaType
180+ }
181+ }
182+ // all following conditionals are Swagger2 only
156183 else if ( Array . isArray ( operation . consumes ) ) {
157- req . headers [ 'content-type ' ] = operation . consumes [ 0 ]
184+ req . headers [ 'Content-Type ' ] = operation . consumes [ 0 ]
158185 }
159186 else if ( Array . isArray ( spec . consumes ) ) {
160- req . headers [ 'content-type ' ] = spec . consumes [ 0 ]
187+ req . headers [ 'Content-Type ' ] = spec . consumes [ 0 ]
161188 }
162- else if ( operation . parameters . filter ( p => p . type === 'file' ) . length ) {
163- req . headers [ 'content-type ' ] = 'multipart/form-data'
189+ else if ( operation . parameters && operation . parameters . filter ( p => p . type === 'file' ) . length ) {
190+ req . headers [ 'Content-Type ' ] = 'multipart/form-data'
164191 }
165- else if ( operation . parameters . filter ( p => p . in === 'formData' ) . length ) {
166- // TODO: OAS3: disable this
167- req . headers [ 'content-type' ] = 'application/x-www-form-urlencoded'
192+ else if ( operation . parameters && operation . parameters . filter ( p => p . in === 'formData' ) . length ) {
193+ req . headers [ 'Content-Type' ] = 'application/x-www-form-urlencoded'
168194 }
169195 }
170196
@@ -176,8 +202,10 @@ export function buildRequest({
176202}
177203
178204// Add the body to the request
179- export function bodyBuilder ( { req, value} ) {
180- // REVIEW: OAS3: wtf does this do
205+ export function bodyBuilder ( { req, value, specIsOAS3} ) {
206+ if ( specIsOAS3 ) {
207+ return
208+ }
181209 req . body = value
182210}
183211
@@ -237,8 +265,68 @@ export function queryBuilder({req, value, parameter}) {
237265
238266const stripNonAlpha = str => ( str ? str . replace ( / \W / g, '' ) : null )
239267
268+ export function baseUrl ( obj ) {
269+ const specIsOAS3 = isOAS3 ( obj . spec )
270+
271+ return specIsOAS3 ? oas3BaseUrl ( obj ) : swagger2BaseUrl ( obj )
272+ }
273+
274+ function oas3BaseUrl ( { spec, server, serverVariables = { } } ) {
275+ const servers = spec . servers
276+
277+ let selectedServerUrl = ''
278+ let selectedServerObj = null
279+
280+ if ( ! servers || ! Array . isArray ( servers ) ) {
281+ return '/'
282+ }
283+
284+ if ( server ) {
285+ const serverUrls = servers . map ( srv => srv . url )
286+
287+ if ( serverUrls . indexOf ( server ) > - 1 ) {
288+ selectedServerUrl = server
289+ selectedServerObj = servers [ serverUrls . indexOf ( server ) ]
290+ }
291+ }
292+
293+ if ( ! selectedServerUrl ) {
294+ // default to the first server if we don't have one by now
295+ selectedServerUrl = servers [ 0 ] . url
296+ selectedServerObj = servers [ 0 ]
297+ }
298+
299+ if ( selectedServerUrl . indexOf ( '{' ) > - 1 ) {
300+ // do variable substitution
301+ const varNames = getVariableTemplateNames ( selectedServerUrl )
302+ varNames . forEach ( ( vari ) => {
303+ if ( selectedServerObj . variables && selectedServerObj . variables [ vari ] ) {
304+ // variable is defined in server
305+ const variableDefinition = selectedServerObj . variables [ vari ]
306+ const variableValue = serverVariables [ vari ] || variableDefinition . default
307+
308+ const re = new RegExp ( `\{${ vari } \}` , "g" )
309+ selectedServerUrl = selectedServerUrl . replace ( re , variableValue )
310+ }
311+ } )
312+ }
313+
314+ return selectedServerUrl
315+ }
316+
317+ function getVariableTemplateNames ( str ) {
318+ const results = [ ]
319+ const re = / { ( [ ^ } ] + ) } / g
320+ let text
321+
322+ while ( text = re . exec ( str ) ) {
323+ results . push ( text [ 1 ] )
324+ }
325+ return results
326+ }
327+
240328// Compose the baseUrl ( scheme + host + basePath )
241- export function baseUrl ( { spec, scheme, contextUrl = '' } ) {
329+ function swagger2BaseUrl ( { spec, scheme, contextUrl = '' } ) {
242330 // TODO: OAS3: support `servers` instead of host+basePath
243331 // QUESTION: OAS3: how are we handling `servers`?
244332 // QUESTION: OAS3: are we still doing assumed URL components the same way?
0 commit comments