From 19c6f4918e3b7d89cacc4212e27a789db0521ec9 Mon Sep 17 00:00:00 2001 From: Carmine DiMascio Date: Fri, 27 Nov 2020 21:25:24 -0500 Subject: [PATCH] fix: parameter style handling #473 (#474) --- src/middlewares/parsers/util.ts | 34 ++++++++++++++- test/query.serialization.ts | 46 ++++++++++++++++++++ test/resources/query.serialization.yaml | 58 +++++++++++++++++++++++++ 3 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 test/query.serialization.ts create mode 100644 test/resources/query.serialization.yaml diff --git a/src/middlewares/parsers/util.ts b/src/middlewares/parsers/util.ts index e3864aca..f7031d93 100644 --- a/src/middlewares/parsers/util.ts +++ b/src/middlewares/parsers/util.ts @@ -31,7 +31,7 @@ export function normalizeParameter( } else if (parameter?.schema?.['$ref']) { schema = dereferenceSchema(ajv, parameter.schema['$ref']); } else { - schema = parameter.schema + schema = parameter.schema; } if (!schema && parameter.content) { const contentType = Object.keys(parameter.content)[0]; @@ -41,11 +41,43 @@ export function normalizeParameter( schema = parameter; } + applyParameterStyle(parameter); + applyParameterExplode(parameter); + const name = parameter.in === 'header' ? parameter.name.toLowerCase() : parameter.name; + return { name, schema }; } +function applyParameterStyle(param: OpenAPIV3.ParameterObject) { + if (!param.style) { + if (param.in === 'path') { + param.style = 'simple'; + } else if (param.in === 'query') { + param.style = 'form'; + } else if (param.style === 'header') { + param.style = 'simple'; + } else if (param.style === 'cookie') { + param.style = 'form'; + } + } +} + +function applyParameterExplode(param: OpenAPIV3.ParameterObject) { + if (param.explode == null) { + if (param.in === 'path') { + param.explode = false; + } else if (param.in === 'query') { + param.explode = true; + } else if (param.style === 'header') { + param.explode = false; + } else if (param.style === 'cookie') { + param.explode = true; + } + } +} + export function dereferenceSchema(ajv: Ajv, ref: string) { // TODO cache schemas - so that we don't recurse every time const derefSchema = ajv.getSchema(ref); diff --git a/test/query.serialization.ts b/test/query.serialization.ts new file mode 100644 index 00000000..78435907 --- /dev/null +++ b/test/query.serialization.ts @@ -0,0 +1,46 @@ +import * as path from 'path'; +import * as express from 'express'; +import { expect } from 'chai'; +import * as request from 'supertest'; +import { createApp } from './common/app'; +import * as packageJson from '../package.json'; +import { log } from 'console'; + +describe.only('styles', () => { + let app = null; + before(async () => { + const apiSpec = path.join('test', 'resources', 'query.serialization.yaml'); + app = await createApp({ apiSpec }, 3005, (app) => + app.use( + `/`, + express + .Router() + .get('/api/q_form_explode', (req, res) => res.json({ query: req.query })) + .get('/api/q_form_nexplode', (req, res) => res.json({ query: req.query })), + ), + ); + }); + + after(async () => { + app.server.close(); + }); + + it('should handle querey param (default) style=form, explode=true', async () => + request(app) + .get('/api/q_form_explode?state=on&state=off') + .expect(200) + .then((r) => { + expect(r.body.query.state).is.an('array').of.length(2); + })); + + it.only('should handle query param with style=form, explode=false', async () => + request(app) + .get('/api/q_form_nexplode') + .query({ + state: 'on,off', + }) + .expect(200) + .then((r) => { + expect(r.body.query.state).is.an('array').of.length(2); + })); +}); diff --git a/test/resources/query.serialization.yaml b/test/resources/query.serialization.yaml new file mode 100644 index 00000000..5ffb5d24 --- /dev/null +++ b/test/resources/query.serialization.yaml @@ -0,0 +1,58 @@ +openapi: '3.0.3' +info: + title: Dummy + version: '0.1.0' + +paths: + /api/q_form_explode: + get: + parameters: + - description: Description + schema: + title: State + type: array + items: + $ref: '#/components/schemas/Foo' + description: A description + name: state + in: query + responses: + 200: + description: OK + content: + 'application/json; charset=utf-8': + schema: + type: object + + /api/q_form_nexplode: + get: + parameters: + - description: Description + required: false + explode: false + schema: + title: State + type: array + items: + $ref: '#/components/schemas/Foo' + description: A description + name: state + in: query + responses: + 200: + description: OK + content: + 'application/json; charset=utf-8': + schema: + type: object + + +components: + schemas: + Foo: + type: string + enum: + - on + - off + + \ No newline at end of file