From 02157b54971a9f4134a9fae6c11b7698f8b9372d Mon Sep 17 00:00:00 2001 From: Kiskae <546681+Kiskae@users.noreply.github.com> Date: Fri, 30 Aug 2024 18:41:21 +0200 Subject: [PATCH] fix(fromOpenApi): remove extra whitespace from content type (#62) Co-authored-by: Kiskae Co-authored-by: Artem Zakharchenko --- src/open-api/utils/open-api-utils.test.ts | 48 +++++++++++++++++++++++ src/open-api/utils/open-api-utils.ts | 18 +++++---- test/oas/oas-json-schema.test.ts | 19 +++++++++ vitest.workspace.ts | 6 ++- 4 files changed, 82 insertions(+), 9 deletions(-) create mode 100644 src/open-api/utils/open-api-utils.test.ts diff --git a/src/open-api/utils/open-api-utils.test.ts b/src/open-api/utils/open-api-utils.test.ts new file mode 100644 index 0000000..05132ec --- /dev/null +++ b/src/open-api/utils/open-api-utils.test.ts @@ -0,0 +1,48 @@ +import { getAcceptedContentTypes } from './open-api-utils.js' + +it('returns a single content type as-is', () => { + expect( + getAcceptedContentTypes(new Headers([['accept', 'text/html']])), + ).toEqual(['text/html']) +}) + +it('ignores whitespace separating multiple content types', () => { + expect( + getAcceptedContentTypes( + new Headers([['accept', 'text/html, application/xhtml+xml, */*']]), + ), + ).toEqual(['text/html', 'application/xhtml+xml', '*/*']) +}) + +it('removes an empty content type', () => { + expect(getAcceptedContentTypes(new Headers([['accept', ', ,']]))).toEqual([]) + + expect( + getAcceptedContentTypes(new Headers([['accept', 'text/html, , */*']])), + ).toEqual(['text/html', '*/*']) +}) + +describe.skip('complex "accept" headers', () => { + it('supports weight reordering', () => { + expect( + getAcceptedContentTypes( + new Headers([ + [ + 'accept', + 'text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c', + ], + ]), + ), + ).toEqual(['text/html', 'text/x-c', 'text/x-dvi', 'text/plain']) + }) + + it('supports specificity reordering', () => { + expect( + getAcceptedContentTypes( + new Headers([ + ['accept', 'text/*, text/plain, text/plain;format=flowed, */*'], + ]), + ), + ).toEqual(['text/plain;format=flowed', 'text/plain', 'text/*', '*/*']) + }) +}) diff --git a/src/open-api/utils/open-api-utils.ts b/src/open-api/utils/open-api-utils.ts index f6246a9..178841b 100644 --- a/src/open-api/utils/open-api-utils.ts +++ b/src/open-api/utils/open-api-utils.ts @@ -81,10 +81,7 @@ export function toHeaders( } // See what "Content-Type" the request accepts. - const accept = request.headers.get('accept') || '' - const acceptedContentTypes = accept - .split(',') - .filter((item) => item.length !== 0) + const acceptedContentTypes = getAcceptedContentTypes(request.headers) const responseContentTypes = Object.keys(content) @@ -164,10 +161,7 @@ export function toBody( } // See what "Content-Type" the request accepts. - const accept = request.headers.get('accept') || '' - const acceptedContentTypes = accept - .split(',') - .filter((item) => item.length !== 0) + const acceptedContentTypes = getAcceptedContentTypes(request.headers) let mediaTypeObject: OpenAPIV3.MediaTypeObject | undefined const responseContentTypes = Object.keys(content) @@ -263,6 +257,14 @@ export function toBody( return null } +export function getAcceptedContentTypes(headers: Headers): string[] { + const accept = headers.get('accept') || '' + return accept + .split(',') + .map((item) => item.trim()) + .filter((item) => item.length !== 0) +} + function contentTypeToRegExp(contentType: string): RegExp { return new RegExp(contentType.replace(/\/+/g, '\\/').replace(/\*/g, '.+?')) } diff --git a/test/oas/oas-json-schema.test.ts b/test/oas/oas-json-schema.test.ts index 83d818e..2d45516 100644 --- a/test/oas/oas-json-schema.test.ts +++ b/test/oas/oas-json-schema.test.ts @@ -272,4 +272,23 @@ it('respects the "Accept" request header', async () => { }, }), ) + + // Skip content-types if the schema does not contain + // a matching response. + await expect( + await withHandlers(handlers, () => { + return fetch('http://localhost/user', { + headers: { + Accept: 'text/html, application/json', + }, + }) + }), + ).toEqualResponse( + new Response(JSON.stringify({ id: 'user-1' }), { + status: 200, + headers: { + 'Content-Type': 'application/json', + }, + }), + ) }) diff --git a/vitest.workspace.ts b/vitest.workspace.ts index 147ad53..3f8f325 100644 --- a/vitest.workspace.ts +++ b/vitest.workspace.ts @@ -4,7 +4,11 @@ export default defineWorkspace([ { test: { name: 'node', - include: ['!**/*.browser.test.ts', 'test/**/*.test.ts'], + include: [ + '!**/*.browser.test.ts', + 'test/**/*.test.ts', + 'src/**/*.test.ts', + ], globals: true, setupFiles: ['./vitest.setup.ts'], environment: 'node',