Description
When a POST route's input schema contains only path parameters (e.g. z.object({ studyName: z.string() }) for a route /{studyName}/export), the OpenAPI generator emits an empty requestBody:
```yaml
requestBody:
required: false
content:
application/json:
schema:
type: object
properties: {}
required: []
```
This body is meaningless — the endpoint has no request body — and causes noise/confusion in generated clients and documentation.
Why it happens
In packages/openapi/src/openapi-generator.ts, the #inputParams() method (around line 351) calls separateObjectSchema(schema, dynamicParams) to split path params from the rest. When all fields are path params, the remainder is an empty object schema { properties: {}, required: [] }. The generator emits this unconditionally as a requestBody.
Expected behaviour
No requestBody should be emitted when the remainder after path-param separation is an empty object schema.
Suggested fix
Skip emitting requestBody when the remaining schema is an empty object:
```typescript
else {
const isEmptyObject = isObjectSchema(schema)
&& (!schema.properties || Object.keys(schema.properties).length === 0)
&& (!schema.required || schema.required.length === 0)
if (!isEmptyObject) {
ref.requestBody = {
required,
content: toOpenAPIContent(schema),
}
}
}
```
Backward compatibility
Only suppresses requestBody when it would be an empty object. Any route with actual body fields is unaffected.
Reproduction
```typescript
const contract = oc
.route({ method: 'POST', path: '/{studyName}/export' })
.input(z.object({ studyName: z.string() }))
.output(z.string())
```
Discovered while working on #1058.
Description
When a POST route's input schema contains only path parameters (e.g.
z.object({ studyName: z.string() })for a route/{studyName}/export), the OpenAPI generator emits an emptyrequestBody:```yaml
requestBody:
required: false
content:
application/json:
schema:
type: object
properties: {}
required: []
```
This body is meaningless — the endpoint has no request body — and causes noise/confusion in generated clients and documentation.
Why it happens
In
packages/openapi/src/openapi-generator.ts, the#inputParams()method (around line 351) callsseparateObjectSchema(schema, dynamicParams)to split path params from the rest. When all fields are path params, the remainder is an empty object schema{ properties: {}, required: [] }. The generator emits this unconditionally as arequestBody.Expected behaviour
No
requestBodyshould be emitted when the remainder after path-param separation is an empty object schema.Suggested fix
Skip emitting
requestBodywhen the remaining schema is an empty object:```typescript
else {
const isEmptyObject = isObjectSchema(schema)
&& (!schema.properties || Object.keys(schema.properties).length === 0)
&& (!schema.required || schema.required.length === 0)
if (!isEmptyObject) {
ref.requestBody = {
required,
content: toOpenAPIContent(schema),
}
}
}
```
Backward compatibility
Only suppresses
requestBodywhen it would be an empty object. Any route with actual body fields is unaffected.Reproduction
```typescript
const contract = oc
.route({ method: 'POST', path: '/{studyName}/export' })
.input(z.object({ studyName: z.string() }))
.output(z.string())
```
Discovered while working on #1058.