Skip to content

v0.2.1 — interpret every trait simpleRestJson does

Choose a tag to compare

@kubukoz kubukoz released this 19 Aug 19:36
· 14 commits to main since this release
v0.2.1
427b0bb

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

  • ProtocolTraitsTests asserts the trait set against alloy.SimpleRestJson.protocol.traits directly, not against a hand-copied list — so alloy adding a trait fails the build instead of drifting quietly back into this bug.
  • A new Formats fixture operation proves it end to end, exercising @timestampFormat and @jsonName on a unary input and a streamed element within one call.

Full changelog: v0.2.0...v0.2.1