From 1367380a88e6da91704662d680d66ea8aca587f2 Mon Sep 17 00:00:00 2001 From: Roman Hotsiy Date: Thu, 1 Aug 2019 11:17:50 +0300 Subject: [PATCH] fix: support json serialization for parameter examples fixes #934 --- src/components/Fields/FieldDetails.tsx | 7 ++-- src/services/models/Field.ts | 16 +++++++-- src/utils/__tests__/openapi.test.ts | 49 +++++++++++++++++++++++++- src/utils/openapi.ts | 32 +++++++++++++++-- 4 files changed, 94 insertions(+), 10 deletions(-) diff --git a/src/components/Fields/FieldDetails.tsx b/src/components/Fields/FieldDetails.tsx index 65ce160e..cdfa38b6 100644 --- a/src/components/Fields/FieldDetails.tsx +++ b/src/components/Fields/FieldDetails.tsx @@ -33,11 +33,10 @@ export class FieldDetails extends React.PureComponent { let exampleField: JSX.Element | null = null; - if (showExamples) { + if (showExamples && example !== undefined) { const label = l('example') + ':'; - if (field.in && field.style) { - const serializedValue = - example !== undefined ? serializeParameterValue(field, example) : undefined; + if (field.in && (field.style || field.serializationMime)) { + const serializedValue = serializeParameterValue(field, example); exampleField = ; } else { exampleField = ; diff --git a/src/services/models/Field.ts b/src/services/models/Field.ts index 1e717196..5302a09f 100644 --- a/src/services/models/Field.ts +++ b/src/services/models/Field.ts @@ -44,6 +44,8 @@ export class FieldModel { explode: boolean; style?: OpenAPIParameterStyle; + serializationMime?: string; + constructor( parser: OpenAPIParser, infoOrRef: Referenced & { name?: string; kind?: string }, @@ -55,12 +57,22 @@ export class FieldModel { this.name = infoOrRef.name || info.name; this.in = info.in; this.required = !!info.required; - this.schema = new SchemaModel(parser, info.schema || {}, pointer, options); + + let fieldSchema = info.schema; + let serializationMime = ''; + if (!fieldSchema && info.in && info.content) { + serializationMime = Object.keys(info.content)[0]; + fieldSchema = info.content[serializationMime] && info.content[serializationMime].schema; + } + + this.schema = new SchemaModel(parser, fieldSchema || {}, pointer, options); this.description = info.description === undefined ? this.schema.description || '' : info.description; this.example = info.example || this.schema.example; - if (info.style) { + if (serializationMime) { + this.serializationMime = serializationMime; + } else if (info.style) { this.style = info.style; } else if (this.in) { this.style = getDefaultStyleValue(this.in); diff --git a/src/utils/__tests__/openapi.test.ts b/src/utils/__tests__/openapi.test.ts index b8da1712..54a0bac4 100644 --- a/src/utils/__tests__/openapi.test.ts +++ b/src/utils/__tests__/openapi.test.ts @@ -11,7 +11,7 @@ import { serializeParameterValue, } from '../'; -import { OpenAPIParser } from '../../services'; +import { FieldModel, OpenAPIParser, RedocNormalizedOptions } from '../../services'; import { OpenAPIParameter, OpenAPIParameterLocation, OpenAPIParameterStyle } from '../../types'; import { expandDefaultServerVariables } from '../openapi'; @@ -389,6 +389,7 @@ describe('Utils', () => { explode: boolean; expected: string; } + interface TestValueTypeGroup { value: any; description: string; @@ -565,5 +566,51 @@ describe('Utils', () => { }); }); }); + + describe('advanced serialization', () => { + it('should serialize correctly query parameter with content with application/json', () => { + const parameter: OpenAPIParameter = { + name: 'id', + in: 'query', + content: { + 'application/json': { + schema: { + type: 'string', + }, + }, + }, + }; + + const parser = new OpenAPIParser({ openapi: '3.0' } as any); + const opts = new RedocNormalizedOptions({}); + + const field = new FieldModel(parser, parameter, '', opts); + expect(serializeParameterValue(field, { name: 'test', age: 23 })).toEqual( + 'id={"name":"test","age":23}', + ); + }); + + it('should serialize correctly header parameter with content with application/json', () => { + const parameter: OpenAPIParameter = { + name: 'x-header', + in: 'header', + content: { + 'application/json': { + schema: { + type: 'string', + }, + }, + }, + }; + + const parser = new OpenAPIParser({ openapi: '3.0' } as any); + const opts = new RedocNormalizedOptions({}); + + const field = new FieldModel(parser, parameter, '', opts); + expect(serializeParameterValue(field, { name: 'test', age: 23 })).toEqual( + '{"name":"test","age":23}', + ); + }); + }); }); }); diff --git a/src/utils/openapi.ts b/src/utils/openapi.ts index 92de72ec..aa346a38 100644 --- a/src/utils/openapi.ts +++ b/src/utils/openapi.ts @@ -308,11 +308,37 @@ function serializeCookieParameter( } } -export function serializeParameterValue(parameter: OpenAPIParameter, value: any): string { - const { name, style, explode = false } = parameter; +export function serializeParameterValueWithMime(value: any, mime: string): string { + if (isJsonLike(mime)) { + return JSON.stringify(value); + } else { + console.warn(`Parameter serialization as ${mime} is not supported`); + return ''; + } +} + +export function serializeParameterValue( + parameter: OpenAPIParameter & { serializationMime?: string }, + value: any, +): string { + const { name, style, explode = false, serializationMime } = parameter; + + if (serializationMime) { + switch (parameter.in) { + case 'path': + case 'header': + return serializeParameterValueWithMime(value, serializationMime); + case 'cookie': + case 'query': + return `${name}=${serializeParameterValueWithMime(value, serializationMime)}`; + default: + console.warn('Unexpected parameter location: ' + parameter.in); + return ''; + } + } if (!style) { - console.warn(`Missing style attribute for parameter ${name}`); + console.warn(`Missing style attribute or content for parameter ${name}`); return ''; }