Skip to content

Commit b023192

Browse files
authored
fix: oas2 collectionFormat when not 'multi' (#1550)
* reorganize http-multipart tests * simplify negation in 'buildFormData'
1 parent a7ff21b commit b023192

File tree

3 files changed

+113
-7
lines changed

3 files changed

+113
-7
lines changed

src/http.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import qs from 'qs'
33
import jsYaml from 'js-yaml'
44
import isString from 'lodash/isString'
55
import isFunction from 'lodash/isFunction'
6+
import isNil from 'lodash/isNil'
67
import FormData from './internal/form-data-monkey-patch'
78

89
// For testing
@@ -182,9 +183,16 @@ function formatValue(input, skipEncoding) {
182183
}
183184

184185
let encodeFn = encodeURIComponent
186+
// skipEncoding is an option to skip using the encodeURIComponent
187+
// and allow reassignment to a different "encoding" function
188+
// we should only use encodeURIComponent for known url strings
185189
if (skipEncoding) {
186-
if (isString(value)) encodeFn = str => str
187-
else encodeFn = obj => JSON.stringify(obj)
190+
if (isString(value) || Array.isArray(value)) {
191+
encodeFn = str => str
192+
}
193+
else {
194+
encodeFn = obj => JSON.stringify(obj)
195+
}
188196
}
189197

190198
if (typeof value === 'object' && !Array.isArray(value)) {
@@ -214,7 +222,7 @@ function buildFormData(reqForm) {
214222
* @return {FormData} - new FormData instance
215223
*/
216224
return Object.entries(reqForm).reduce((formData, [name, input]) => {
217-
if (!input.collectionFormat && !input.isOAS3formatArray) {
225+
if ((isNil(input.collectionFormat) || input.collectionFormat !== 'multi') && !input.isOAS3formatArray) {
218226
formData.append(name, formatValue(input, true))
219227
}
220228
else {

test/data/sample-multipart-oas2.js

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,62 @@ export default {
5656
{
5757
in: 'formData',
5858
name: 'email[]',
59-
description: 'The list of emails.',
59+
description: 'The list of emails as multi.',
6060
type: 'array',
6161
collectionFormat: 'multi',
6262
items: {
6363
type: 'string'
6464
}
65+
},
66+
{
67+
in: 'formData',
68+
name: 'none[]',
69+
description: 'The list of emails as none.',
70+
type: 'array',
71+
collectionFormat: 'none',
72+
items: {
73+
type: 'string'
74+
}
75+
},
76+
{
77+
in: 'formData',
78+
name: 'csv[]',
79+
description: 'The list of emails as csv.',
80+
type: 'array',
81+
collectionFormat: 'csv',
82+
items: {
83+
type: 'string'
84+
}
85+
},
86+
{
87+
in: 'formData',
88+
name: 'tsv[]',
89+
description: 'The list of emails as tsv.',
90+
type: 'array',
91+
collectionFormat: 'tsv',
92+
items: {
93+
type: 'string'
94+
}
95+
},
96+
{
97+
in: 'formData',
98+
name: 'ssv[]',
99+
description: 'The list of emails as ssv.',
100+
type: 'array',
101+
collectionFormat: 'ssv',
102+
items: {
103+
type: 'string'
104+
}
105+
},
106+
{
107+
in: 'formData',
108+
name: 'pipes[]',
109+
description: 'The list of emails as pipes.',
110+
type: 'array',
111+
collectionFormat: 'pipes',
112+
items: {
113+
type: 'string'
114+
}
65115
}
66116
],
67117
responses: {

test/http-multipart.js

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,16 @@ describe('buildRequest - openapi 2.0', () => {
2323
parameters: {
2424
'formData.hhlContent:sort': 'id',
2525
'formData.hhlContent:order': 'desc',
26-
'formData.email[]': ["person1", "person2"] // eslint-disable-line quotes
26+
'formData.email[]': ["person1", "person2"], // eslint-disable-line quotes
27+
'formData.none[]': ['foo', 'bar'],
28+
'formData.csv[]': ['foo', 'bar'],
29+
'formData.tsv[]': ['foo', 'bar'],
30+
'formData.ssv[]': ['foo', 'bar'],
31+
'formData.pipes[]': ['foo', 'bar'],
2732
}
2833
})
2934

30-
test('should return FormData entry list and entry item entries (in order)', () => {
35+
test('should return appropriate response media type', () => {
3136
expect(req).toMatchObject({
3237
method: 'POST',
3338
url: '/api/v1/land/content/ViewOfAuthOwner',
@@ -36,14 +41,50 @@ describe('buildRequest - openapi 2.0', () => {
3641
'Content-Type': 'multipart/form-data'
3742
},
3843
})
44+
})
45+
46+
test('should build request body as FormData', () => {
3947
const validateFormDataInstance = req.body instanceof FormData
4048
expect(validateFormDataInstance).toEqual(true)
49+
})
50+
51+
test('should return "collectionFormat: multi" as FormData entry list and entry item entries (in order)', () => {
4152
const itemEntries = req.body.getAll('email[]')
4253
expect(itemEntries.length).toEqual(2)
4354
expect(itemEntries[0]).toEqual('person1')
4455
expect(itemEntries[1]).toEqual('person2')
4556
})
4657

58+
test('should return "collectionFormat: none" as single FormData entry in csv format', () => {
59+
const itemEntriesNone = req.body.getAll('none[]')
60+
expect(itemEntriesNone.length).toEqual(1)
61+
expect(itemEntriesNone[0]).toEqual('foo,bar')
62+
})
63+
64+
test('should return "collectionFormat: csv" as single FormData entry in csv format', () => {
65+
const itemEntriesCsv = req.body.getAll('csv[]')
66+
expect(itemEntriesCsv.length).toEqual(1)
67+
expect(itemEntriesCsv[0]).toEqual('foo,bar')
68+
})
69+
70+
test('should return "collectionFormat: tsv" as single FormData entry in tsv format', () => {
71+
const itemEntriesTsv = req.body.getAll('tsv[]')
72+
expect(itemEntriesTsv.length).toEqual(1)
73+
expect(itemEntriesTsv[0]).toEqual('foo%09bar')
74+
})
75+
76+
test('should return "collectionFormat: ssv" as single FormData entry in ssv format', () => {
77+
const itemEntriesSsv = req.body.getAll('ssv[]')
78+
expect(itemEntriesSsv.length).toEqual(1)
79+
expect(itemEntriesSsv[0]).toEqual('foo%20bar')
80+
})
81+
82+
test('should return "collectionFormat: pipes" as single FormData entry in pipes format', () => {
83+
const itemEntriesPipes = req.body.getAll('pipes[]')
84+
expect(itemEntriesPipes.length).toEqual(1)
85+
expect(itemEntriesPipes[0]).toEqual('foo|bar')
86+
})
87+
4788
/**
4889
* Dev test only: assumes local server exists for POST
4990
* Expect server response format: { message: 'ok', data: returnData }
@@ -113,7 +154,7 @@ describe('buildRequest - openapi 3.0', () => {
113154
}
114155
})
115156

116-
test('should return FormData entry list and item entries (in order)', () => {
157+
test('should return appropriate response media type', () => {
117158
expect(req).toMatchObject({
118159
method: 'POST',
119160
url: '/api/v1/land/content/ViewOfAuthOwner',
@@ -122,13 +163,20 @@ describe('buildRequest - openapi 3.0', () => {
122163
'Content-Type': 'multipart/form-data'
123164
},
124165
})
166+
})
167+
168+
test('should build request body as FormData', () => {
125169
const validateFormDataInstance = req.body instanceof FormData
126170
expect(validateFormDataInstance).toEqual(true)
171+
})
172+
173+
test('should return FormData entry list and item entries (in order)', () => {
127174
const itemEntries = req.body.getAll('email[]')
128175
expect(itemEntries.length).toEqual(2)
129176
expect(itemEntries[0]).toEqual('person1')
130177
expect(itemEntries[1]).toEqual('person2')
131178
})
179+
132180
/**
133181
* Dev test only: assumes local server exists for POST
134182
* Expect server response format: { message: 'ok', data: returnData }

0 commit comments

Comments
 (0)