Repository navigation
v0.2.1 — interpret every trait simpleRestJson does
The fix
ndjsonRestJson's @protocolDefinition list named only 11 of the 28 traits alloy#simpleRestJson declares. That list isn't documentation — Protocol.hintMask is derived from it, and the interpreter builds its JSON codecs from that mask. So the 17 missing traits were silently ignored on every body, unary payloads and NDJSON elements alike.
Silently is the operative word: nothing errored. A @timestampFormat("date-time") member was written as an epoch number instead of an RFC-3339 string, and @jsonName reverted to the member name. The first sign was a decode failure on the far side of the wire, against a body that looked reasonable.
Traits that were being dropped:
smithy.api |
timestampFormat, jsonName, httpResponseCode, length, pattern, range |
alloy |
uuidFormat, discriminated, nullable, untagged, jsonUnknown, openEnum, durationSecondsFormat, dateFormat, localTimeFormat, offsetDateTimeFormat, preserveKeyOrder |
The codec stack already handled all of them — it's smithy4s's own, shared with SimpleRestJsonBuilder. Only the declaration was short. The list is now simpleRestJson's verbatim, plus @streaming.
⚠️ This changes bytes on the wire
If your model uses any trait in that table, your JSON changes — to what the protocol always promised. A @timestampFormat("date-time") member that 0.2.0 wrote as 1767225600 now writes "2026-01-01T00:00:00Z".
Binary compatibility is unaffected (MiMa passes), but binary compatibility doesn't imply behavioural compatibility. If you have a peer built against 0.2.0's output — a hand-written client, a recorded fixture, a stored payload — check it before upgrading. If you use none of those traits, this is a no-op.
Guarding it
ProtocolTraitsTestsasserts the trait set againstalloy.SimpleRestJson.protocol.traitsdirectly, not against a hand-copied list — so alloy adding a trait fails the build instead of drifting quietly back into this bug.- A new
Formatsfixture operation proves it end to end, exercising@timestampFormatand@jsonNameon a unary input and a streamed element within one call.
Full changelog: v0.2.0...v0.2.1