json modeling
Discriminated unions: serde tag vs json.RawMessage
One webhook endpoint, three event shapes (payment.succeeded, payment.failed, refund.created). Rust's serde reads the discriminator and lifts the right variant in one pass; Go has to do a two-step parse via an envelope of json.RawMessage fields.
// shop-two-backends not found at build time // shop-two-backends not found at build time What to take away
The headline is the type definition.
Rust: ten lines of enum WebhookEvent
with #[serde(tag = "type")]. serde reads
the "type" field, picks the variant, deserializes the
remaining JSON into that variant's struct. The handler then
match-es exhaustively — adding a fourth event variant
refuses to compile until handled.
Go: an envelope struct with
json.RawMessage for each possible payload field, a
switch on env.Type, and a per-arm
json.Unmarshal to lift the right sub-payload into a
concrete struct. ~3× the lines, and the switch's
default branch is the only thing standing between you
and a silently-ignored event you forgot to handle.
Both backends drive the same state-machine transitions
(payment.succeeded → paid,
payment.failed → cancelled,
refund.created → refunded) and return the same JSON
shape on success — the parity test exercises all three event
types per backend, plus the unknown event error path
(which Rust normalizes from axum's default 422 down to 400 to
match the Go side).