backstage / backstage/backstage
OpenAPI client generator should preserve types for multiple HTTP responses
- Dominant language
- TypeScript
- Stars
- 34.4k
- Forks
- 7.6k
- Avg merge
- 2d 16h
- Merged PRs (30d)
- 211
Description
### 📜 Issue Labels
- [x] Please familiarize yourself with the issue labels used in this project: [LABELS.md](https://github.com/backstage/backstage/blob/master/LABELS.md)
### 🔎 Search Terms
```plain
openapi tooling, openapi generator
```
### 🗃️ Project Area
OpenAPI Tooling
### 🔖 Need
The Backstage OpenAPI TypeScript client generator currently only uses the primary response type when generating `TypedResponse`.
For an OpenAPI operation with multiple responses, such as:
```yaml
responses:
'200':
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/User'
'404':
description: Resource not found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
```
the generated client exposes only:
```ts
Promise>
```
This loses the response body types for the 404 and 500 responses, even though they are explicitly defined in the OpenAPI specification.
This makes it difficult to write fully type-safe clients for APIs where different HTTP status codes have different response schemas.
### 📝 Proposal
Update the TypeScript client generator to preserve the relationship between each HTTP response status code and its response body type.
the generated client could expose:
```ts
export type GetUserResponse =
| TypedResponse
| TypedResponse
| TypedResponse;
```
and:
```
public async getUser(
request: GetUser,
options?: RequestOptions,
): Promise
```
This would allow consumers to safely narrow the response body based on the HTTP status:
```
const response = await client.getUser(request);
if (response.status === 200) {
const user = await response.json();
// User
}
if (response.status === 404) {
const error = await response.json();
// ErrorResponse
}
```
The exact generated API can differ, but the important requirement is that the generated client preserves the mapping between HTTP status codes and their response schemas.
### 🔄 Alternatives
1. **Use a union of response body types**
```ts
TypedResponse
```
This does not preserve the relationship between the HTTP status and response body, so TypeScript cannot safely narrow the body type based on response.status.
2. **Handle error responses outside the generated client**
Consumers can manually inspect and type-cast error responses. This requires duplicated response handling/type definitions in every consumer and loses the benefit of generating types from the OpenAPI specification.
3. **Manually modify the generated client**
This is not desirable because the client is generated code and changes would be lost whenever the OpenAPI client is regenerated.
4. **Keep the current behavior**
Consumers can continue using only the successful response type and handle non-success responses without generated body types. However, this means information already present in the OpenAPI specification is discarded by the generated TypeScript client.
### Have you read the Code of Conduct?
- [x] I have read the [Code of Conduct](https://github.com/backstage/backstage/blob/master/CODE_OF_CONDUCT.md)
### Are you willing to submit a PR?
Undecided
Contributor guide
Research direction
Begin at the OpenAPI TypeScript client generator and trace how TypedResponse is produced for operations with multiple responses. Verify that the generated response type retains each status-code/schema pairing, including 200, 404, and 500, and that consumers can narrow the body type by response status.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- openapi, typescript
- Domain
- api, tooling
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100