12. Serialization and Protocol traits#
12.1. protocolDefinition
trait#
- Summary
- A meta-trait that marks a trait as a protocol definition trait. Traits that are marked with this trait are applied to service shapes to define the protocols supported by a service. A client MUST understand at least one of the protocols in order to successfully communicate with the service.
- Trait selector
[trait|trait]
- Value type
An object with the following properties:
Property Type Description traits [Shape ID] List of shape IDs that protocol implementations MUST understand in order to successfully use the protocol. Each shape MUST exist and MUST be a trait. Code generators SHOULD ensure that they support each listed trait. noInlineDocumentSupport boolean
If set to true
, indicates that this protocol does not supportdocument
type shapes. A service that uses such a protocol MUST NOT contain anydocument
shapes in their service closure.
Smithy is protocol agnostic, which means it focuses on the interfaces and abstractions that are provided to end-users rather than how the data is sent over the wire. In Smithy, a protocol is a named set of rules that defines the syntax and semantics of how a client and server communicate. This includes the application layer protocol of a service (for example, HTTP) and the serialization formats used in messages (for example, JSON). Traits MAY be used to influence how messages are serialized (for example, jsonName trait and xmlAttribute trait).
The following example defines a service that supports both the hypothetical
jsonExample
and xmlExample
protocols.
/// An example JSON protocol.
@protocolDefinition
@trait(selector: "service")
structure jsonExample {}
/// An example XML protocol.
@protocolDefinition
@trait(selector: "service")
structure xmlExample {}
@jsonExample
@xmlExample
service WeatherService {
version: "2017-02-11"
}
Because protocol definitions are just specialized shapes, they can also support configuration settings.
@protocolDefinition
@trait(selector: "service")
structure configurableExample {
@required
version: String
}
@configurableExample(version: "1.0")
service WeatherService {
version: "2017-02-11"
}
12.2. jsonName
trait#
- Summary
- Allows a serialized object property name in a JSON document to differ from a structure or union member name used in the model.
- Trait selector
:is(structure, union) > member
Any structure or union member
- Value type
string
Given the following structure definition,
structure MyStructure {
@jsonName("Foo")
foo: String
bar: String
}
and the following values provided for MyStructure
,
"foo" = "abc"
"bar" = "def"
the JSON representation of the value would be serialized with the following document:
{
"Foo": "abc",
"bar": "def"
}
Note
No two members of the same structure or union can use the
same case-sensitive @jsonName
.
12.3. mediaType
trait#
- Summary
- Describes the contents of a blob or string shape using a design-time
media type as defined by RFC 6838 (for example,
application/json
). - Trait selector
:is(blob, string)
Any blob or string
- Value type
string
The following example defines a video/quicktime
blob:
$version: "2"
namespace smithy.example
@mediaType("video/quicktime")
blob VideoData
12.3.1. Use cases#
The primary function of the mediaType
trait is to send open content
data over the wire inside of values that are isolated from the rest of
a payload using exact representations of customer provided data. While the
model does define the serialization format of values able to be stored in a
shape at design-time using a media type, models are not required to define
any kind of schema for the shape.
The mediaType
trait can be used to aid tools in documentation,
validation, special-cased helpers to serialize and deserialize media type
contents in code, assigning a fixed Content-Type when using
HTTP bindings, etc.
12.3.2. Comparisons to document types#
The serialization format of a shape marked with the @mediaType
trait is
an important part of its contract. In contrast, document types are
serialized in a protocol-agnostic way and can only express data types as
granular as the JSON-type system. Design-time media types are preferred over
document types when the exact bytes of a value are required for an
application to function.
12.4. timestampFormat
trait#
- Summary
- Defines a custom timestamp serialization format.
- Trait selector
:test(timestamp, member > timestamp)
timestamp or member that targets a timestamp
- Value type
string
By default, the serialization format of a timestamp is implicitly determined by
the protocol of a service; however, the
serialization format can be explicitly configured in some protocols to
override the default format using the timestampFormat
trait.
12.4.1. Timestamp formats#
Smithy defines the following built-in timestamp formats:
Format | Description |
---|---|
date-time | Date time as defined by the date-time production in
RFC 3339#section-5.6 with optional millisecond precision but no
UTC offset (for example, 1985-04-12T23:20:50.520Z ). Values that
are more granular than millisecond precision SHOULD be truncated to
fit millisecond precision. Deserializers SHOULD parse date-time
values that contain offsets gracefully by normalizing them to UTC. |
http-date | An HTTP date as defined by the IMF-fixdate production in
RFC 9110#section-5.6.7 (for example,
Tue, 29 Apr 2014 18:30:38 GMT ). A deserializer that encounters an
http-date timestamp with fractional precision SHOULD fail to
deserialize the value (for example, an HTTP server SHOULD return a 400
status code). |
epoch-seconds | Also known as Unix time, the number of seconds that have elapsed since
00:00:00 Coordinated Universal Time (UTC), Thursday, 1 January 1970,
with optional millisecond precision (for example, 1515531081.123 ).
Values that are more granular than millisecond precision SHOULD be
truncated to fit millisecond precision. |
12.4.2. Resolving timestamp formats#
The following steps are taken to determine the serialization format of a member that targets a timestamp:
- Use the
timestampFormat
trait of the member, if present. - Use the
timestampFormat
trait of the shape, if present. - Use the default format of the protocol.
Important
This trait SHOULD NOT be used unless the intended serialization format of a timestamp differs from the default protocol format. Using this trait too liberally can cause other tooling to improperly interpret the timestamp.
12.5. XML bindings#
Defines how to bind Smithy shapes to XML documents.
12.5.1. Structure and union serialization#
All XML serialization starts with a structure or union. The shape name of a structure/union is used as the outermost XML element name. Members of a structure/union are serialized as nested XML elements where the name of the element is the same as the name of the member.
For example, given the following:
structure MyStructure {
foo: String
}
The XML serialization is:
<MyStructure>
<foo>example</foo>
</MyStructure>
12.5.1.1. Custom XML element names#
Structure/union member element names can be changed using the xmlName trait.
12.5.1.2. XML attributes#
The xmlAttribute trait is used to serialize a structure member as an XML attribute.
12.5.1.3. xmlName
on structures and unions#
An xmlName
trait applied to a structure or union changes the element name
of the serialized shape; however, it does not influence the serialization of
members that target it. Given the following:
@xmlName("AStruct")
structure A {
b: B
}
@xmlName("BStruct")
structure B {
hello: String
}
The XML serialization of AStruct
is:
<AStruct>
<b>
<hello>value</hello>
</b>
</AStruct>
12.5.2. Simple type serialization#
The following table defines how simple types are serialized in XML documents.
Shape | Serialization |
---|---|
blob | Serialized as a base64 encoded string structure Struct {
binary: Blob
}
given a value of <Struct>
<binary>dmFsdWU=</binary>
</Struct>
|
boolean | Serialized as "true " or "false " |
string | Serialized as an XML-safe UTF-8 string |
byte | Serialized as the string value of the number |
short | Serialized as the string value of the number |
integer | Serialized as the string value of the number |
long | Serialized as the string value of the number |
float | Serialized as the string value of the number using scientific notation if an exponent is needed. |
double | Serialized as the string value of the number using scientific notation if an exponent is needed. |
bigInteger | Serialized as the string value of the number using scientific notation if an exponent is needed. |
bigDecimal | Serialized as the string value of the number using scientific notation if an exponent is needed. |
timestamp | Serialized as RFC 3339 date-time value. structure Struct {
date: Timestamp
}
given a value of <Struct>
<date>2020-01-05T20:13:26Z</date>
</Struct>
|
document | Warning Document shapes are not recommended for use in XML based protocols. |
12.5.3. List serialization#
List shapes use the same serialization semantics. List shapes can be serialized as wrapped lists (the default behavior) or flattened lists.
12.5.3.1. Wrapped list serialization#
A wrapped list is serialized in an XML element where each value is
serialized in a nested element named member
. For example, given the
following:
structure Foo {
values: MyList
}
list MyList {
member: String
}
The XML serialization of Foo
is:
<Foo>
<values>
<member>example1</member>
<member>example2</member>
<member>example3</member>
</values>
</Foo>
The xmlName trait can be applied to the member of a list to change the nested element name. For example, given the following:
structure Foo {
values: MyList
}
list MyList {
@xmlName("Item")
member: String
}
The XML serialization of Foo
is:
<Foo>
<values>
<Item>example1</Item>
<Item>example2</Item>
<Item>example3</Item>
</values>
</Foo>
12.5.3.2. Flattened list serialization#
The xmlFlattened trait can be used to unwrap the values of list into a containing structure/union. The name of the elements repeated within the structure/union is based on the structure/union member name. For example, given the following:
structure Foo {
@xmlFlattened
flat: MyList
}
The XML serialization of Foo
is:
<Foo>
<flat>example1</flat>
<flat>example2</flat>
<flat>example3</flat>
</Foo>
The xmlName
trait applied to the structure/union member is used to change
the name of the repeated XML element. For example, given the following:
union Choice {
@xmlFlattened
@xmlName("Hi")
flat: MyList
}
list MyList {
member: String
}
The XML serialization of Choice
is:
<Choice>
<Hi>example1</Hi>
<Hi>example2</Hi>
<Hi>example3</Hi>
</Choice>
The xmlName
trait applied to the member of a list has no effect when
serializing a flattened list into a structure/union. For example, given the
following:
union Choice {
@xmlFlattened
flat: MyList
}
list MyList {
@xmlName("Hi")
member: String
}
The XML serialization of Choice
is:
<Choice>
<flat>example1</flat>
<flat>example2</flat>
<flat>example3</flat>
</Choice>
12.5.4. Map serialization#
Map shapes can be serialized as wrapped maps (the default behavior) or flattened maps.
12.5.4.1. Wrapped map serialization#
A wrapped map is serialized in an XML element where each value is
serialized in a nested element named entry
that contains a nested
key
and value
element. For example, given the following:
structure Foo {
values: MyMap
}
map MyMap {
key: String
value: String
}
The XML serialization of Foo
is:
<Foo>
<values>
<entry>
<key>example-key1</key>
<value>example1</value>
</entry>
<entry>
<key>example-key2</key>
<value>example2</value>
</entry>
</values>
</Foo>
The xmlName trait can be applied to the key and value members of a map to change the nested element names. For example, given the following:
structure Foo {
values: MyMap
}
map MyMap {
@xmlName("Name")
key: String
@xmlName("Setting")
value: String
}
The XML serialization of Foo
is:
<Foo>
<values>
<entry>
<Name>example-key1</Name>
<Setting>example1</Setting>
</entry>
<entry>
<Name>example-key2</Name>
<Setting>example2</Setting>
</entry>
</values>
</Foo>
12.5.4.2. Flattened map serialization#
The xmlFlattened trait can be used to flatten the members of map into a containing structure/union. For example, given the following:
structure Bar {
@xmlFlattened
flatMap: MyMap
}
map MyMap {
key: String
value: String
}
The XML serialization of Bar
is:
<Bar>
<flatMap>
<key>example-key1</key>
<value>example1</value>
</flatMap>
<flatMap>
<key>example-key2</key>
<value>example2</value>
</flatMap>
<flatMap>
<key>example-key3</key>
<value>example3</value>
</flatMap>
</Bar>
The xmlName
trait applied to the structure/union member is used to change
the name of the repeated XML element. For example, given the following:
union Choice {
@xmlFlattened
@xmlName("Hi")
flat: MyMap
}
map MyMap {
key: String
value: String
}
The XML serialization of Choice
is:
<Choice>
<Hi>
<key>example-key1</key>
<value>example1</value>
</Hi>
<Hi>
<key>example-key1</key>
<value>example1</value>
</Hi>
<Hi>
<key>example-key1</key>
<value>example1</value>
</Hi>
</Choice>
Unlike flattened lists and sets, flattened maps do honor xmlName
traits applied to the key or value members of the map. For example, given
the following:
union Choice {
@xmlFlattened
@xmlName("Hi")
flat: MyMap
}
map MyMap {
@xmlName("Name")
key: String
@xmlName("Setting")
value: String
}
The XML serialization of Choice
is:
<Choice>
<Hi>
<Name>example-key1</Name>
<Setting>example1</Setting>
</Hi>
<Hi>
<Name>example-key2</Name>
<Setting>example2</Setting>
</Hi>
<Hi>
<Name>example-key3</Name>
<Setting>example3</Setting>
</Hi>
</Choice>
12.5.5. xmlAttribute
trait#
- Summary
- Serializes an object property as an XML attribute rather than a nested XML element.
- Trait selector
structure > :test(member > :test(boolean, number, string, timestamp))
Structure members that target boolean, number, string, or timestamp
- Value type
- Annotation trait
- Conflicts with
- xmlNamespace trait
By default, the serialized XML attribute name is the same as the structure member name. For example, given the following:
structure MyStructure {
@xmlAttribute
foo: String
bar: String
}
The XML serialization is:
<MyStructure foo="example">
<bar>example</bar>
</MyStructure>
The serialized attribute name can be changed using the xmlName trait. Given the following:
structure MyStructure {
@xmlAttribute
@xmlName("NotFoo")
foo: String
}
The XML serialization is:
<MyStructure NotFoo="example"/>
12.5.6. xmlFlattened
trait#
- Summary
- Unwraps the values of a list or map into the containing structure.
- Trait selector
:is(structure, union) > :test(member > :test(list, map))
Member of a structure or union that targets a list or map
- Value type
- Annotation trait
Given the following:
structure Foo {
@xmlFlattened
flat: MyList
nested: MyList
}
list MyList {
member: String
}
The XML serialization of Foo
is:
<Foo>
<flat>example1</flat>
<flat>example2</flat>
<flat>example3</flat>
<nested>
<member>example1</member>
<member>example2</member>
<member>example3</member>
</nested>
</Foo>
Maps can be flattened into structures too. Given the following:
structure Foo {
@xmlFlattened
flat: MyMap
notFlat: MyMap
}
map MyMap {
key: String
value: String
}
The XML serialization is:
<Foo>
<flat>
<key>example-key1</key>
<value>example1</value>
</flat>
<flat>
<key>example-key2</key>
<value>example2</value>
</flat>
<notFlat>
<entry>
<key>example-key1</key>
<value>example1</value>
</entry>
<entry>
<key>example-key2</key>
<value>example2</value>
</entry>
</notFlat>
</Foo>
12.5.7. xmlName
trait#
- Summary
- Changes the serialized element or attribute name of a structure, union, or member.
- Trait selector
:is(structure, union, member)
A structure, union, or member
- Value type
string
value that MUST adhere to thesmithy:XmlName
ABNF production:XmlName =
XmlIdentifier
/ (XmlIdentifier
` ":"XmlIdentifier
`) XmlIdentifier = (ALPHA / "_") *(ALPHA / DIGIT / "-" / "_")
By default, structure properties are serialized in attributes or nested elements using the same name as the structure member name. Given the following:
structure MyStructure {
@xmlName("Foo")
foo: String
bar: String
}
The XML serialization is:
<MyStructure>
<Foo>example</Foo>
<bar>example</bar>
</MyStructure>
A namespace prefix can be inserted before the element name. Given the following
structure AnotherStructure {
@xmlName("hello:foo")
foo: String
}
The XML serialization is:
<AnotherStructure>
<hello:foo>example</hello:foo>
</AnotherStructure>
12.5.8. xmlNamespace
trait#
- Summary
- Adds an XML namespace to an XML element.
- Trait selector
:is(service, member, simpleType, list, map, structure, union)
Service, simple types, list, map, structure, or union
- Value type
structure
- Conflicts with
- xmlAttribute trait
The xmlNamespace
trait is a structure that contains the following members:
Property | Type | Description |
---|---|---|
uri | string value containing a valid URI |
Required. The namespace URI for scoping this XML element. |
prefix | string value |
The namespace prefix for elements from this namespace. Values
provides for prefix property MUST adhere to the
smithy:XmlIdentifier production. |
Given the following:
@xmlNamespace(uri: "http://foo.com")
structure MyStructure {
foo: String
bar: String
}
The XML serialization is:
<MyStructure xmlns="http://foo.com">
<foo>example</foo>
<bar>example</bar>
</MyStructure>
Given the following:
@xmlNamespace(uri: "http://foo.com", prefix: "baz")
structure MyStructure {
foo: String
@xmlName("baz:bar")
bar: String
}
The XML serialization is:
<MyStructure xmlns:baz="http://foo.com">
<foo>example</foo>
<baz:bar>example</baz:bar>
</MyStructure>