14. HTTP bindings#
Smithy provides various HTTP binding traits that can be used by protocols to explicitly configure HTTP request and response messages.
The members of an operation input, output, and errors MUST NOT be bound to multiple HTTP message locations (e.g., a member cannot be bound to both a URI label and to a header). Only top-level members of an operation's input, output, and error structures are considered when serializing HTTP messages.
Important
Violating :rfc`HTTP specifications <7230>` or relying on poorly-supported HTTP functionality when defining HTTP bindings will limit interoperability and likely lead to undefined behavior across Smithy implementations. For example, avoid defining GET/DELETE requests with payloads, defining response payloads for operations with a 204/205 status, etc.
14.1. http
trait#
- Summary
- Configures the HTTP bindings of an operation.
- Trait selector
operation
- Value type
structure
The http
trait is a structure that supports the following members:
Property | Type | Description |
---|---|---|
method | string |
Required. The HTTP method of the operation. |
uri | string |
Required. The URI pattern of the operation. Labels defined in the URI pattern are used to bind operation input members to the URI. |
code | integer |
The HTTP status code of a successful response. Defaults to 200 if
not provided. The provided value SHOULD be between 100 and 599, and
it MUST be between 100 and 999. Status codes that do not allow a body
like 204 and 205 SHOULD bind all output members to locations other than
the body of the response. |
The following example defines an operation that uses HTTP bindings:
$version: "2"
namespace smithy.example
@idempotent
@http(method: "PUT", uri: "/{bucketName}/{key}", code: 200)
operation PutObject {
input: PutObjectInput
}
@input
structure PutObjectInput {
// Sent in the URI label named "key".
@required
@httpLabel
key: ObjectKey
// Sent in the URI label named "bucketName".
@required
@httpLabel
bucketName: String
// Sent in the X-Foo header
@httpHeader("X-Foo")
foo: String
// Sent in the query string as paramName
@httpQuery("paramName")
someValue: String
// Sent in the body
data: MyBlob
// Sent in the body
additional: String
}
14.1.1. method#
The method
property defines the HTTP method of the operation (e.g., "GET",
"PUT", "POST", "DELETE", "PATCH", etc). Smithy will use this value literally
and will perform no validation on the method. The method
value SHOULD
match the operation
production rule of RFC 7230#appendix-B. This
property does not influence the safety or idempotency characteristics of an
operation.
14.1.2. uri#
The uri
property defines the request-target of the operation in
origin-form as defined in RFC 7230#section-5.3.1. The URI is a simple
pattern that Smithy uses to match HTTP requests to operations and to bind
components of the request URI to fields in the operations's input structure.
Patterns consist of literal characters that MUST be matched in the
request URI and labels which are used to insert named components into the
request URI.
The resolved absolute URI of an operation is formed by combining the URI of
the operation with the endpoint of the service. (that is, the host and any
base URL of where the service is deployed). For example, given a service
endpoint of https://example.com/v1
and an operation pattern of
/myresource
, the resolved absolute URI of the operation is
https://example.com/v1/myresource
.
The value provided for the uri
property MUST adhere to the following
constraints:
- MUST start with "/".
- MUST NOT contain empty path segments (i.e., "//").
- MUST NOT contain a fragment (i.e., "#").
- MUST NOT end with "?".
- MUST NOT contain dot-segments (i.e., ".." and ".").
- MUST NOT case-sensitively conflict with other
http
/uri
properties.
@readonly
@http(method: "GET", uri: "/foo/{baz}")
operation GetService {
output: GetServiceOutput
}
14.1.2.1. Literal character sequences#
Patterns with no labels will match only requests containing the exact literal characters declared in the pattern, with the exception of trailing slashes which are always optional.
Given an endpoint of https://yourhost
and a pattern of /my/uri/path
:
Request URI | Matches? | Reason |
---|---|---|
https://yourhost/my/uri/path |
Yes | Exact match |
https://yourhost/my/uri/path/ |
Yes | Trailing slashes are ignored |
https://yourhost/my/uri |
No | Missing "/path" |
https://yourhost/my/uri/other |
No | Found "/other" instead of "/path" |
https://yourhost/my/uri/path/other |
No | Trailing segment "/other" |
14.1.2.2. Labels#
Patterns MAY contain label placeholders in the path. Labels consist of
label name characters surrounded by open and closed braces (i.e.,
"{label_name}" is a label and label_name
is the label name). The label
name corresponds to a top-level operation input structure member name. Every
label MUST have a corresponding input member, the input member MUST be marked
as required trait, the input member MUST have the httpLabel trait,
and the input member MUST reference a string, byte, short, integer, long,
float, double, bigDecimal, bigInteger, boolean, or timestamp. Labels only
capture path segments.
Labels MUST adhere to the following constraints:
- Labels MUST NOT appear in the query string.
- Each label MUST span an entire path segment (e.g., "/{foo}/bar" is valid, and "/{foo}bar" is invalid).
A pattern of /my/uri/{label}
will match any URI that begins with
/my/uri/
followed by any string not including an additional path segment
("/").
Given a pattern of /my/uri/{label}
and an endpoint of http://yourhost
:
Request URI | Matches? | Reason |
---|---|---|
http://yourhost/my/uri/foo |
Yes | "/my/uri/" matches and "foo" is captured as label . |
http://yourhost/my/uri/foo/ |
Yes | "/my/uri/" matches and "foo" is captured as label . The trailing
"/" is ignored. |
http://yourhost/my/uri/foo?query=bar |
Yes | "/my/uri/" matches and "foo" is captured as label . |
http://yourhost/my/uri/foo#bar |
Yes | "/my/uri/" matches and "foo" is captured as label . |
http://yourhost/my/uri/bar |
Yes | "/my/uri/" matches and "bar" is captured as label . |
http://yourhost/my/uri |
No | "/my/uri" matches but is missing a segment for label . |
http://yourhost/my/uri/foo/bar |
No | Found a trailing segment "/bar". |
Any number of labels can be included within a pattern, provided that they are
not immediately adjacent and do not have identical label names. Given a
pattern of /my/uri/{label1}/{label2}
and an endpoint of
http://yourhost
:
Request URI | Matches? | Reason |
---|---|---|
http://yourhost/my/uri/foo/bar |
Yes | Matches literal "/my/uri/", "foo" is captured as label1 , and "bar"
is captured as label2 . |
http://yourhost/my/uri/bar/baz/ |
Yes | Matches literal "/my/uri/", "bar" is captured as label1 , and "baz"
is captured as label2 . |
http://yourhost/my/uri/foo |
No | Matches literal "/my/uri/" but is missing a segment for label2 . |
http://yourhost/my/uri |
No | Matches literal "/my/uri/" but is missing segments for label1 and
label2 . |
http://yourhost/my/uri/foo/bar/baz |
No | Matches literal "/my/uri/", "bar" is captured as label1 , and "baz"
is captured as label2 , but contains an additional segment "baz". |
14.1.2.3. Query string literals#
Components of the query string can be matched literally in the URI pattern. The query string portion of a pattern MUST NOT contain labels.
Literals can be in the form of required keys without values. Given a pattern
of /path?requiredKey
and an endpoint of http://yourhost
:
Request URI | Matches? | Reason |
---|---|---|
http://yourhost/path?requiredKey |
Yes | Matches literal "/path" and contains a "requiredKey" query string parameter. |
http://yourhost/path?other&requiredKey |
Yes | Matches literal "/path" and contains a "requiredKey" query string parameter. |
http://yourhost/path |
No | Matches literal "/path" but does not contain the "requiredKey" query string parameter. |
http://yourhost/path? |
No | Matches literal "/path" but does not contain the "requiredKey" query string parameter. |
http://yourhost/path?otherKey |
No | Matches literal "/path" but does not contain the "requiredKey" query string parameter. |
Literal query string parameters can be matched with required key-value pairs.
Given a pattern of /path?requiredKey=requiredValue
and an endpoint of
http://yourhost
:
Request URI | Matches? | Reason |
---|---|---|
http://yourhost/path?requiredKey=requiredValue |
Yes | Matches literal "/path" and contains a query string parameter named "requiredKey" with a value of "requiredValue". |
http://yourhost/path?other&requiredKey=requiredValue |
Yes | Matches literal "/path" and contains a query string parameter named "requiredKey" with a value of "requiredValue". "other" is disregarded or bound to another input member. |
http://yourhost/path |
No | Does not contain a query string parameter named "requiredKey". |
http://yourhost/path? |
No | Does not contain a query string parameter named "requiredKey". |
http://yourhost/path?requiredKey=otherValue |
No | Contains a query string parameter named "requiredKey" but its value is not "requiredValue". |
14.1.2.4. Greedy labels#
A greedy label is a label suffixed with the +
qualifier that can be
used to match more than one path segment. At most, one greedy label may exist
in any path pattern, and if present, it MUST be the last label in the pattern.
Greedy labels MUST be bound to a string shape.
Given a pattern of /my/uri/{label+}
and an endpoint of http://yourhost
:
Request URI | Matches? | Reason |
---|---|---|
http://yourhost/my/uri/foo/bar |
Yes | Matches literal "/my/uri/", and "foo/bar" is captured as label . |
http://yourhost/my/uri/bar/baz/ |
Yes | Matches literal "/my/uri/", and "bar/baz" is captured as label . |
http://yourhost/my/uri/foo/bar/baz |
Yes | Matches literal "/my/uri/", and "foo/bar/baz" is captured as label . |
http://yourhost/my/uri |
No | Matches literal "/my/uri/" but does not contain a segment to match
label . |
Greedy matching can be used to capture the whole URI to a label, which results
in every request for a particular HTTP method being captured. For example, this
can be modeled with a pattern of /{label+}
.
Segments in the middle of a URI can be captured using greedy labels. Greedy
labels match greedily: they will match the longest possible string. Given a
pattern of /prefix/{label+}/suffix
and an endpoint of https://yourhost
:
Request URI | Matches? | Reason |
---|---|---|
http://yourhost/prefix/foo/suffix |
Yes | Matches literal "/prefix", captures "foo" in greedy label , and
matches literal "/suffix". |
http://yourhost/prefix/foo/bar/suffix |
Yes | Matches literal "/prefix", captures "foo/bar" in greedy label , and
matches literal "/suffix". |
http://yourhost/prefix/foo/bar |
No | Matches literal "/prefix", but does not contain the trailing literal "/suffix". |
http://yourhost/foo/bar/suffix |
No | Does not match the literal "/prefix". |
http://yourhost/prefix/foo/suffix/bar/suffix |
Yes | Matches literal "/prefix", captures "foo/suffix/bar" in greedy
label , and matches literal "/suffix". |
http://yourhost/prefix/suffix |
No | Matches literal "/prefix", matches literal "/suffix", but does not
contain a segment to match label . |
14.1.2.5. Pattern Validation and Conflict Avoidance#
Smithy validates the patterns within a service against each other to ensure that no two patterns conflict with each other for the same HTTP method. To prevent ambiguity when matching requests for different operations, the following rules are in place:
- All labels MUST be delimited by '/' characters.
/{foo}/{bar}
is legal/{foo}{bar}
is illegal/{foo}bar/{bar}
is illegal/{foo}a{bar}
is illegal
- At most, one greedy label MAY exist per pattern.
/{foo}/{bar+}
is legal/{foo+}/{bar+}
is illegal
- If present, a greedy pattern MUST be the last label in a pattern.
/{foo}/{bar+}
is legal/{foo+}/{bar}
is illegal
- Patterns MUST NOT be equivalent if they share a host.
- Pattern
/foo/bar
and/foo/bar
conflict. - Pattern
/foo/{bar}
and/foo/{baz}
conflict regardless of any constraint traits on the label members.
- Pattern
- A label and a literal SHOULD NOT both occupy the same segment in patterns
which are equivalent to that point if they share a host.
/foo/bar/{baz}
and/foo/baz/bam
can coexist./foo/bar
and/foo/{baz}/bam
cannot coexist unless pattern traits prevent{baz}
from evaluating tobar
because the label occupies the same segment of another pattern with the same prefix.
- A query string literal with no value and a query string literal with an
empty value are considered equivalent. For example,
/foo?baz
and/foo?baz=
are considered the same route. - Patterns MAY conflict if the operations use different hosts. Different hosts
can be configured using the endpoint trait's
hostPrefix
property./foo/bar
and/foo/{baz}/bam
can coexist if one operation has no endpoint trait and the other specifiesfoo.
as thehostPrefix
./foo/bar
and/foo/{baz}/bam
can coexist if one operation specifiesfoo.
as thehostPrefix
and the other specifiesbar.
as thehostPrefix
.
14.2. httpError
trait#
- Summary
- Defines an HTTP response code for an operation error.
- Trait selector
structure[trait|error]
The
httpError
trait can only be applied to structure shapes that also have the error trait.- Value type
integer
value representing the HTTP response status code (for example,404
).
The following example defines an error with an HTTP status code of 404
.
@error("client")
@httpError(404)
structure MyError {}
Default HTTP status codes
The httpError
trait is used to set a custom HTTP response status code.
By default, error structures with no httpError
trait use the default
HTTP status code of the error trait.
400
is used for "client" errors500
is used for "server" errors
14.3. httpHeader
trait#
- Summary
- Binds a structure member to an HTTP header.
- Trait selector
structure > :test(member > :test(boolean, number, string, timestamp, list > member > :test(boolean, number, string, timestamp)))
The
httpHeader
trait can be applied tostructure
members that target aboolean
,number
,string
, ortimestamp
; or astructure
member that targets a list of these types.- Value type
string
value defining a valid HTTP header field name according to section 3.2 of RFC7230. The value MUST NOT be empty and MUST be case-insensitively unique across all other members of the structure.- Conflicts with
- httpLabel trait, httpQuery trait, httpQueryParams trait, httpPrefixHeaders trait, httpPayload trait, httpResponseCode trait
httpHeader
serialization rules:
- When a list shape is targeted, each member of the shape is serialized as a separate HTTP header either by concatenating the values with a comma on a single line or by serializing each header value on its own line.
boolean
values are serialized astrue
orfalse
.string
values with a mediaType trait are always base64 encoded.timestamp
values are serialized using thehttp-date
format by default, as defined in theIMF-fixdate
production of RFC 7231#section-7.1.1.1. The timestampFormat trait MAY be used to use a custom serialization format.
Do not put too much data in HTTP headers
While there is no limit placed on the length of an HTTP header field, many HTTP client and server implementations enforce limits in practice. Carefully consider the maximum allowed length of each member that is bound to an HTTP header.
14.3.1. Restricted HTTP headers#
Various HTTP headers are highly discouraged for the httpHeader
and
httpPrefixHeaders
traits.
Header | Reason |
---|---|
Authorization | This header should be populated by authentication traits. |
Connection | This is controlled at a lower level by the HTTP client or server. |
Content-Length | HTTP clients and servers are responsible for providing a Content-Length header. |
Expect | This is controlled at a lower level by the HTTP client. |
Host | The Host header is controlled by the HTTP client, not the model. |
Max-Forwards | This is controlled at a lower level by the HTTP client. |
Proxy-Authenticate | This header should be populated by authentication traits. |
Server | The Server header is controlled by the HTTP server, not the model. |
TE | This is controlled at a lower level by the HTTP client and server. |
Trailer | This is controlled at a lower level by the HTTP client and server. |
Transfer-Encoding | This is controlled at a lower level by the HTTP client and server. |
Upgrade | This is controlled at a lower level by the HTTP server. |
User-Agent | Setting a User-Agent is the responsibility of an HTTP client. |
WWW-Authenticate | This header should be populated by authentication traits. |
X-Forwarded-For | X-Forwarded-For is an implementation detail of HTTP that does not need to be modeled. |
14.4. httpLabel
trait#
- Summary
- Binds an operation input structure member to an HTTP label so that it is used as part of an HTTP request URI.
- Trait selector
structure > member[trait|required] :test(> :test(string, number, boolean, timestamp))
The
httpLabel
trait can be applied tostructure
members marked with the required trait that target astring
,number
,boolean
, ortimestamp
.- Value type
- Annotation trait.
- Conflicts with
- httpHeader trait, httpQuery trait, httpQueryParams trait, httpPrefixHeaders trait, httpPayload trait, httpResponseCode trait
The following example defines an operation that send an HTTP label named
foo
as part of the URI of an HTTP request:
$version: "2"
namespace smithy.example
@readonly
@http(method: "GET", uri: "/{foo}")
operation GetStatus {
input: GetStatusInput
output: GetStatusOutput
}
@input
structure GetStatusInput {
@required
@httpLabel
foo: String
}
Relationship to http trait
When a structure is used as the input of an operation, any member of the
structure with the httpLabel
trait MUST have a corresponding
URI label with the same name as the member.
httpLabel
traits are ignored when serializing operation output or errors.
Applying the httpLabel
trait to members
httpLabel
can only be applied to structure members that are marked as required.- If the corresponding URI label in the operation is not greedy, then the
httpLabel
trait MUST target a member that targets astring
,byte
,short
,integer
,long
,float
,double
,bigDecimal
,bigInteger
,boolean
, ortimestamp
. - If the corresponding URI label in the operation is greedy, then the
httpLabel
trait MUST target a member that targets astring
shape.
httpLabel
serialization rules:
boolean
values are serialized astrue
orfalse
.timestamp
values are serialized as an RFC 3339 string by default (for example,1985-04-12T23:20:50.52Z
, and with percent-encoding,1985-04-12T23%3A20%3A50.52Z
). The timestampFormat trait MAY be used to use a custom serialization format.- Characters not defined as unreserved by RFC 3986 section 2.3
MUST be percent-encoded. That is, all characters except for
alphanumerics and
-._~
. - However, if the label is greedy, then "/" MUST NOT be percent-encoded because greedy labels are meant to span multiple path segments.
httpLabel
is only used on input
httpLabel
is ignored when resolving the HTTP bindings of an operation's
output or an error. This means that if a structure that contains members
marked with the httpLabel
trait is used as the top-level output structure
of an operation, then those members are sent as part of the
protocol-specific document sent in
the body of the response.
14.5. httpPayload
trait#
- Summary
- Binds a single structure member to the body of an HTTP message.
- Trait selector
structure > :test(member > :test(string, blob, structure, union, document, list, map))
The
httpPayload
trait can be applied tostructure
members that target astring
,blob
,structure
,union
,document
,map
, orlist
.- Value type
- Annotation trait.
- Conflicts with
- httpLabel trait, httpQuery trait, httpQueryParams trait, httpHeader trait, httpPrefixHeaders trait, httpResponseCode trait
- Structurally exclusive
- Only a single structure member can be bound to
httpPayload
.
The following example defines an operation that returns a blob
of binary
data in a response:
$version: "2"
namespace smithy.example
@readonly
@http(method: "GET", uri: "/random-binary-data")
operation GetRandomBinaryData {
input: GetRandomBinaryDataInput
output: GetRandomBinaryDataOutput
}
@input
structure GetRandomBinaryDataInput {}
@output
structure GetRandomBinaryDataOutput {
@required
@httpHeader("Content-Type")
contentType: String
@httpPayload
content: Blob
}
Protocol-specific document payloads
By default, all structure members that are not bound as part of the HTTP
message are serialized in a protocol-specific document sent in the body of
the message (e.g., a JSON object). The httpPayload
trait can be used to
bind a single top-level operation input, output, or error structure member to
the body of the HTTP message. Multiple members of the same structure MUST NOT
be bound to httpPayload
.
Binding members to httpPayload
If the httpPayload
trait is present on the structure referenced by the
input of an operation, then all other structure members MUST be bound with
the httpLabel trait, httpHeader trait,
httpPrefixHeaders trait, httpQueryParams trait, or httpQuery trait.
If the httpPayload
trait is present on the structure referenced by the
output of an operation or a structure targeted by the error trait,
then all other structure members MUST be bound to a httpHeader trait
or httpPrefixHeaders trait.
Serialization rules
- When a string or blob member is referenced, the raw value is serialized as the body of the message.
- When a structure, union, list, map, or document type is targeted, the shape value is serialized as a protocol-specific document that is sent as the body of the message.
14.6. httpPrefixHeaders
trait#
- Summary
- Binds a map of key-value pairs to prefixed HTTP headers.
- Trait selector
structure > member :test(> map :not([trait|sparse]) > member[id|member=value] > string)
The
httpPrefixHeaders
trait can be applied tostructure
members that target amap
ofstring
. The targeted map MUST NOT be marked with the sparse trait.- Value type
string
value that defines the prefix to prepend to each header field name stored in the targeted map member. For example, given a prefix value of "X-Amz-Meta-" and a map key entry of "Baz", the resulting header field name serialized in the message is "X-Amz-Meta-Baz".- Conflicts with
- httpLabel trait, httpQuery trait, httpQueryParams trait, httpHeader trait, httpPayload trait, httpResponseCode trait
- Structurally exclusive
- Only a single structure member can be bound to
httpPrefixHeaders
.
Given the following Smithy model:
@readonly
@http(method: "GET", uri: "/myOperation")
operation MyOperation {
input: MyOperationInput
}
@input
structure MyOperationInput {
@httpPrefixHeaders("X-Foo-")
headers: StringMap
}
map StringMap {
key: String
value: String
}
And given the following input to MyOperation
:
{
"headers": {
"first": "hi",
"second": "there"
}
}
An example HTTP request would be serialized as:
GET /myOperation
Host: <server>
X-Foo-first: hi
X-Foo-second: there
Disambiguation of httpPrefixHeaders
In order to differentiate httpPrefixHeaders
from other headers, when
httpPrefixHeaders
are used, no other httpHeader trait bindings can
start with the same prefix provided in httpPrefixHeaders
trait. If
httpPrefixHeaders
is set to an empty string, then no other members can be
bound to headers
.
14.7. httpQuery
trait#
- Summary
- Binds an operation input structure member to a query string parameter.
- Trait selector
structure > member :test(> :test(string, number, boolean, timestamp), > list > member > :test(string, number, boolean, timestamp))
The
httpQuery
trait can be applied tostructure
members that target astring
,number
,boolean
, ortimestamp
; or alist
of these types.- Value type
- A non-empty
string
value that defines the name of the query string parameter. The query string parameter name MUST be case-sensitively unique across all other members marked with thehttpQuery
trait. - Conflicts with
- httpLabel trait, httpHeader trait, httpQueryParams trait, httpPrefixHeaders trait, httpPayload trait, httpResponseCode trait
The following example defines an operation that optionally sends the
color
, shape
, and size
query string parameters in an HTTP
request:
@readonly
@http(method: "GET", uri: "/things")
operation ListThings {
input: ListThingsInput
output: ListThingsOutput, // omitted for brevity
}
@input
structure ListThingsInput {
@httpQuery("color")
color: String
@httpQuery("shape")
shape: String
@httpQuery("size")
size: Integer
}
Serialization rules
- "&" is used to separate query string parameter key-value pairs.
- "=" is used to separate query string parameter names from values.
- Characters not defined as unreserved by RFC 3986 section 2.3
MUST be percent-encoded. That is, all characters except for
alphanumerics and
-._~
. boolean
values are serialized astrue
orfalse
.timestamp
values are serialized as an RFC 3339date-time
string by default (for example,1985-04-12T23:20:50.52Z
, and with percent-encoding,1985-04-12T23%3A20%3A50.52Z
). The timestampFormat trait MAY be used to use a custom serialization format.- List members are serialized by adding multiple
query string parameters to the query string using the same name. For
example, given a member bound to
foo
that targets a list of strings with a value of["a", "b"]
, the value is serialized in the query string asfoo=a&foo=b
. - When deserializing, server implementations SHOULD use the first encountered
value in the query string for non-list members. For example, given a
member bound to
foo
that targets a string and a query string offoo=a&foo=b
, the deserialized value offoo
should bea
.
Important
Percent-encoding is an implementation detail
The encoding and serialization rules of shapes defined in a Smithy model are implementation details. When designing clients, servers, and other kinds of software based on Smithy models, the format in which the value of a member is serialized SHOULD NOT be a concern of the end-user. As such, members bound to the query string MUST be automatically percent-encoded when serializing HTTP requests and automatically percent-decoded when deserializing HTTP requests.
httpQuery
is only used on input
httpQuery
is ignored when resolving the HTTP bindings of an operation's
output or an error. This means that if a structure that contains members
marked with the httpQuery
trait is used as the top-level output structure
of an operation, then those members are sent as part of the
protocol-specific document sent in
the body of the response.
Do not put too much data in the query string
While there is no limit placed on the length of an HTTP request line, many HTTP client and server implementations enforce limits in practice. Carefully consider the maximum allowed length of each member that is bound to an HTTP query string or path.
14.8. httpQueryParams
trait#
- Summary
- Binds a map of key-value pairs to query string parameters.
- Trait selector
structure > member :test(> map > member[id|member=value] > :test(string, list > member > string))
The
httpQueryParams
trait can be applied tostructure
members that target amap
ofstring
, or amap
oflist
ofstring
.- Value type
- Annotation trait.
- Conflicts with
- httpLabel trait, httpHeader trait, httpQuery trait, httpPrefixHeaders trait, httpPayload trait, httpResponseCode trait
- Structurally exclusive
- Only a single structure member can be bound to
httpQueryParams
.
The following example defines an operation that optionally sends the target input map as query string parameters in an HTTP request:
@readonly
@http(method: "GET", uri: "/things")
operation ListThings {
input: ListThingsInput
output: ListThingsOutput, // omitted for brevity
}
@input
structure ListThingsInput {
@httpQueryParams()
myParams: MapOfStrings
}
map MapOfStrings {
key: String
value: String
}
httpQueryParams
is only used on input
httpQueryParams
is ignored when resolving the HTTP bindings of an operation's
output or an error. This means that if a structure that contains members
marked with the httpQueryParams
trait is used as the top-level output structure
of an operation, then those members are sent as part of the
protocol-specific document sent in
the body of the response.
Serialization rules
See the httpQuery trait serialization rules that define how the keys and values of the target map will be serialized in the request query string. Key-value pairs in the target map are treated like they were explicitly bound using the httpQuery trait, including the requirement that reserved characters MUST be percent-encoded.
When servers deserialize the query string into a map
of string
, they SHOULD take the
first encountered value for each key. Since this rule applies to all future query string
values, and changing from a map
of string
to a map
of list
of string
is
backwards-incompatible, care should be taken to use map
of string
only when it is
certain that multiple values for any query string will never be meaningful for the operation.
If a member with the httpQueryParams
trait and a member with the httpQuery trait
conflict, clients MUST use the value set by the member with the httpQuery trait and
disregard the value set by httpQueryParams
. For example, given the following model:
@http(method: "POST", uri: "/things")
operation PutThing {
input: PutThingInput
}
@input
structure PutThingInput {
@httpQuery
@required
thingId: String,
@httpQueryParams
tags: MapOfStrings
}
map MapOfStrings {
key: String
value: String
}
And given the following input to PutThing
:
{
"thingId": "realId",
"tags": {
"thingId": "fakeId",
"otherTag": "value"
}
}
An example HTTP request would be serialized as:
POST /things?thingId=realId&otherTag=value
Host: <server>
When deserializing HTTP request query string parameters into members with the
httpQueryParams
trait, servers MUST treat all values as strings and produce
empty string values for keys which do not have values specified. For example,
given the following model:
@http(method: "POST", uri: "/things")
operation PostThing {
input: PostThingInput
}
structure PostThingInput {
@httpQueryParams
tags: MapOfStrings
}
map MapOfStrings {
key: String
value: String
}
And the following HTTP request:
POST /things?thingId=realId&otherTag=true&anotherTag&lastTag=
A server should deserialize the following input structure:
{
"tags": {
"thingId": "realId",
"otherTag": "true",
"anotherTag": "",
"lastTag": ""
}
}
14.9. httpResponseCode
trait#
- Summary
- Binds a structure member to the HTTP response status code so that an
HTTP response status code can be set dynamically at runtime to something
other than
code
of the http trait. - Trait selector
structure :not([trait|input]) > member :test(> integer)
The
httpResponseCode
trait can be applied tostructure
members that target aninteger
within anystructure
that has noinput
trait applied.- Value type
- Annotation trait.
- Conflicts with
- httpLabel trait, httpHeader trait, httpPrefixHeaders trait, httpPayload trait, httpQuery trait, httpQueryParams trait,
httpResponseCode
use cases
Marking an output structure
member with this trait can be used to provide
different response codes for an operation, like a 200 or 201 for a PUT
operation. If this member isn't provided, server implementations MUST default
to the code set by the http trait.
httpResponseCode
is only used on output
httpResponseCode
is ignored when resolving the HTTP bindings of any
structure except an operation's output structure. This means that if a
structure that contains members marked with the httpResponseCode
trait
is not used as an output structure of an operation, then those members are
sent as part of the protocol-specific document
sent in the body of the request.
14.10. cors
trait#
- Summary
- Defines how a service supports cross-origin resource sharing
- Trait selector
service
- Value type
structure
The cors
trait is a structure that supports the following members:
Property | Type | Description |
---|---|---|
origin | string |
The origin from which browser script-originating requests will be
allowed. Defaults to * . |
maxAge | integer |
The maximum number of seconds for which browsers are allowed to cache
the results of a preflight OPTIONS request. Defaults to 600 , the
maximum age permitted by several browsers. Set to -1 to disable
caching entirely. |
additionalAllowedHeaders | list<string> |
The names of headers that should be included in the
Access-Control-Allow-Headers header in responses to preflight
OPTIONS requests. This list will be used in addition to the names of
all request headers bound to an input data member via the
httpHeader trait, as well as any headers required by the protocol
or authentication scheme. |
additionalExposedHeaders | list<string> |
The names of headers that should be included in the
Access-Control-Expose-Headers header in all responses sent by the
service. This list will be used in addition to the names of all request
headers bound to an output data member via the httpHeader trait,
as well as any headers required by the protocol or authentication
scheme. |
Adding a cors
trait with its value set to an empty object enables
cross-origin resource sharing for all origins and allows browser scripts access
to all headers to which data is bound in the model, as well as any headers used
by the protocol and authentication scheme.
The default settings are not compatible with certain authentication schemes
(e.g., http-basic
) that rely on browser-managed credentials. Services using
such authentication schemes MUST designate a single origin from which
cross-origin, credentialed requests will be accepted.
14.11. httpChecksumRequired
trait#
- Summary
- Indicates that an operation requires a checksum in its HTTP request. By default, the checksum used for a service is a MD5 checksum passed in the Content-MD5 header.
- Trait selector
operation
- Value type
- Annotation trait.
- See
- RFC 1864
@httpChecksumRequired
operation PutSomething {
input: PutSomethingInput
output: PutSomethingOutput
}
14.12. Serializing HTTP messages#
The following steps are taken to serialize an HTTP request given a map of parameters:
- Set the HTTP method to the
method
property of the http trait of the operation. - Set the URI of the HTTP request to the
uri
property of thehttp
trait. - Iterate over all of the key-value pairs of the parameters and find the
corresponding structure member by name:
- If the member has the
httpLabel
trait, expand the value into the URI. - If the member has the
httpQuery
trait, serialize the value into the HTTP request as a query string parameter. - If the member has the
httpQueryParams
trait, serialize the values into the HTTP request as query string parameters. - If the member has the
httpHeader
trait, serialize the value in an HTTP header using the value of thehttpHeader
trait. - If the member has the
httpPrefixHeaders
trait and the value is a map, serialize the map key value pairs as prefixed HTTP headers. - If the member has the
httpPayload
trait, serialize the value as the body of the request. - If the member has no bindings, serialize the key-value pair as part of a protocol-specific document sent in the body of the request.
- If the member has the
The following steps are taken to serialize an HTTP response given a map of parameters:
- If serializing the output of an operation, set the status code of the
response to the
code
property of the http trait. - If serializing an error and the httpError trait is present, set the status code of the response to its value. Otherwise, set the status code to 400 if the error trait is "client" or to 500 if the error trait is "server".
- Iterate over all of the key-value pairs of the parameters and find the
corresponding structure member by name:
- If the member has the
httpHeader
trait, serialize the value in an HTTP header using the value of thehttpHeader
trait. - If the member has the
httpPrefixHeaders
trait and the value is a map, serialize the map key value pairs as prefixed HTTP headers. - If the member has the
httpPayload
trait, serialize the value as the body of the response. - If the member has no bindings, serialize the key-value pair as part of a protocol-specific document sent in the body of the response.
- If the member has the
14.13. Event streams#
When using event streams and HTTP bindings, the httpPayload trait MUST be applied to any input or output member that targets a shape marked with the streaming trait.
The following example defines an operation that uses an input event stream and HTTP bindings:
$version: "2"
namespace smithy.example
@http(method: "POST", uri: "/messages")
operation PublishMessages {
input: PublishMessagesInput
}
@input
structure PublishMessagesInput {
@httpPayload
messages: MessageStream
}
@streaming
union MessageStream {
message: Message
}
structure Message {
message: String
}
The following is invalid because the operation has the http
trait
and an input member is marked with the streaming
trait but not
marked with the httpPayload
trait:
$version: "2"
namespace smithy.example
@http(method: "POST", uri: "/messages")
operation InvalidOperation {
input: InvalidOperationInput
}
@input
structure InvalidOperationInput {
invalid: MessageStream // <-- Missing the @httpPayload trait
}
@streaming
union MessageStream {
message: Message
}
structure Message {
message: String
}