Skip to content

Commit ba42f5d

Browse files
authored
improvement: bypass style/explode processing for Parameter.content values (#1469)
* improvement: add newline remover for Header values * bypass style/explode processing for `Parameter.content` values * use named exports * Update main.js
1 parent b9189be commit ba42f5d

File tree

5 files changed

+139
-14
lines changed

5 files changed

+139
-14
lines changed

src/execute/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import stockHttp, {mergeInQueryOrForm} from '../http'
99
import createError from '../specmap/lib/create-error'
1010

1111
import SWAGGER2_PARAMETER_BUILDERS from './swagger2/parameter-builders'
12-
import OAS3_PARAMETER_BUILDERS from './oas3/parameter-builders'
12+
import * as OAS3_PARAMETER_BUILDERS from './oas3/parameter-builders'
1313
import oas3BuildRequest from './oas3/build-request'
1414
import swagger2BuildRequest from './swagger2/build-request'
1515
import {
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/*
2+
Serializer that serializes according to a media type instead of OpenAPI's
3+
`style` + `explode` constructs.
4+
*/
5+
6+
export default function serialize(value, mediaType) {
7+
if (mediaType.includes('application/json')) {
8+
if (typeof value === 'string') {
9+
// Assume the user has a JSON string
10+
return value
11+
}
12+
return JSON.stringify(value)
13+
}
14+
15+
return value.toString()
16+
}

src/execute/oas3/parameter-builders.js

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
1-
import stylize from './style-serializer'
1+
import stylize, {encodeDisallowedCharacters} from './style-serializer'
2+
import serialize from './content-serializer'
23

3-
export default {
4-
path,
5-
query,
6-
header,
7-
cookie
8-
}
4+
export function path({req, value, parameter}) {
5+
const {name, style, explode, content} = parameter
6+
7+
if (content) {
8+
const effectiveMediaType = Object.keys(content)[0]
9+
10+
req.url = req.url.split(`{${name}}`).join(
11+
encodeDisallowedCharacters(
12+
serialize(value, effectiveMediaType),
13+
{escape: true}
14+
)
15+
)
16+
return
17+
}
918

10-
function path({req, value, parameter}) {
11-
const {name, style, explode} = parameter
1219
const styledValue = stylize({
1320
key: parameter.name,
1421
value,
@@ -20,9 +27,16 @@ function path({req, value, parameter}) {
2027
req.url = req.url.split(`{${name}}`).join(styledValue)
2128
}
2229

23-
function query({req, value, parameter}) {
30+
export function query({req, value, parameter}) {
2431
req.query = req.query || {}
2532

33+
if (parameter.content) {
34+
const effectiveMediaType = Object.keys(parameter.content)[0]
35+
36+
req.query[parameter.name] = serialize(value, effectiveMediaType)
37+
return
38+
}
39+
2640
if (value === false) {
2741
value = 'false'
2842
}
@@ -98,13 +112,20 @@ const PARAMETER_HEADER_BLACKLIST = [
98112
'content-type'
99113
]
100114

101-
function header({req, parameter, value}) {
115+
export function header({req, parameter, value}) {
102116
req.headers = req.headers || {}
103117

104118
if (PARAMETER_HEADER_BLACKLIST.indexOf(parameter.name.toLowerCase()) > -1) {
105119
return
106120
}
107121

122+
if (parameter.content) {
123+
const effectiveMediaType = Object.keys(parameter.content)[0]
124+
125+
req.headers[parameter.name] = serialize(value, effectiveMediaType)
126+
return
127+
}
128+
108129
if (typeof value !== 'undefined') {
109130
req.headers[parameter.name] = stylize({
110131
key: parameter.name,
@@ -116,10 +137,17 @@ function header({req, parameter, value}) {
116137
}
117138
}
118139

119-
function cookie({req, parameter, value}) {
140+
export function cookie({req, parameter, value}) {
120141
req.headers = req.headers || {}
121142
const type = typeof value
122143

144+
if (parameter.content) {
145+
const effectiveMediaType = Object.keys(parameter.content)[0]
146+
147+
req.headers.Cookie = `${parameter.name}=${serialize(value, effectiveMediaType)}`
148+
return
149+
}
150+
123151
if (type !== 'undefined') {
124152
const prefix = (
125153
type === 'object' &&

src/execute/oas3/style-serializer.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export function encodeDisallowedCharacters(str, {escape} = {}, parse) {
4141
}).join('')
4242
}
4343

44-
export default function (config) {
44+
export default function stylize(config) {
4545
const {value} = config
4646

4747
if (Array.isArray(value)) {

test/oas3/execute/main.js

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import xmock from 'xmock'
22
import path from 'path'
33
import fs from 'fs'
44
import jsYaml from 'js-yaml'
5+
import {escape} from 'querystring'
56

67
import {execute, buildRequest, baseUrl, applySecurities, self as stubs} from '../../../src/execute'
78

@@ -565,6 +566,86 @@ describe('buildRequest - OpenAPI Specification 3.0', function () {
565566
})
566567
})
567568
})
569+
570+
describe('`content` parameters', function () {
571+
it('should serialize JSON values provided as objects', function () {
572+
const req = buildRequest({
573+
spec: {
574+
openapi: '3.0.0',
575+
paths: {
576+
'/{pathPartial}': {
577+
post: {
578+
operationId: 'myOp',
579+
parameters: [
580+
{
581+
name: 'query',
582+
in: 'query',
583+
content: {
584+
'application/json': {
585+
schema: {
586+
type: 'object'
587+
}
588+
}
589+
}
590+
},
591+
{
592+
name: 'FooHeader',
593+
in: 'header',
594+
content: {
595+
'application/json': {
596+
schema: {
597+
type: 'object'
598+
}
599+
}
600+
}
601+
},
602+
{
603+
name: 'pathPartial',
604+
in: 'path',
605+
content: {
606+
'application/json': {
607+
schema: {
608+
type: 'object'
609+
}
610+
}
611+
}
612+
},
613+
{
614+
name: 'myCookie',
615+
in: 'cookie',
616+
content: {
617+
'application/json': {
618+
schema: {
619+
type: 'object'
620+
}
621+
}
622+
}
623+
},
624+
]
625+
}
626+
}
627+
}
628+
},
629+
operationId: 'myOp',
630+
parameters: {
631+
query: {a: 1, b: '2'},
632+
FooHeader: {foo: 'bar'},
633+
pathPartial: {baz: 'qux'},
634+
myCookie: {flavor: 'chocolate chip'}
635+
}
636+
})
637+
638+
expect(req).toEqual({
639+
method: 'POST',
640+
url: `/${escape('{"baz":"qux"}')}?query=${escape('{"a":1,"b":"2"}')}`,
641+
credentials: 'same-origin',
642+
headers: {
643+
FooHeader: '{"foo":"bar"}',
644+
Cookie: 'myCookie={"flavor":"chocolate chip"}'
645+
}
646+
})
647+
})
648+
})
568649
describe('baseUrl', function () {
569650
it('should consider contextUrls correctly with relative server paths', function () {
570651
const spec = {

0 commit comments

Comments
 (0)