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 support document type shapes. A service that uses such a protocol MUST NOT contain any document 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:

  1. Use the timestampFormat trait of the member, if present.
  2. Use the timestampFormat trait of the shape, if present.
  3. 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 value for binary:

<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 1578255206 for date:

<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 the smithy: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>

12.6. See also#