Add Optional Per-Call JSONDecoder
Atom now lets a single request decode with its own JSONDecoder. Both resume(expecting:) overloads accept an optional decoder; when supplied, it is used for that one call, and when omitted, decoding falls back to the decoder on ServiceConfiguration - exactly as before.
ServiceConfiguration has always carried a single decoder for the whole service. This release adds the missing granularity: a single service can decode one endpoint with a custom strategy while every other endpoint keeps the default, without standing up a second service.
A ServiceConfiguration carries one decoder, so every request through that Atom instance decodes the same way. That is the right default, but it is all-or-nothing: the moment one endpoint needs a different strategy - a date-decoding strategy for string dates, or key handling for a payload whose casing differs from the rest of the service - the choices were to change the decoder for the entire service or to build a second Atom for that one call. Both are heavier than the problem. This release adds a third option: decode one call differently, right where the call happens.
Proposed Solution
1. Accept an Optional Decoder at the Call Site
Both public resume(expecting:) overloads gained decoder: JSONDecoder? = nil. Because the parameter defaults to nil, every existing call site compiles unchanged.
2. Fall Back to the Service Decoder
The parameter is threaded through ServiceActor to the single decode site. When it is nil, decoding uses serviceConfiguration.decoder - the existing behavior. The de-duplication call and the raw-response passthrough are untouched.
3. Stateless by Design
The decoder rides with the request as a plain value parameter rather than living as mutable state on Atom or the actor. Concurrent calls cannot affect one another's decoding, and there is nothing new to make Sendable. It composes cleanly with in-flight de-duplication (v4.9.0): the coalescing key is method + URL only, so two callers that share one network call each decode the shared bytes with their own decoder.
Scope
Decoder only. The raw-response resume() overloads do not decode and are unchanged, and there is no matching change to JSONEncoder. ServiceConfiguration.decoder remains the default for every call that does not pass its own.
Changes:
- Added
decoder: JSONDecoder? = nilto both publicresume(expecting:)overloads (async and completion). - Threaded the per-call decoder through
ServiceActorto the decode site, falling back toServiceConfiguration.decoderwhen omitted. - Kept the override stateless, so it is safe under concurrency and under in-flight de-duplication.
- Updated the doc-comments on the affected overloads.
Source Compatibility:
- This change is additive and does not impact existing source code.
- This change breaks existing source code.