Skip to content

Commit 2f33f29

Browse files
authored
fix(type-safe-api): generate models for inline request body schemas (#873)
Inline request body schemas were typed as `any` and no model was generated for them. Address this by hoisting inline request schemas in the same way we do for responses. Note that OpenAPI generator named these hoisted inline request models `<OperationID>Request` which also clashes with the overall operation request model - and resolved it by appending `Operation` to the Operation ID (see #789). We deviate from OpenAPI generator behaviour to avoid this issue recurring by naming the type `<OperationID>RequestContent`.
1 parent ab61148 commit 2f33f29

File tree

5 files changed

+1757
-122
lines changed

5 files changed

+1757
-122
lines changed

packages/type-safe-api/scripts/type-safe-api/generators/generate-next.ts

+25-12
Original file line numberDiff line numberDiff line change
@@ -718,21 +718,34 @@ const buildData = async (inSpec: OpenAPIV3.Document, metadata: any) => {
718718
};
719719
}
720720

721-
// "Hoist" inline response schemas
721+
// "Hoist" inline request and response schemas
722722
Object.entries(spec.paths ?? {}).forEach(([path, pathOps]) => Object.entries(pathOps ?? {}).forEach(([method, op]) => {
723723
const operation = resolveIfRef(spec, op);
724-
if (operation && typeof operation === "object" && "responses" in operation) {
725-
Object.entries(operation.responses ?? {}).forEach(([code, res]) => {
726-
const response = resolveIfRef(spec, res);
727-
const jsonResponseSchema = response?.content?.['application/json']?.schema;
728-
if (jsonResponseSchema && !isRef(jsonResponseSchema) && ["object", "array"].includes(jsonResponseSchema.type!)) {
729-
const schemaName = `${_upperFirst(_camelCase(operation.operationId ?? `${path}-${method}`))}${code}Response`;
730-
spec.components!.schemas![schemaName] = jsonResponseSchema;
731-
response!.content!['application/json'].schema = {
732-
$ref: `#/components/schemas/${schemaName}`,
733-
};
724+
if (operation && typeof operation === "object") {
725+
if ("responses" in operation) {
726+
Object.entries(operation.responses ?? {}).forEach(([code, res]) => {
727+
const response = resolveIfRef(spec, res);
728+
const jsonResponseSchema = response?.content?.['application/json']?.schema;
729+
if (jsonResponseSchema && !isRef(jsonResponseSchema) && ["object", "array"].includes(jsonResponseSchema.type!)) {
730+
const schemaName = `${_upperFirst(_camelCase(operation.operationId ?? `${path}-${method}`))}${code}Response`;
731+
spec.components!.schemas![schemaName] = jsonResponseSchema;
732+
response!.content!['application/json'].schema = {
733+
$ref: `#/components/schemas/${schemaName}`,
734+
};
735+
}
736+
});
737+
}
738+
if ("requestBody" in operation) {
739+
const requestBody = resolveIfRef(spec, operation.requestBody);
740+
const jsonRequestSchema = requestBody?.content?.['application/json']?.schema;
741+
if (jsonRequestSchema && !isRef(jsonRequestSchema) && ["object", "array"].includes(jsonRequestSchema.type!)) {
742+
const schemaName = `${_upperFirst(_camelCase(operation.operationId ?? `${path}-${method}`))}RequestContent`;
743+
spec.components!.schemas![schemaName] = jsonRequestSchema;
744+
requestBody!.content!['application/json'].schema = {
745+
$ref: `#/components/schemas/${schemaName}`,
746+
};
734747
}
735-
});
748+
}
736749
}
737750
}));
738751

packages/type-safe-api/test/resources/specs/edge-cases.yaml

+17
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,23 @@ paths:
101101
enum:
102102
- fruit
103103
- vegetable
104+
/inline-request-body:
105+
post:
106+
operationId: inlineRequestBody
107+
responses:
108+
204:
109+
description: ok
110+
requestBody:
111+
content:
112+
application/json:
113+
schema:
114+
type: object
115+
properties:
116+
someProperty:
117+
type:
118+
string
119+
required:
120+
- someProperty
104121
components:
105122
schemas:
106123
MyEnum:

0 commit comments

Comments
 (0)