RFC 9457 Problem Details for HttpApi errors
Maintainers usually reply within 1 day
Assessment
- Difficulty
- 5/5
- Estimated time
- Over a week
- Newbie friendliness
- 20/100
- Issue type
- Feature
- Clarity
- Clearly specified
- Activity status
- Stale
- Tech stack
- typescript
- Domain
- backend-api-design
Research direction
Start with packages/effect/src/http-api/HttpApiError.ts and the existing HttpApi middleware, schema, OpenAPI, and client paths named in the proposal. Review linked pull request #9706 and issue #5367 before considering scope; the issue leaves package placement and decode disclosure open. Done means implementing the proposed Problem Details schema, typed errors, opt-in rendering, OpenAPI support, and client decoding while preserving the default empty-body behavior.
Written by the indexing model from the issue text.
Description
Problem
RFC 9457 (application/problem+json) is the standard JSON format for HTTP API errors. HttpApi doesn't support it, and by default its errors have no body:
- The built-in errors (
HttpApiError.BadRequest,NotFound, and so on) are sent as empty responses (packages/effect/src/http-api/HttpApiError.ts:23-56). - When a request fails to decode, the server answers with an empty
400(HttpApiError.ts:507). The client gets no indication of which field was wrong or why.
You can build Problem Details yourself with HttpApiMiddleware.layerSchemaErrorTransform and HttpApiSchema.asJson({ contentType }). But every project then writes its own schema, picks its own type, title and status defaults, and has to get the RFC's parsing rules right. For example, §3.1 says a member with the wrong JSON type is ignored, not rejected. #5367 asked for this in v3 and was closed with a workaround that re-encoded response bodies in a middleware. The people in that thread noted that the OpenAPI output then had to be patched as well.
Proposal
- A
ProblemDetailsvalue and Schema:typedefaults toabout:blank.status,title,detailandinstanceare optional.- Unknown members are kept as extensions.
- It decodes leniently, as §3.1 requires, and encodes canonically.
- A way to declare a typed problem: a fixed
typeURI with typed extension members, usable as an HttpApi error schema with the right status, media type and OpenAPI entry.
- An opt-in that renders HttpApi's own errors (decode failures and the built-ins) as Problem Details.
HttpApiClientdecodesapplication/problem+jsonresponses into the declared problem type.
// names illustrative
class OutOfCredit extends ProblemDetails.Type("https://example.com/probs/out-of-credit", {
status: 403,
balance: Schema.Number
}) {}
HttpApiEndpoint.post("buy", "/buy", { error: OutOfCredit })
Why in Effect
HttpApi owns both the mapping from errors to responses and the OpenAPI output, so this is the one place where it can be done without post-processing bodies and patching the spec. The format is widely supported elsewhere: ASP.NET Core (AddProblemDetails), Spring (ProblemDetail), and Rust's http-api-problem crate.
Scope
In scope:
- The value and Schema, typed problems, opt-in rendering, OpenAPI output and client decoding.
Out of scope:
application/problem+xml.- Changing the default empty-body behaviour without an opt-in.
Open questions
- Should this live in
effect/http, so it can be used without HttpApi, or ineffect/http-api? - How much should a decode failure reveal by default? The failing path and message help clients, but they also expose details of the schema.
- Dominant language
- TypeScript
- Stars
- 16.7k
- Forks
- 808
- Avg merge
- 10h 7m
- Merged PRs (30d)
- 808
Getting set up
This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from Effect-TS/effect
-
Support {self: this} for fnUntracedPossibly taken @ArjunCodess claimed this 32 days ago. Openenhancement
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
Effect-TS/effect#8101 · 1 comment ·
Maintainers usually reply within 1 day
-
Difficulty 3/5 1-2 days Newbie friendliness 72/100
Maintainers usually reply within 1 day
-
v4 Cache.get: a caller that joins an abandoned lookup fails with an interruption it did not ask forOpen
Difficulty 4/5 3-5 days Newbie friendliness 42/100
Maintainers usually reply within 1 day
-
Typed unix socket and TLS options for `BunHttpClient` and `DenoHttpClient`Possibly taken @effect-bot claimed this today. Opendocker-made-me-do-it enhancement platform
Effect-TS/effect#9687 · 1 assignee ·
Maintainers usually reply within 1 day
-
Typed parsers and formatters for common HTTP header valuesPossibly taken @effect-bot claimed this today. Opendocker-made-me-do-it enhancement
Effect-TS/effect#9685 · 1 assignee ·
Maintainers usually reply within 1 day
All issues in Effect-TS/effect
Similar issues
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
endora-commerce/endora-commerce#397 ·
Maintainers usually reply within 1 day
-
level/task
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
wazuh/wazuh-dashboard-plugins#9472 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 63/100
Maintainers usually reply within 1 day
-
ready-for-agent
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
xavxyz/bei-shan-lin-shui#57 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
opennextjs/opennextjs-cloudflare#1461 ·
Maintainers usually reply within 1 day