diff --git a/packages/openapi-2-kong/src/declarative-config/fixtures/nullable-true.expected.json b/packages/openapi-2-kong/src/declarative-config/fixtures/nullable-true.expected.json new file mode 100644 index 0000000000..ef1f7b9dc4 --- /dev/null +++ b/packages/openapi-2-kong/src/declarative-config/fixtures/nullable-true.expected.json @@ -0,0 +1,65 @@ +{ + "_format_version": "1.1", + "services": [ + { + "name": "cktest_cards_api", + "protocol": "https", + "host": "alb-dev01.openapi-test.merlin", + "port": 443, + "path": "/", + "plugins": [], + "routes": [ + { + "tags": [ + "OAS3_import", + "OAS3file_nullable-true.yaml" + ], + "name": "cktest_cards_api-get_api1", + "methods": [ + "GET" + ], + "paths": [ + "/cktest/cktest_cards/api1$" + ], + "strip_path": false + }, + { + "tags": [ + "OAS3_import", + "OAS3file_nullable-true.yaml" + ], + "name": "cktest_cards_api-post_api1", + "methods": [ + "POST" + ], + "paths": [ + "/cktest/cktest_cards/api1$" + ], + "strip_path": false, + "plugins": [ + { + "name": "request-validator", + "config": { + "version": "draft4", + "body_schema": "{\"type\":\"object\",\"title\":\"request-body-nullable\",\"description\":\"This object is sent in post application request.\",\"required\":[\"redirectUri\"],\"properties\":{\"redirectUri\":{\"type\":[\"string\",\"null\"],\"nullable\":true}}}", + "allowed_content_types": [ + "application/json" + ], + "verbose_response": true + }, + "tags": [ + "OAS3_import", + "OAS3file_nullable-true.yaml" + ], + "enabled": true + } + ] + } + ], + "tags": [ + "OAS3_import", + "OAS3file_nullable-true.yaml" + ] + } + ] +} diff --git a/packages/openapi-2-kong/src/declarative-config/fixtures/nullable-true.yaml b/packages/openapi-2-kong/src/declarative-config/fixtures/nullable-true.yaml new file mode 100644 index 0000000000..9df0894d2c --- /dev/null +++ b/packages/openapi-2-kong/src/declarative-config/fixtures/nullable-true.yaml @@ -0,0 +1,59 @@ +openapi: '3.0.2' +x-kong-name: cktest_cards_api +info: + title: FTI-3278 Test + version: '1.0' + description: A sample API specification for FTI-3278 + contact: + email: support@insomnia.rest + +servers: +- url: https://alb-dev01.openapi-test.merlin/ + +tags: + - name: oauth2-credential-flow + +paths: + /cktest/cktest_cards/api1: + get: + description: test oauth2 + operationId: get_api1 + tags: + - oauth2-credential-flow + + responses: + '200': + description: OK + + post: + description: test oauth2 + operationId: post_api1 + x-kong-plugin-request-validator: + enabled: true + config: + verbose_response: true + requestBody: + content: + application/json: + schema: + "$ref": "#/components/schemas/request-body-nullable" + responses: + '200': + description: OK + + tags: + - oauth2-credential-flow + + +components: + schemas: + request-body-nullable: + type: object + title: request-body-nullable + description: This object is sent in post application request. + required: + - redirectUri + properties: + redirectUri: + type: string + nullable: true diff --git a/packages/openapi-2-kong/src/declarative-config/plugins.test.ts b/packages/openapi-2-kong/src/declarative-config/plugins.test.ts index adf7b9be4e..5155e7e460 100644 --- a/packages/openapi-2-kong/src/declarative-config/plugins.test.ts +++ b/packages/openapi-2-kong/src/declarative-config/plugins.test.ts @@ -1,7 +1,7 @@ import { ParameterSchema, RequestTerminationPlugin, RequestValidatorPlugin, xKongPluginKeyAuth, xKongPluginRequestTermination, xKongPluginRequestValidator } from '../types/kong'; import { OA3Operation, OA3Parameter } from '../types/openapi3'; import { getSpec, pluginDummy, tags, UserDCPlugin } from './jest/test-helpers'; -import { ALLOW_ALL_SCHEMA, generateGlobalPlugins, generateRequestValidatorPlugin } from './plugins'; +import { ALLOW_ALL_SCHEMA, generateBodyOptions, generateGlobalPlugins, generateRequestValidatorPlugin } from './plugins'; describe('plugins', () => { describe('generateGlobalPlugins()', () => { @@ -393,5 +393,63 @@ describe('plugins', () => { }); }); }); + describe('body_schema generateBodyOptions FTI-3278', () => { + it('should keep to properties[].type unchanged nullable is not set', () => { + const generated = generateBodyOptions({ + requestBody: { + content: { + 'application/json': { + schema: { + properties: { + redirectUri: { + type: 'string', + }, + }, + }, + }, + }, + }, + }); + expect(generated.bodySchema).toStrictEqual('{\"properties\":{\"redirectUri\":{\"type\":\"string\"}}}'); + }); + it('should keep to properties[].type unchanged nullable is false', () => { + const generated = generateBodyOptions({ + requestBody: { + content: { + 'application/json': { + schema: { + properties: { + redirectUri: { + type: 'string', + nullable: false, + }, + }, + }, + }, + }, + }, + }); + expect(generated.bodySchema).toStrictEqual('{\"properties\":{\"redirectUri\":{\"type\":\"string\",\"nullable\":false}}}'); + }); + it('should append null to properties[].type if nullable is true', () => { + const generated = generateBodyOptions({ + requestBody: { + content: { + 'application/json': { + schema: { + properties: { + redirectUri: { + type: 'string', + nullable: true, + }, + }, + }, + }, + }, + }, + }); + expect(generated.bodySchema).toStrictEqual('{\"properties\":{\"redirectUri\":{\"type\":[\"string\",\"null\"],\"nullable\":true}}}'); + }); + }); }); }); diff --git a/packages/openapi-2-kong/src/declarative-config/plugins.ts b/packages/openapi-2-kong/src/declarative-config/plugins.ts index 3c34193800..2042a1a004 100644 --- a/packages/openapi-2-kong/src/declarative-config/plugins.ts +++ b/packages/openapi-2-kong/src/declarative-config/plugins.ts @@ -85,7 +85,7 @@ const generateParameterSchema = (operation?: OA3Operation) => { return parameterSchemas; }; -function generateBodyOptions(operation?: OA3Operation) { +export function generateBodyOptions(operation?: OA3Operation) { let bodySchema; let allowedContentTypes; const bodyContent = (operation?.requestBody as OA3RequestBody)?.content; @@ -96,6 +96,13 @@ function generateBodyOptions(operation?: OA3Operation) { if (allowedContentTypes.includes(jsonContentType)) { const item = bodyContent[jsonContentType]; + const schema = item.schema; + for (const key in schema.properties) { + // Append 'null' to property type if nullable true, see FTI-3278 + if (schema.properties[key].nullable === true) { + schema.properties[key].type = [schema.properties[key].type, 'null']; + } + } bodySchema = JSON.stringify(item.schema); } }