HttpApi: per-slot ParseOptions annotations with ParseOptions fallback - #8572
Merged
Merged
Conversation
Tests-first for EFF-1607: covers ParamsParseOptions, QueryParseOptions,
HeadersParseOptions, PayloadParseOptions, SuccessParseOptions and
ErrorParseOptions on the server (HttpApiBuilder) and client
(HttpApiClient, urlBuilder), including fallback to ParseOptions,
API-level slot annotations beating endpoint ParseOptions, replace-not-merge
semantics, and strict ParseOptions with HeadersParseOptions {} accepting
transport headers on requests and buffered/streamed WithHeaders responses.
Adds ParamsParseOptions, QueryParseOptions, HeadersParseOptions, PayloadParseOptions, SuccessParseOptions and ErrorParseOptions. Each slot uses its own annotation when set on the API, group or endpoint, otherwise falls back to ParseOptions. The buffered client WithHeaders path now decodes headers and bodies with their own options.
🦋 Changeset detectedLatest commit: 21ba2e5 The changes in this PR will be included in the next version bump. This PR includes changesets to release 31 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Contributor
Bundle Size AnalysisGenerated from PR build output; treat the content below as untrusted.
|
Replace the per-slot cases with one server scenario and three client scenarios that relax one slot at a time, covering fallback, API-level slots over endpoint ParseOptions, replace-not-merge, and the separate header/body decoding for buffered and streamed WithHeaders responses.
Server: encodeToWithHeaders response headers must use HeadersParseOptions rather than the error body options, in both directions. Client: header transformations must decode with HeadersParseOptions.
Store the user mapping and body/header wire codecs in the encodeToWithHeaders annotation, so the server and client handle these schemas like structural WithHeaders: the body uses the success/error options, the headers use the headers options, then the mapping applies. This removes the client's two-pass header check and the double header validation.
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.
Setting
HttpApi.ParseOptionsto{ onExcessProperty: "error" }breaks every endpoint with declared headers and everyWithHeadersresponse. That's because header maps always carry transport headers likecontent-typeanduser-agent. #8557 fixed this by quietly clearingonExcessPropertyfor header codecs. This PR instead lets users set parse options per codec slot.Changes
HttpApi:ParamsParseOptions,QueryParseOptions,HeadersParseOptions,PayloadParseOptions,SuccessParseOptionsandErrorParseOptions.ParseOptions, then to Schema defaults. A slot annotation at any level beatsParseOptionsat any level. It replacesParseOptionsand is never merged with it. Headers follow the same rule as every other slot.HttpApiBuilder,HttpApiClientandurlBuilderresolve options per slot.WithHeadersresponse headers (success and error, buffered and streamed) useHeadersParseOptions.WithHeaderspath no longer decodes a singleStruct({ body, headers })union with one set of options. Each response schema now decodes its body with the success/error options and its headers with the headers options, the same way the streamed path already works. There is no wrapper schema and noas any.ParseOptionsJSDoc lists the slot annotations and the resolution rule. It also explains the transport-header problem ("error"rejects real traffic,"preserve"leaks transport headers into decoded values) and shows the fix:Notes
encodeToWithHeadersschemas are handled like structuralWithHeaders: the annotation stores the user mapping plus the body and header codecs, so the server and client encode/decode the body with the success/error options and the headers with the headers options, then apply the mapping.HttpApiEndpointno longer wraps these schemas in a{ body, headers }struct; it only swaps in the response codecs.WithHeaderserrors andencodeToWithHeadersresponses share one response schema builder. On the client, each bufferedWithHeadersschema becomes a decode-only schema that applies the slot options internally, so response unions stay plainSchema.Unions.Validation
pnpm vitest --run packages/effect/test/httpapi/ packages/effect/test/reactivity/AtomHttpApi.test.ts packages/effect/test/httpplus the platform-nodeHttpApitests: 668 tests pass. This includes the tests-first commit and the existing Expose HttpApi.ParseOptions for schema decoding and encoding #8269ParseOptionstests.pnpm check,pnpm lint,pnpm jsdocs --checkandpnpm doctest --run packages/effect/src/http-api/HttpApi.tsall pass.Closes EFF-1607
Closes #8557