From e7011e366cf9558e7d95a337fc341c33e1b15865 Mon Sep 17 00:00:00 2001 From: Patrick McLaughlin Date: Fri, 17 Jan 2025 11:44:34 -0500 Subject: [PATCH] fix: don't explode headers --- packages/openapi-generator/src/route.ts | 26 ++++++--- .../test/openapi/union.test.ts | 56 ++++++++++++++++++- 2 files changed, 74 insertions(+), 8 deletions(-) diff --git a/packages/openapi-generator/src/route.ts b/packages/openapi-generator/src/route.ts index 70e7d41b..082d671c 100644 --- a/packages/openapi-generator/src/route.ts +++ b/packages/openapi-generator/src/route.ts @@ -157,13 +157,25 @@ function parseRequestUnion( }); } if (headerSchema.schemas.length > 0) { - parameters.push({ - type: 'header', - name: 'union', - explode: true, - required: true, - schema: headerSchema, - }); + // For headers in unions, take properties from first schema that has headers + // Also not perfect but we cannot use the `explode: true` trick for headers + const firstHeaderSchema = schema.schemas.find( + (s) => s.type === 'object' && s.properties['headers']?.type === 'object', + ); + if ( + firstHeaderSchema?.type === 'object' && + firstHeaderSchema.properties['headers']?.type === 'object' + ) { + const headers = firstHeaderSchema.properties['headers']; + for (const [name, prop] of Object.entries(headers.properties)) { + parameters.push({ + type: 'header', + name, + schema: prop, + required: headers.required.includes(name), + }); + } + } } const firstSubSchema = schema.schemas[0]; diff --git a/packages/openapi-generator/test/openapi/union.test.ts b/packages/openapi-generator/test/openapi/union.test.ts index e8b62212..443f1b5d 100644 --- a/packages/openapi-generator/test/openapi/union.test.ts +++ b/packages/openapi-generator/test/openapi/union.test.ts @@ -373,4 +373,58 @@ testCase("route with unknown unions", ROUTE_WITH_UNKNOWN_UNIONS, { } } }, -}); \ No newline at end of file +}); + +const ROUTE_WITH_REQUEST_UNION = ` +import * as t from 'io-ts'; +import * as h from '@api-ts/io-ts-http'; +import { BooleanFromString, BooleanFromNumber, NumberFromString } from 'io-ts-types'; + +export const route = h.httpRoute({ + path: '/foo', + method: 'GET', + request: t.union([ + h.httpRequest({ + headers: { + foo: t.string, + }, + }), + h.httpRequest({}), + ]), + response: { + 200: t.string, + }, +}); +`; + +testCase("route with request union", ROUTE_WITH_REQUEST_UNION, { + info: { + title: 'Test', + version: '1.0.0' + }, + openapi: '3.0.3', + paths: { + '/foo': { + get: { + parameters: [ + { in: 'header', name: 'foo', required: true, schema: { type: 'string' } }, + ], + responses: { + '200': { + description: 'OK', + content: { + 'application/json': { + schema: { + type: 'string' + } + } + } + } + } + } + } + }, + components: { + schemas: {} + } +});