From 7286ecafdbd3b7fea5c99983be9c11ea8e9a836f Mon Sep 17 00:00:00 2001 From: Gerard Downes Date: Tue, 17 Oct 2023 14:51:21 +0100 Subject: [PATCH] Add default responses to schema --- src/mock-mapper.ts | 4 ++-- src/oas.ts | 2 +- src/schema-type.ts | 52 ++++++++++++++++++++++++++++++++++++++---- src/sdk-mapper.ts | 8 +++---- test/schema-example.ts | 12 +++++----- 5 files changed, 61 insertions(+), 17 deletions(-) diff --git a/src/mock-mapper.ts b/src/mock-mapper.ts index 363f553..135c1ba 100644 --- a/src/mock-mapper.ts +++ b/src/mock-mapper.ts @@ -18,8 +18,8 @@ export interface Mock { } export const responseFrom = (oas: OAS, method: OASOperation): [string, any] => { - const statusCode = Object.keys(method.responses).find(x => x)!; - const refResponse = method.responses[statusCode]; + const statusCode = Object.keys(method.responses!).find(x => x)!; + const refResponse = method.responses![statusCode]; const response = Object.prototype.hasOwnProperty.call(refResponse, '$ref') ? traversePath((refResponse as OASRef)['$ref'], oas) : refResponse as OASResponse; const contentType = Object.keys(response.content ?? '')[0] const content = response.content ? response.content[contentType] : undefined; diff --git a/src/oas.ts b/src/oas.ts index 45d42e5..eadd74e 100644 --- a/src/oas.ts +++ b/src/oas.ts @@ -120,7 +120,7 @@ export interface OASOperation { operationId?: string; parameters?: Array; requestBody?: OASRequestBody | OASRef; - responses: { [statusCode: string]: OASResponse | OASRef }; + responses?: { [statusCode: string]: OASResponse | OASRef }; callbacks?: { [key: string]: OASPath | OASRef }; deprecated?: boolean; security?: OASSecurity[]; diff --git a/src/schema-type.ts b/src/schema-type.ts index c89e14d..ce79ec5 100644 --- a/src/schema-type.ts +++ b/src/schema-type.ts @@ -3,10 +3,10 @@ import { OASEncoding, OASInfo, OASMedia, - OASOAuthFlows, - OASParameter, + OASOAuthFlows, OASOperation, + OASParameter, OASPath, OASRef, OASResponse, - OASSecurityScheme + OASSecurityScheme, } from "./oas"; import {OAS, OASComponents} from "./oas.js"; @@ -169,6 +169,8 @@ export class OpenApiSpecificationBuilder Exclude): this { + this._defaultResponses = itemBuilder(this); + return this + } + addComponent OASComponents[K]>(location: K, itemBuilder: B): B extends (builder: any) => infer R ? OpenApiSpecificationBuilder : never { const item = itemBuilder(this); const current = this.oas.components ?? {}; @@ -294,13 +301,50 @@ export class OpenApiSpecificationBuilder ({ ...previousValue, [path]: this.addDefaultResponsesToPath(paths[path])}), {}) + } + add(location: K, itemBuilder: (builder: this) => OAS[K]): this { const item = itemBuilder(this); if (typeof item === "object") { if (Array.isArray(item)) { this.oas = {...this.oas, [location]: [...(this.oas[location] as any[] ?? []), ...item]}; } else { - this.oas = {...this.oas, [location]: {...(this.oas[location] as any ?? {}), ...(item as any)}}; + this.oas = {...this.oas, [location]: {...(this.oas[location] as any ?? {}), ...(location === "paths" ? this.addDefaultResponses(item as any) : (item as any))}}; } } else { this.oas = {...this.oas, [location]: item}; diff --git a/src/sdk-mapper.ts b/src/sdk-mapper.ts index f5974af..87b25a8 100644 --- a/src/sdk-mapper.ts +++ b/src/sdk-mapper.ts @@ -89,8 +89,8 @@ export function typeFrom(oas: OAS, response: OASResponse | OASRef): [string, str } function returnType(oas: OAS, method: OASOperation, imports: string[]): string { - return Object.keys(method.responses).map(statusCode => { - const response = method.responses[statusCode]; + return Object.keys(method.responses!).map(statusCode => { + const response = method.responses![statusCode]; const [type, newImports] = typeFrom(oas, response); imports.push(...newImports); return `{ statusCode: ${statusCode}; result: ${type} }`; @@ -104,8 +104,8 @@ function ifCode(code: string, json: boolean): string { } function bodyValue(oas: OAS, method: OASOperation): string { - return Object.keys(method.responses).map(statusCode => { - const response = method.responses[statusCode]; + return Object.keys(method.responses!).map(statusCode => { + const response = method.responses![statusCode]; const def = Object.prototype.hasOwnProperty.call(response, '$ref') ? traversePath((response as OASRef)['$ref'], oas) : response as OASResponse; const types = Object.keys(def.content ?? {}); const json = types[0] === 'application/json'; diff --git a/test/schema-example.ts b/test/schema-example.ts index 1443558..bf48710 100644 --- a/test/schema-example.ts +++ b/test/schema-example.ts @@ -1,4 +1,4 @@ -import {OpenApiSpecificationBuilder, SchemaBuilder, OASServer} from "../dist"; +import {OpenApiSpecificationBuilder, SchemaBuilder, OASServer} from "../src"; const builder = SchemaBuilder.create(); @@ -35,6 +35,9 @@ const schemas = builder.add('Chicken', s => s.object({ export default OpenApiSpecificationBuilder .create(schemas, { title: 'Chicken Store API', version: '1.0.0'}) .add('servers', () => servers) + .defaultResponses(o => ({ + 200: o.response('', o.textContent()) + })) .addComponent('securitySchemes', o => ({ Auth: o.openIdConnectScheme('.well-known/xyz')})) .add('paths', o => ({ '/chicken': { @@ -83,7 +86,7 @@ export default OpenApiSpecificationBuilder content: o.jsonContent('ChickenCreateRequest') }, responses: { - 200: o.response('The Chicken', {...o.jsonContent('Chicken'), ...o.textContent()}, ['Location']), + 200: o.response('The Chicken', {...o.jsonContent('Chicken'), ...o.textContent()}), 404: o.response('Not Found', o.textContent()), } }, @@ -92,10 +95,7 @@ export default OpenApiSpecificationBuilder parameters: [ o.path('chickenId'), o.header('X-Encryption-Key') - ], - responses: { - 200: {description: 'Success', content: o.textContent('Deleted')}, - } + ] }, }, '/schema': {