smithy
smithy copied to clipboard
How are `union` shapes bound with `httpPayload` serialized in JSON-based protocols?
The httpPayload
trait:
can be applied to
structure
members that target astring
,blob
,structure
,union
,document
,map
, orlist
.
Of note is that no AWS protocol supports list
or map
, but presumably union
is supported in e.g. restJson1
. How is it serialized?
Consider:
structure OperationInputOutput {
@httpPayload
union: Union
}
union Union {
good: String,
bad: String,
}
Surely the good
/bad
tag needs to be serialized in the payload for a deserializer to know what exact variant it's deserializing.
If you don't bind with httpPayload
, you'd serialize:
{
"good": "a good string"
}
It's serialized exactly like a structure. It's supported, I just don't think it's been used much in practice yet. We also should add a protocol test.
With an HTTP payload like in your example, it's serialized as the full payload:
{
"good": "hi"
}
If you don't bind with httpPayload, you'd serialize [...]
No, you'd serialize the union value inside the outer structure. If the OperationInputOutput$union
member had no @httpPayload
trait, then it's serialized inside a member of the input/output structure:
{
"union": {
"good": "hi"
}
}
No, you'd serialize the union value inside the outer structure.
Ah, my bad. This is how we're doing it. How do we serialize the union when the user has not set it (it's not required
)?. Without httpPayload
we'd do:
{
"union": null
}
So it seems like binding the union shape with httpPayload
to the HTTP body should serialize an unset union as just the null
value:
null
And for protocols that don't serialize null
values, it would just be an empty payload.
It's doable, but implementation-wise tricky, since the deserializer has to account for it expecting a JSON object or a value (or nothing) at the top-level.
Just to confirm, is this behavior what we want?
Unions can’t be assigned a default value, ~~so to bind them as httpPayload, they must be required. So I don’t think we need to account for a root level null.~~
Unions can’t be assigned a default value, so to bind them as httpPayload, they must be required.
I'm confused, is this implying that httpPayload
implies the member shape must be default
or required
?
I thought IDL v2 only made that provision for streaming
blobs:
Members targeting streaming blobs MUST be marked with the required trait or default trait.
Oh whoops. You’re right. Hm, I don’t know if we need to support an explicit null or can just rely on there being no payload at all.
Just to document the decision that was made, the added tests show that no payload is sent if the union has no value.