diff --git a/src/services/RedocNormalizedOptions.ts b/src/services/RedocNormalizedOptions.ts index acccfe4c84..f1a7373ce3 100644 --- a/src/services/RedocNormalizedOptions.ts +++ b/src/services/RedocNormalizedOptions.ts @@ -14,6 +14,8 @@ export interface RedocRawOptions { untrustedSpec?: boolean | string; hideLoading?: boolean | string; hideDownloadButton?: boolean | string; + + unstable_ignoreMimeParameters?: boolean; } function argValueToBoolean(val?: string | boolean): boolean { @@ -92,6 +94,9 @@ export class RedocNormalizedOptions { untrustedSpec: boolean; hideDownloadButton: boolean; + /* tslint:disable-next-line */ + unstable_ignoreMimeParameters: boolean; + constructor(raw: RedocRawOptions) { this.theme = resolveTheme(mergeObjects({} as any, defaultTheme, raw.theme || {})); this.scrollYOffset = RedocNormalizedOptions.normalizeScrollYOffset(raw.scrollYOffset); @@ -103,5 +108,7 @@ export class RedocNormalizedOptions { this.pathInMiddlePanel = argValueToBoolean(raw.pathInMiddlePanel); this.untrustedSpec = argValueToBoolean(raw.untrustedSpec); this.hideDownloadButton = argValueToBoolean(raw.hideDownloadButton); + + this.unstable_ignoreMimeParameters = argValueToBoolean(raw.unstable_ignoreMimeParameters); } } diff --git a/src/services/models/MediaContent.ts b/src/services/models/MediaContent.ts index bd126a21d8..dd3cc30001 100644 --- a/src/services/models/MediaContent.ts +++ b/src/services/models/MediaContent.ts @@ -3,12 +3,13 @@ import { action, computed, observable } from 'mobx'; import { OpenAPIMediaType } from '../../types'; import { MediaTypeModel } from './MediaType'; +import { mergeSimilarMediaTypes } from '../../utils'; import { OpenAPIParser } from '../OpenAPIParser'; import { RedocNormalizedOptions } from '../RedocNormalizedOptions'; /** * MediaContent model ready to be sued by React components - * Contains multiple MediaTypes and keeps track of the currently active on + * Contains multiple MediaTypes and keeps track of the currently active one */ export class MediaContentModel { mediaTypes: MediaTypeModel[]; @@ -20,10 +21,13 @@ export class MediaContentModel { */ constructor( public parser: OpenAPIParser, - info: { [mime: string]: OpenAPIMediaType }, + info: Dict, public isRequestType: boolean, options: RedocNormalizedOptions, ) { + if (options.unstable_ignoreMimeParameters) { + info = mergeSimilarMediaTypes(info); + } this.mediaTypes = Object.keys(info).map(name => { const mime = info[name]; // reset deref cache just in case something is left there diff --git a/src/utils/openapi.ts b/src/utils/openapi.ts index 188e52f840..e5ef887264 100644 --- a/src/utils/openapi.ts +++ b/src/utils/openapi.ts @@ -1,5 +1,11 @@ import { OpenAPIParser } from '../services/OpenAPIParser'; -import { OpenAPIOperation, OpenAPIParameter, OpenAPISchema, Referenced } from '../types'; +import { + OpenAPIMediaType, + OpenAPIOperation, + OpenAPIParameter, + OpenAPISchema, + Referenced, +} from '../types'; export function getStatusCodeType(statusCode: string | number, defaultAsError = false): string { if (statusCode === 'default') { @@ -199,4 +205,20 @@ export function mergeParams( return pathParams.concat(operationParams); } +export function mergeSimilarMediaTypes(types: Dict): Dict { + const mergedTypes = {}; + Object.keys(types).forEach(name => { + const mime = types[name]; + // ignore content type parameters (e.g. charset) and merge + const normalizedMimeName = name.split(';')[0].trim(); + if (!mergedTypes[normalizedMimeName]) { + mergedTypes[normalizedMimeName] = mime; + return; + } + mergedTypes[normalizedMimeName] = { ...mergedTypes[normalizedMimeName], ...mime }; + }); + + return mergedTypes; +} + export const SECURITY_SCHEMES_SECTION = 'section/Authentication/';