problem-details-ktor-client

Ktor Client integration: turn a recognized application/problem+json error response into the same io.github.ilyankin.rfc9457.ProblemException that application code throws on the server side and problem-details-ktor answers.

This module never depends on problem-details-ktor. It only needs to know the wire format, not how the other side of the connection is built — the same reasoning that keeps problem-details-ktor itself independent of either XML module.

JSON only, likewise by artifact: the Appendix B XML form is decoded by problemXml() in problem-details-ktor-client-xml, so a client that never speaks XML never resolves an XML parser. Registering both is order-independent — each gates on a Content-Type the other never matches — unlike the server's ContentNegotiation pair, where order decides an absent or wildcard Accept.

expectSuccess must be true

Ktor's own HttpClientConfig.expectSuccess defaults to false. Without it, nothing throws for a non-2xx response in the first place, so there is nothing for this module to intercept and replace:

val client = HttpClient(CIO) {
expectSuccess = true
HttpResponseValidator {
problemJson()
}
}

A client that has to keep the default can opt in per request instead — client.get(url) { expectSuccess = true }. Either way, the failure mode when it is missing is silence: nothing throws, and get() returns the error response as if it were a normal one.

What it does not do

It does not touch outgoing requests — no automatic Accept: application/problem+json header. Ktor's own default response validation runs regardless of what Accept was sent, and a server may answer with a problem document even when the client did not list the media type in Accept: RFC 9457 §3 does exactly that in its own example, as RFC 9110 §12.5.1 allows.

Packages

Link copied to clipboard

Two behaviors here are decisions, not defaults, and each is pinned by a test: