diff --git a/src/fromOpenApi/fromOpenApi.ts b/src/fromOpenApi/fromOpenApi.ts index f9ef0bf..10a7e9a 100644 --- a/src/fromOpenApi/fromOpenApi.ts +++ b/src/fromOpenApi/fromOpenApi.ts @@ -1,5 +1,6 @@ import { invariant } from 'outvariant' import { datatype, internet, random } from 'faker' +import { headersToObject } from 'headers-utils' import { randexp } from 'randexp' import { RestContext, @@ -147,10 +148,23 @@ function createResponseResolver( if ('content' in response && response.content != null) { let body: unknown - const explicitContentType = req.url.searchParams.get('type') - const contentType = explicitContentType - ? explicitContentType - : Object.keys(response.content)[0] + const requestHeaders = headersToObject(req.headers) + const acceptedMimeTypes = ([] as string[]).concat(requestHeaders.accept) + const explicitContentType = acceptedMimeTypes[0] + const explicitContentTypeRegexp = new RegExp( + explicitContentType.replace(/\/+/g, '\\/').replace(/\*/g, '.+?'), + ) + + const allContentTypes = Object.keys(response.content) + + const contentType = + allContentTypes.find((contentType) => { + // Find the first declared response content type + // that matches the "Accept" request header. + // Keep in mind that values like "*/*" and "application/*" + // are completely valid. + return explicitContentTypeRegexp.test(contentType) + }) || allContentTypes[0] transformers.push(ctx.set('Content-Type', contentType)) @@ -167,7 +181,7 @@ function createResponseResolver( mediaTypeObject.examples, )[0] as OpenAPIV3.ExampleObject - // Response body must always be string. + // Response body must always be a string. body = value } // JSON Schema is populated with random values. diff --git a/test/oas/oas-json-schema.test.ts b/test/oas/oas-json-schema.test.ts index 419dd31..c539fb3 100644 --- a/test/oas/oas-json-schema.test.ts +++ b/test/oas/oas-json-schema.test.ts @@ -173,3 +173,53 @@ it('responds with 501 to a request for explicit non-existing response status', a expect(await res.text()).toEqual('') }) }) + +it('respects the "Accept" request header', async () => { + const handlers = await fromOpenApi( + createOpenApiSpec({ + paths: { + '/user': { + get: { + responses: { + 200: { + content: { + 'application/json': { + example: { id: 'user-1' }, + }, + 'application/xml': { + example: `xml-1`, + }, + }, + }, + }, + }, + }, + }, + }), + ) + + // The "Accept" request header with a single value. + await withHandlers(handlers, () => { + return fetch('http://localhost/user', { + headers: { + Accept: 'application/xml', + }, + }) + }).then(async (res) => { + expect(res.status).toEqual(200) + expect(await res.text()).toEqual(`xml-1`) + }) + + // The "Accept" request header with multiple values. + await withHandlers(handlers, () => { + return fetch('http://localhost/user', { + headers: { + Accept: 'application/json, application/xml', + }, + }) + }).then(async (res) => { + expect(res.status).toEqual(200) + // The first MimeType is used for the mocked data. + expect(await res.text()).toEqual(`{"id":"user-1"}`) + }) +})