Skip to content

Commit

Permalink
fix: support json serialization for parameter examples
Browse files Browse the repository at this point in the history
fixes #934
  • Loading branch information
RomanHotsiy committed Aug 1, 2019
1 parent 2afc2e4 commit 1367380
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 10 deletions.
7 changes: 3 additions & 4 deletions src/components/Fields/FieldDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,10 @@ export class FieldDetails extends React.PureComponent<FieldProps> {

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 = <FieldDetail label={label} value={serializedValue} raw={true} />;
} else {
exampleField = <FieldDetail label={label} value={example} />;
Expand Down
16 changes: 14 additions & 2 deletions src/services/models/Field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ export class FieldModel {
explode: boolean;
style?: OpenAPIParameterStyle;

serializationMime?: string;

constructor(
parser: OpenAPIParser,
infoOrRef: Referenced<OpenAPIParameter> & { name?: string; kind?: string },
Expand All @@ -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);
Expand Down
49 changes: 48 additions & 1 deletion src/utils/__tests__/openapi.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -389,6 +389,7 @@ describe('Utils', () => {
explode: boolean;
expected: string;
}

interface TestValueTypeGroup {
value: any;
description: string;
Expand Down Expand Up @@ -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}',
);
});
});
});
});
32 changes: 29 additions & 3 deletions src/utils/openapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 '';
}

Expand Down

0 comments on commit 1367380

Please sign in to comment.