diff --git a/src/http.js b/src/http.js index fd314ca8f..97e69ea3e 100644 --- a/src/http.js +++ b/src/http.js @@ -3,6 +3,7 @@ import qs from 'qs' import jsYaml from 'js-yaml' import isString from 'lodash/isString' import isFunction from 'lodash/isFunction' +import isNil from 'lodash/isNil' import FormData from './internal/form-data-monkey-patch' // For testing @@ -182,9 +183,16 @@ function formatValue(input, skipEncoding) { } let encodeFn = encodeURIComponent + // skipEncoding is an option to skip using the encodeURIComponent + // and allow reassignment to a different "encoding" function + // we should only use encodeURIComponent for known url strings if (skipEncoding) { - if (isString(value)) encodeFn = str => str - else encodeFn = obj => JSON.stringify(obj) + if (isString(value) || Array.isArray(value)) { + encodeFn = str => str + } + else { + encodeFn = obj => JSON.stringify(obj) + } } if (typeof value === 'object' && !Array.isArray(value)) { @@ -214,7 +222,7 @@ function buildFormData(reqForm) { * @return {FormData} - new FormData instance */ return Object.entries(reqForm).reduce((formData, [name, input]) => { - if (!input.collectionFormat && !input.isOAS3formatArray) { + if ((isNil(input.collectionFormat) || input.collectionFormat !== 'multi') && !input.isOAS3formatArray) { formData.append(name, formatValue(input, true)) } else { diff --git a/test/data/sample-multipart-oas2.js b/test/data/sample-multipart-oas2.js index 88eca377b..0ac125733 100644 --- a/test/data/sample-multipart-oas2.js +++ b/test/data/sample-multipart-oas2.js @@ -56,12 +56,62 @@ export default { { in: 'formData', name: 'email[]', - description: 'The list of emails.', + description: 'The list of emails as multi.', type: 'array', collectionFormat: 'multi', items: { type: 'string' } + }, + { + in: 'formData', + name: 'none[]', + description: 'The list of emails as none.', + type: 'array', + collectionFormat: 'none', + items: { + type: 'string' + } + }, + { + in: 'formData', + name: 'csv[]', + description: 'The list of emails as csv.', + type: 'array', + collectionFormat: 'csv', + items: { + type: 'string' + } + }, + { + in: 'formData', + name: 'tsv[]', + description: 'The list of emails as tsv.', + type: 'array', + collectionFormat: 'tsv', + items: { + type: 'string' + } + }, + { + in: 'formData', + name: 'ssv[]', + description: 'The list of emails as ssv.', + type: 'array', + collectionFormat: 'ssv', + items: { + type: 'string' + } + }, + { + in: 'formData', + name: 'pipes[]', + description: 'The list of emails as pipes.', + type: 'array', + collectionFormat: 'pipes', + items: { + type: 'string' + } } ], responses: { diff --git a/test/http-multipart.js b/test/http-multipart.js index d878d2be0..658fa6d0b 100644 --- a/test/http-multipart.js +++ b/test/http-multipart.js @@ -23,11 +23,16 @@ describe('buildRequest - openapi 2.0', () => { parameters: { 'formData.hhlContent:sort': 'id', 'formData.hhlContent:order': 'desc', - 'formData.email[]': ["person1", "person2"] // eslint-disable-line quotes + 'formData.email[]': ["person1", "person2"], // eslint-disable-line quotes + 'formData.none[]': ['foo', 'bar'], + 'formData.csv[]': ['foo', 'bar'], + 'formData.tsv[]': ['foo', 'bar'], + 'formData.ssv[]': ['foo', 'bar'], + 'formData.pipes[]': ['foo', 'bar'], } }) - test('should return FormData entry list and entry item entries (in order)', () => { + test('should return appropriate response media type', () => { expect(req).toMatchObject({ method: 'POST', url: '/api/v1/land/content/ViewOfAuthOwner', @@ -36,14 +41,50 @@ describe('buildRequest - openapi 2.0', () => { 'Content-Type': 'multipart/form-data' }, }) + }) + + test('should build request body as FormData', () => { const validateFormDataInstance = req.body instanceof FormData expect(validateFormDataInstance).toEqual(true) + }) + + test('should return "collectionFormat: multi" as FormData entry list and entry item entries (in order)', () => { const itemEntries = req.body.getAll('email[]') expect(itemEntries.length).toEqual(2) expect(itemEntries[0]).toEqual('person1') expect(itemEntries[1]).toEqual('person2') }) + test('should return "collectionFormat: none" as single FormData entry in csv format', () => { + const itemEntriesNone = req.body.getAll('none[]') + expect(itemEntriesNone.length).toEqual(1) + expect(itemEntriesNone[0]).toEqual('foo,bar') + }) + + test('should return "collectionFormat: csv" as single FormData entry in csv format', () => { + const itemEntriesCsv = req.body.getAll('csv[]') + expect(itemEntriesCsv.length).toEqual(1) + expect(itemEntriesCsv[0]).toEqual('foo,bar') + }) + + test('should return "collectionFormat: tsv" as single FormData entry in tsv format', () => { + const itemEntriesTsv = req.body.getAll('tsv[]') + expect(itemEntriesTsv.length).toEqual(1) + expect(itemEntriesTsv[0]).toEqual('foo%09bar') + }) + + test('should return "collectionFormat: ssv" as single FormData entry in ssv format', () => { + const itemEntriesSsv = req.body.getAll('ssv[]') + expect(itemEntriesSsv.length).toEqual(1) + expect(itemEntriesSsv[0]).toEqual('foo%20bar') + }) + + test('should return "collectionFormat: pipes" as single FormData entry in pipes format', () => { + const itemEntriesPipes = req.body.getAll('pipes[]') + expect(itemEntriesPipes.length).toEqual(1) + expect(itemEntriesPipes[0]).toEqual('foo|bar') + }) + /** * Dev test only: assumes local server exists for POST * Expect server response format: { message: 'ok', data: returnData } @@ -113,7 +154,7 @@ describe('buildRequest - openapi 3.0', () => { } }) - test('should return FormData entry list and item entries (in order)', () => { + test('should return appropriate response media type', () => { expect(req).toMatchObject({ method: 'POST', url: '/api/v1/land/content/ViewOfAuthOwner', @@ -122,13 +163,20 @@ describe('buildRequest - openapi 3.0', () => { 'Content-Type': 'multipart/form-data' }, }) + }) + + test('should build request body as FormData', () => { const validateFormDataInstance = req.body instanceof FormData expect(validateFormDataInstance).toEqual(true) + }) + + test('should return FormData entry list and item entries (in order)', () => { const itemEntries = req.body.getAll('email[]') expect(itemEntries.length).toEqual(2) expect(itemEntries[0]).toEqual('person1') expect(itemEntries[1]).toEqual('person2') }) + /** * Dev test only: assumes local server exists for POST * Expect server response format: { message: 'ok', data: returnData }