Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions src/codegen/inputs/openapi/generators/payloads.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,22 +152,26 @@ function extractPayloadsFromOperations(
path: pathKey
});

// Extract request payload schema
// Extract request payload schema.
// Prefer the 3.x `requestBody`: 3.x operations also carry a `parameters`
// array (path/query/header), so presence of `parameters` cannot be used
// to detect 2.0 - doing so would drop the body on any 3.x operation that
// declares parameters. The 2.0 body lives in a `parameters` entry with
// `in: 'body'`, so fall back to that only when there is no `requestBody`.
let requestSchema: any = null;

// Check if this is OpenAPI 2.0 vs 3.x based on the structure
if ('parameters' in operationObj && operationObj.parameters) {
// OpenAPI 2.0 style
requestSchema = extractOpenAPI2RequestSchema(
operationObj.parameters as OpenAPIV2.ParameterObject[]
);
} else if ('requestBody' in operationObj && operationObj.requestBody) {
if ('requestBody' in operationObj && operationObj.requestBody) {
// OpenAPI 3.x style
requestSchema = extractOpenAPI3RequestSchema(
operationObj.requestBody as
| OpenAPIV3.RequestBodyObject
| OpenAPIV3_1.RequestBodyObject
);
} else if ('parameters' in operationObj && operationObj.parameters) {
// OpenAPI 2.0 style (body carried as a `in: 'body'` parameter)
requestSchema = extractOpenAPI2RequestSchema(
operationObj.parameters as OpenAPIV2.ParameterObject[]
);
}

if (requestSchema) {
Expand Down
8 changes: 8 additions & 0 deletions test/codegen/generators/typescript/payload.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,10 @@ describe('payloads', () => {
key: "createUsersWithListInput",
value: "CreateUsersWithListInputRequest",
},
{
key: "updateUser",
value: "AUser",
},
{
key: "addPet_Response",
value: "APet",
Expand Down Expand Up @@ -277,6 +281,10 @@ describe('payloads', () => {
key: "createUsersWithListInput",
value: "CreateUsersWithListInputRequest",
},
{
key: "updateUser",
value: "AUser",
},
{
key: "addPet_Response",
value: "APet",
Expand Down
60 changes: 60 additions & 0 deletions test/codegen/inputs/openapi/payloads.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import {OpenAPIV3} from 'openapi-types';
import {processOpenAPIPayloads} from '../../../../src/codegen/inputs/openapi/generators/payloads';

describe('OpenAPI payload extraction', () => {
describe('processOpenAPIPayloads', () => {
it('extracts the request body of a 3.x operation that also declares parameters', () => {
// Regression: a 3.x operation carrying both `parameters` (header/path/query)
// and a `requestBody` must not be mistaken for OpenAPI 2.0 - the body was
// previously dropped whenever any parameter was present.
const document: OpenAPIV3.Document = {
openapi: '3.0.0',
info: {title: 'Test API', version: '1.0.0'},
paths: {
'/things': {
post: {
parameters: [
{
name: 'X-Correlation-Id',
in: 'header',
schema: {type: 'string'}
}
],
requestBody: {
required: true,
content: {
'application/json': {
schema: {
type: 'object',
properties: {name: {type: 'string'}}
}
}
}
},
responses: {
200: {
description: 'OK',
content: {
'application/json': {
schema: {type: 'object', properties: {id: {type: 'string'}}}
}
}
}
}
}
}
}
};

const {operationPayloads} = processOpenAPIPayloads(document);

// The request body surfaces as an operation payload whose schema id ends
// in `Request`; before the fix only the `Response` payload was present.
const schemaIds = Object.values(operationPayloads).map(
(payload) => payload.schemaId
);
expect(schemaIds.some((id) => id.endsWith('Request'))).toBe(true);
expect(schemaIds.some((id) => id.endsWith('Response'))).toBe(true);
});
});
});
Loading