From e8967c609eb76bd916d2d1c0340c71099aa4b630 Mon Sep 17 00:00:00 2001 From: Patrick McLaughlin Date: Tue, 5 Nov 2024 11:30:31 -0500 Subject: [PATCH] feat: add support for request headers --- packages/openapi-generator/src/route.ts | 77 +++++++++++++++---- packages/openapi-generator/test/route.test.ts | 41 ++++++++++ 2 files changed, 101 insertions(+), 17 deletions(-) diff --git a/packages/openapi-generator/src/route.ts b/packages/openapi-generator/src/route.ts index 4a84d674..70e7d41b 100644 --- a/packages/openapi-generator/src/route.ts +++ b/packages/openapi-generator/src/route.ts @@ -8,7 +8,7 @@ import { findSymbolInitializer } from './resolveInit'; import { errorLeft } from './error'; export type Parameter = { - type: 'path' | 'query'; + type: 'path' | 'query' | 'header'; name: string; schema: Schema; explode?: boolean; @@ -84,6 +84,22 @@ function parseRequestObject(schema: Schema): E.Either { } } + const headerSchema = schema.properties['headers']; + if (headerSchema !== undefined) { + if (headerSchema.type !== 'object') { + return errorLeft('Route headers must be an object'); + } else { + for (const [name, prop] of Object.entries(headerSchema.properties)) { + parameters.push({ + type: 'header', + name, + schema: prop, + required: headerSchema.required.includes(name), + }); + } + } + } + return E.right({ parameters, body: schema.properties['body'], @@ -103,6 +119,7 @@ function parseRequestUnion( // This isn't perfect but it's about as good as we can do in openapi const parameters: Parameter[] = []; const querySchema: Schema = { type: 'union', schemas: [] }; + const headerSchema: Schema = { type: 'union', schemas: [] }; let body: Schema | undefined; for (let subSchema of schema.schemas) { @@ -126,6 +143,9 @@ function parseRequestUnion( } (body as CombinedType).schemas.push(subSchema.properties['body']); } + if (subSchema.properties['headers'] !== undefined) { + headerSchema.schemas.push(subSchema.properties['headers']); + } } if (querySchema.schemas.length > 0) { parameters.push({ @@ -136,6 +156,15 @@ function parseRequestUnion( schema: querySchema, }); } + if (headerSchema.schemas.length > 0) { + parameters.push({ + type: 'header', + name: 'union', + explode: true, + required: true, + schema: headerSchema, + }); + } const firstSubSchema = schema.schemas[0]; if (firstSubSchema !== undefined && firstSubSchema.type === 'object') { @@ -203,28 +232,42 @@ function parseRequestSchema( } } +export function resolveStringProperty( + project: Project, + schema: Schema | undefined, + name: string, +): E.Either { + if (schema === undefined) { + return errorLeft(`Route ${name} is missing`); + } else if (schema.type === 'ref') { + const derefE = derefRequestSchema(project, schema); + if (E.isLeft(derefE)) { + return derefE; + } + return resolveStringProperty(project, derefE.right, name); + } else if (schema.type === 'string' && schema.enum?.length === 1) { + return E.right(schema.enum[0]! as string); + } else { + return errorLeft(`Route ${name} must be a string literal`); + } +} + export function parseRoute(project: Project, schema: Schema): E.Either { if (schema.type !== 'object') { return errorLeft('Route must be an object'); } - if (schema.properties['path'] === undefined) { - return errorLeft('Route must have a path'); - } else if ( - schema.properties['path'].type !== 'string' || - schema.properties['path'].enum?.length !== 1 - ) { - return errorLeft('Route path must be a string literal'); + const pathE = resolveStringProperty(project, schema.properties['path'], 'path'); + if (E.isLeft(pathE)) { + return pathE; } + const path = pathE.right; - if (schema.properties['method'] === undefined) { - return errorLeft('Route must have a method'); - } else if ( - schema.properties['method'].type !== 'string' || - schema.properties['method'].enum?.length !== 1 - ) { - return errorLeft('Route method must be a string literal'); + const methodE = resolveStringProperty(project, schema.properties['method'], 'method'); + if (E.isLeft(methodE)) { + return methodE; } + const method = methodE.right; const requestSchema = schema.properties['request']; if (requestSchema === undefined) { @@ -243,8 +286,8 @@ export function parseRoute(project: Project, schema: Schema): E.Either