fix: path parameters are not correctly override, fixes #481

This commit is contained in:
Roman Hotsiy 2018-05-14 11:37:19 +03:00
parent 6d1a9e589c
commit 2cf4c3cd7b
No known key found for this signature in database
GPG Key ID: 5CB7B3ACABA57CB0
4 changed files with 79 additions and 7 deletions

View File

@ -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);
@ -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

View File

@ -12,6 +12,7 @@ import {
getOperationSummary,
isAbsolutePath,
JsonPointer,
mergeParams,
sortByRequired,
stripTrailingSlash,
} from '../../utils';
@ -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;
@ -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);

View File

@ -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', () => {
@ -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]);
});
});
});

View File

@ -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') {
@ -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/';