diff --git a/packages/bruno-app/src/components/ApiSpecPanel/Renderers/Swagger/index.js b/packages/bruno-app/src/components/ApiSpecPanel/Renderers/Swagger/index.js index 94b36c6105b..e1b8f8a2d0a 100644 --- a/packages/bruno-app/src/components/ApiSpecPanel/Renderers/Swagger/index.js +++ b/packages/bruno-app/src/components/ApiSpecPanel/Renderers/Swagger/index.js @@ -2,6 +2,7 @@ import { memo } from 'react'; import SwaggerUI from 'swagger-ui-react'; import StyledWrapper from './StyledWrapper'; import { serializeBody } from './serializeBody'; +import { normalizeSpecForSwagger } from './normalizeSpec'; /* OpenAPISec 3.1.0 resolver ignores to dereference "$refs" when document.baseURI is not http/https as the packaged app is loaded over "file:/", so every internal $ref fails with "Evaluation failed on URI". @@ -77,11 +78,12 @@ const requestInterceptor = (req) => { }; const Swagger = ({ spec, onComplete }) => { + const normalizedSpec = normalizeSpecForSwagger(spec); return (
diff --git a/packages/bruno-app/src/components/ApiSpecPanel/Renderers/Swagger/normalizeSpec.js b/packages/bruno-app/src/components/ApiSpecPanel/Renderers/Swagger/normalizeSpec.js new file mode 100644 index 00000000000..f9f7446cd2a --- /dev/null +++ b/packages/bruno-app/src/components/ApiSpecPanel/Renderers/Swagger/normalizeSpec.js @@ -0,0 +1,24 @@ +/** + * SwaggerUI (swagger-ui-react) supports Swagger 2.0 and OpenAPI 3.0.x / 3.1.x. + * When an OpenAPI specification specifies a newer 3.x version (such as 3.2.0, 3.2.1), + * SwaggerUI rejects it as an unsupported version. Normalizing the version field to 3.1.0 + * allows SwaggerUI to parse and render the document seamlessly. + */ +export const normalizeSpecForSwagger = (spec) => { + if (!spec) return spec; + + if (typeof spec === 'string') { + return spec.replace(/(["']?openapi["']?\s*:\s*["']?)3\.[2-9]\d*(?:\.\d+)?([^"'\n\r]*["']?)/i, '$13.1.0$2'); + } + + if (typeof spec === 'object' && spec !== null) { + if (typeof spec.openapi === 'string' && /^3\.([2-9]|\d{2,})(\.|$)/.test(spec.openapi)) { + return { + ...spec, + openapi: '3.1.0' + }; + } + } + + return spec; +}; diff --git a/packages/bruno-app/src/components/ApiSpecPanel/Renderers/Swagger/normalizeSpec.spec.js b/packages/bruno-app/src/components/ApiSpecPanel/Renderers/Swagger/normalizeSpec.spec.js new file mode 100644 index 00000000000..bc2e662cfb6 --- /dev/null +++ b/packages/bruno-app/src/components/ApiSpecPanel/Renderers/Swagger/normalizeSpec.spec.js @@ -0,0 +1,44 @@ +import { normalizeSpecForSwagger } from './normalizeSpec'; + +describe('normalizeSpecForSwagger', () => { + it('returns falsy or non-object/string inputs unchanged', () => { + expect(normalizeSpecForSwagger(null)).toBeNull(); + expect(normalizeSpecForSwagger(undefined)).toBeUndefined(); + expect(normalizeSpecForSwagger(123)).toBe(123); + }); + + it('leaves OpenAPI 3.0.x and 3.1.x specs unchanged in string format', () => { + const yaml30 = 'openapi: 3.0.3\ninfo:\n title: Test'; + const yaml31 = 'openapi: "3.1.0"\ninfo:\n title: Test'; + const json30 = '{"openapi": "3.0.0", "info": {}}'; + expect(normalizeSpecForSwagger(yaml30)).toBe(yaml30); + expect(normalizeSpecForSwagger(yaml31)).toBe(yaml31); + expect(normalizeSpecForSwagger(json30)).toBe(json30); + }); + + it('normalizes OpenAPI 3.2.0 and 3.2.1 string specs to 3.1.0', () => { + const yaml32 = 'openapi: 3.2.0\ninfo:\n title: Test'; + const yaml321 = 'openapi: 3.2.1\ninfo:\n title: Test'; + const yamlQuotes = 'openapi: "3.2.1"\ninfo:\n title: Test'; + const json32 = '{"openapi": "3.2.0", "info": {}}'; + + expect(normalizeSpecForSwagger(yaml32)).toBe('openapi: 3.1.0\ninfo:\n title: Test'); + expect(normalizeSpecForSwagger(yaml321)).toBe('openapi: 3.1.0\ninfo:\n title: Test'); + expect(normalizeSpecForSwagger(yamlQuotes)).toBe('openapi: "3.1.0"\ninfo:\n title: Test'); + expect(normalizeSpecForSwagger(json32)).toBe('{"openapi": "3.1.0", "info": {}}'); + }); + + it('normalizes OpenAPI 3.2.x object specs to 3.1.0', () => { + const obj32 = { openapi: '3.2.1', info: { title: 'Test' } }; + const result = normalizeSpecForSwagger(obj32); + expect(result.openapi).toBe('3.1.0'); + expect(result.info.title).toBe('Test'); + }); + + it('leaves OpenAPI 3.0.x and 3.1.x object specs unchanged', () => { + const obj30 = { openapi: '3.0.0', info: { title: 'Test' } }; + const obj31 = { openapi: '3.1.0', info: { title: 'Test' } }; + expect(normalizeSpecForSwagger(obj30)).toEqual(obj30); + expect(normalizeSpecForSwagger(obj31)).toEqual(obj31); + }); +});