Skip to content

Commit

Permalink
fix(type-safe-api): fix duplicate 200 response for operations with de…
Browse files Browse the repository at this point in the history
…fault responses

OpenAPI generator treated "default" responses as responses with code 0, however parseOpenapi treats
default as 200. Adjust code generation to follow OpenAPI for backwards compatibility and to avoid
duplicate 200 responses. Note that this should be revisited such that code generation allows for
any response code other than those defined to be returned for the default response, rather than 0.

References #841
  • Loading branch information
cogwirrel committed Oct 7, 2024
1 parent 9f06ae4 commit d2502dc
Show file tree
Hide file tree
Showing 4 changed files with 1,523 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ import _kebabCase from "lodash/kebabCase";
import _orderBy from "lodash/orderBy";
import _uniq from "lodash/uniq";
import _uniqBy from "lodash/uniqBy";
import _isEqual from "lodash/isEqual";
import { OpenAPIV3 } from "openapi-types";
import * as parseOpenapi from "parse-openapi";
import { getOperationResponses } from "parse-openapi/dist/parser/getOperationResponses";
import { getOperationResponse } from "parse-openapi/dist/parser/getOperationResponse";

const TSAPI_WRITE_FILE_START = "###TSAPI_WRITE_FILE###";
const TSAPI_WRITE_FILE_END = "###/TSAPI_WRITE_FILE###";
Expand Down Expand Up @@ -453,12 +455,24 @@ const buildData = (inSpec: OpenAPIV3.Document, metadata: any) => {
// Add all response models to the response model imports
responseModelImports.push(...responses.filter(r => r.export === "reference").map(r => r.type));

// parseOpenapi does not distinguish between returning an "any" or returning "void"
// We distinguish this by looking back each response in the spec, and checking whether it
// has content
const defaultResponse = resolveIfRef(spec, specOp.responses?.['default']);

[...responses, ...op.results].forEach((response) => {
// Check whether this response is actually the "default" response.
if (response.code === 200 && defaultResponse && _isEqual(response, getOperationResponse(spec, defaultResponse, 200))) {
// For backwards compatibility with OpenAPI generator, we set the response code for the default response to 0.
// See: https://github.com/OpenAPITools/openapi-generator/blob/8f2676c5c2bcbcc41942307e5c8648cee38bcc44/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenResponse.java#L622
// TODO: we should likely revisit this to make the handler wrappers more intuitive for the default response case, as
// the code 0 would actually need to be returned by the server for marshalling etc to work for the model associated with
// the default response.
response.code = 0;
}

const matchingSpecResponse = specOp.responses[`${response.code}`];

// parseOpenapi does not distinguish between returning an "any" or returning "void"
// We distinguish this by looking back each response in the spec, and checking whether it
// has content
if (matchingSpecResponse) {
// Resolve the ref if necessary
const specResponse = resolveIfRef(spec, matchingSpecResponse);
Expand Down
51 changes: 51 additions & 0 deletions packages/type-safe-api/test/resources/specs/default-response.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
openapi: 3.0.3
info:
version: 1.0.0
title: My API
description: See https://github.com/aws/aws-pdk/issues/841
paths:
/hello:
get:
operationId: sayHello
x-handler:
language: typescript
parameters:
- in: query
name: name
schema:
type: string
required: true
responses:
200:
description: Successful response
content:
'application/json':
schema:
$ref: '#/components/schemas/SayHelloResponseContent'
default:
description: An error due to the client not being authorized to access the resource
content:
'application/json':
schema:
$ref: '#/components/schemas/ServiceUnavailableErrorResponseContent'
components:
schemas:
SayHelloResponseContent:
type: object
properties:
id:
$ref: '#/components/schemas/HelloId'
message:
type: string
required:
- message
HelloId:
type: string
format: uuid
ServiceUnavailableErrorResponseContent:
type: object
properties:
message:
type: string
required:
- message
Loading

0 comments on commit d2502dc

Please sign in to comment.