Skip to content

Commit

Permalink
fix: path parameters are not correctly override, fixes #481
Browse files Browse the repository at this point in the history
  • Loading branch information
RomanHotsiy committed May 14, 2018
1 parent 6d1a9e5 commit 2cf4c3c
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 7 deletions.
11 changes: 9 additions & 2 deletions src/services/OpenAPIParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ export class OpenAPIParser {

constructor(
spec: OpenAPISpec,
specUrl: string | undefined,
private options: RedocNormalizedOptions,
specUrl?: string,
private options: RedocNormalizedOptions = new RedocNormalizedOptions({}),
) {
this.validate(spec);
this.preprocess(spec);
Expand Down Expand Up @@ -166,6 +166,13 @@ export class OpenAPIParser {
return obj;
}

shalowDeref<T extends object>(obj: OpenAPIRef | T): T {
if (this.isRef(obj)) {
return this.byRef<T>(obj.$ref)!;
}
return obj;
}

/**
* Merge allOf contsraints.
* @param schema schema with allOF
Expand Down
13 changes: 9 additions & 4 deletions src/services/models/Operation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
getOperationSummary,
isAbsolutePath,
JsonPointer,
mergeParams,
sortByRequired,
stripTrailingSlash,
} from '../../utils';
Expand Down Expand Up @@ -65,7 +66,9 @@ export class OperationModel implements IMenuItem {
this.id =
operationSpec.operationId !== undefined
? 'operation/' + operationSpec.operationId
: this.parent !== undefined ? this.parent.id + operationSpec._$ref : operationSpec._$ref;
: this.parent !== undefined
? this.parent.id + operationSpec._$ref
: operationSpec._$ref;

this.name = getOperationSummary(operationSpec);
this.description = operationSpec.description;
Expand All @@ -83,9 +86,11 @@ export class OperationModel implements IMenuItem {
this.codeSamples = operationSpec['x-code-samples'] || [];
this.path = JsonPointer.baseName(this._$ref, 2);

this.parameters = operationSpec.pathParameters
.concat(operationSpec.parameters || [])
.map(paramOrRef => new FieldModel(parser, paramOrRef, this._$ref, options));
this.parameters = mergeParams(
parser,
operationSpec.pathParameters,
operationSpec.parameters,
).map(paramOrRef => new FieldModel(parser, paramOrRef, this._$ref, options));

if (options.requiredPropsFirst) {
sortByRequired(this.parameters);
Expand Down
39 changes: 39 additions & 0 deletions src/utils/__tests__/openapi.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@ import {
getStatusCodeType,
isOperationName,
isPrimitiveType,
mergeParams,
} from '../';

import { OpenAPIParser } from '../../services';
import { OpenAPIParameter } from '../../types';

describe('Utils', () => {
describe('openapi getStatusCode', () => {
it('Should return info for status codes within 100 and 200', () => {
Expand Down Expand Up @@ -183,4 +187,39 @@ describe('Utils', () => {
expect(isPrimitiveType(schema)).toEqual(false);
});
});

describe('openapi mergeParams', () => {
it('Should deduplicate params with same "name" and "in"', () => {
const pathParams: OpenAPIParameter[] = [
{
name: 'param1',
in: 'path',
description: 'path',
},
{
name: 'param2',
in: 'path',
},
];
const operationParams: OpenAPIParameter[] = [
{
name: 'param1',
in: 'path',
description: 'oper',
},
{
name: 'param2',
in: 'query',
},
];

const parser = new OpenAPIParser({ openapi: '3.0' } as any);

const res = mergeParams(parser, pathParams, operationParams) as OpenAPIParameter[];
expect(res).toHaveLength(3);
expect(res[0]).toEqual(pathParams[1]);
expect(res[1]).toEqual(operationParams[0]);
expect(res[2]).toEqual(operationParams[1]);
});
});
});
23 changes: 22 additions & 1 deletion src/utils/openapi.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { OpenAPIOperation, OpenAPISchema } from '../types';
import { OpenAPIParser } from '../services/OpenAPIParser';
import { OpenAPIOperation, OpenAPIParameter, OpenAPISchema, Referenced } from '../types';

export function getStatusCodeType(statusCode: string | number, defaultAsError = false): string {
if (statusCode === 'default') {
Expand Down Expand Up @@ -178,4 +179,24 @@ export function sortByRequired(
});
}

export function mergeParams(
parser: OpenAPIParser,
pathParams: Array<Referenced<OpenAPIParameter>> = [],
operationParams: Array<Referenced<OpenAPIParameter>> = [],
): Array<Referenced<OpenAPIParameter>> {
const operationParamNames = {};
operationParams.forEach(param => {
param = parser.shalowDeref(param);
operationParamNames[param.name + '_' + param.in] = true;
});

// filter out path params overriden by operation ones with the same name
pathParams = pathParams.filter(param => {
param = parser.shalowDeref(param);
return !operationParamNames[param.name + '_' + param.in];
});

return pathParams.concat(operationParams);
}

export const SECURITY_SCHEMES_SECTION = 'section/Authentication/';

0 comments on commit 2cf4c3c

Please sign in to comment.