feat(core): expose rawResponse, a status-preserving normalized response union#114
Open
thetutlage wants to merge 1 commit into
Open
feat(core): expose rawResponse, a status-preserving normalized response union#114thetutlage wants to merge 1 commit into
thetutlage wants to merge 1 commit into
Conversation
`ExtractResponse` flattens every 2xx return to just its body (dropping the
status), and `ExtractErrorResponse` keeps only non-2xx members. So a route's
success status (201/204) is never surfaced, and there's no single type that
enumerates all responses — which blocks OpenAPI generators from emitting
correct success codes and error responses.
Add `ExtractRawResponse<T>`, which normalizes a controller return type into a
discriminated union of `{ status; response }` across ALL status codes
(unbranded plain bodies default to 200), and emit a new `rawResponse` member
per route in the generated registry (with the same 422 validation clause
already applied to `errorResponse`).
Purely additive: `response`/`errorResponse` are unchanged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P3ZYnmGMEZwTuBuZviLDSq
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
@tuyau/core — Expose
rawResponse: a status-preserving normalized response unionProblem
The registry currently exposes two response types per route under
types:response: ExtractResponse<…>— for a 2xx return, extracts only the body and discards the status code. Every success (200, 201, 204, …) collapses to the same shape.errorResponse: ExtractErrorResponse<…>— keeps only non-2xx members, as{ status; response }.So the status is preserved for errors but thrown away for successes. There is no exposed type that says "this endpoint returns
201" or "…returns204", and no single type that enumerates all responses. Downstream consumers — notably OpenAPI generators — therefore cannot emit correct success status codes, and have to readresponse(always 200) +errorResponsefrom two places.Concretely, a controller action
return response.created(await serialize(dto))(typed{ __response: Dto; __status: 201 }) surfaces in the registry only asresponse: Dto— the201is unrecoverable.Change
Purely additive. Introduces one type and one new registry field.
New type
ExtractRawResponse<T>(in the types module, next toExtractResponse/ExtractErrorResponse):It's distributive over unions, so a mixed return (
Dto | { __response; __status: 401 }) becomes{ status: 200; response: Dto } | { status: 401; response: … }. Exported from@tuyau/core/types.Registry generator (
generate_registry) — emit arawResponseentry in each route'stypes, wrapping the raw awaited return type withExtractRawResponse, and appending the same validation-error ({ status: 422; response: … }) clause it already appends toerrorResponse. AddExtractRawResponseto the generated import list.Generated output per route becomes:
Backward compatibility
Non-breaking:
responseanderrorResponseare unchanged;rawResponseis a new additive field ontypes. Existing client typings and consumers are unaffected. (ExtractResponse/ExtractErrorResponsecould later be re-expressed in terms ofExtractRawResponse, but this PR leaves them untouched to minimize surface.)Why the success status matters (discriminated unions)
When a single action has multiple success states — e.g. login returning
{ status: 'authenticated'; … }vs{ status: 'mfaRequired'; … }—rawResponsepreserves each member as{ status: 200; response: <that shape> }, so consumers can render a faithfuloneOf. This is the piece that lets an OpenAPI generator (see companion PR to@outloud/adonis-openapi-generator) document 201/204/4xx and multi-state 200s correctly.Files touched (source equivalents of the compiled build)
ExtractRawResponsegenerate_registry—#wrapRawResponseType, emitrawResponse, extend the import list(The local reproduction patches the compiled
build/outputs:build/index-BPATPJFD.d.ts,build/client/types/index.d.ts,build/backend/generate_registry.js.)