-
Notifications
You must be signed in to change notification settings - Fork 6
HTTP Binding Traits
This wiki contains a mapping between Smithy HTTP binding traits and generated Ruby code.
To support all of these HTTP traits, Hearth provides the following components:
- HTTP request, response, and header objects
- HTTP transfer client (
Net::HTTP
) - HTTP request building utilities
Configures the HTTP bindings of an operation. The http
trait has 3 properties: method
, uri
, and code
.
@http(method: "PUT", uri: "/{bucketName}/{key}", code: 200)
See Smithy Documentation for a full breakdown of details.
This value represents the actual HTTP method. The method
is set onto the HTTP request object in the builder’s top level input structure for the operation.
http_req.http_method = 'PUT'
This value represents the URI pattern of the operation. The uri
is appended to the client’s endpoint.
For patterns without labels, it is appended to the path of the request.
http_req.append_path('/%<bucketName>s/%<key>s')
The uri
string will need its values substituted in with labels. Parameters used for the URI are considered required. The Kernel format method is used to substitute the values.
http_req.append_path(format('/%<bucketName>s/%<key>s',
bucketName: Hearth::HTTP.uri_escape(input[:bucket_name].to_s),
key: Hearth::HTTP.uri_escape(input[:key].to_s)
))
Query string literals do not contain labels, and are appended to the request.
Given the following Smithy operation:
@http(uri: "/someUri?foo=bar", method: "GET")
operation ConstantAndVariableQueryString {
...
}
The generated code is:
http_req.http_method = 'GET'
CGI.parse('foo=bar').each do |k,v|
v.each { |q_v| http_req.append_query_param(k, q_v) }
end
The Greedy label must be a string type. These labels are substituted similarly to other labels but "/" is not escaped.
This value represents the status code of a successful response. The value is code generated into the Client’s operation on the error parser. The error parser will explicitly check for this status code before determining if an error occurred.
stack.use(
Hearth::Middleware::Parse,
error_parser: Hearth::HTTP::ErrorParser.new(
error_module: Errors,
success_status_code: 200, errors: [Errors::UnprocessableEntityError])
data_parser: Parsers::UpdateHighScore
)
Defines an HTTP response code for an operation error.
@error("client")
@httpError(404)
structure MyError {}
This trait does not influence client code generation. Errors are handled by error codes and not status codes.
See Smithy Documentation for more details.
Binds a structure member to an HTTP header.
// Sent in the X-Foo header
structure MyOperationInputOutput {
@httpHeader("X-Foo")
foo: String
}
The header is set on the HTTP request object in the protocol builder.
http_req.headers['X-Foo'] = input[:foo] unless input[:foo].nil? || input[:foo].empty?
When the trait is applied to a list or set, the protocol builder will append the values to the header with commas.
class Operation
def self.build(http_req, input:)
...
http_req.headers['X-List'] = input[:foo].join(',')
end
end
For parsing, the value is split by using Hearth::Http::HeaderListParser
.
class Operation
def self.parse(http_resp)
data = Types::OperationOutput.new
unless http_resp.headers['X-List'].nil? || http_resp.headers['X-List'].empty?
data.foo = Hearth::Http::HeaderListParser.parse_string_list(http_resp.headers['X-List'])
end
...
end
end
String values with the @mediaType
trait are Base64 encoded. Timestamp values are serialized using http-date
unless the @timestampFormat
trait is applied.
See Smithy Documentation for more details.
Binds an operation input structure member to an HTTP label to be used as part of the URI.
structure MyOperationInput {
@required
@httpLabel
foo: String
}
The generated code is:
class MyOperation
def self.build(http_req, input:)
...
if input[:foo].to_s.empty?
raise ArgumentError, "HTTP label :foo cannot be empty."
end
http_req.append_path(format(
'/MyOperation/%<foo>s',
foo: Hearth::HTTP.uri_escape(input[:foo].to_s)
)
)
...
end
end
The required value is inserted into the URI. See the HTTP Trait - URI section.
See Smithy Documentation for more details.
Binds a single structure member to the body of an HTTP message.
structure MyOperationInputOutput {
@httpPayload
blob: Blob
}
When building the request, the blob is set to the request body.
class Operation
def self.build(http_req, input:)
...
http_req.body = StringIO.new(input[:blob] || '')
end
end
For parsing, the entire response body is set on the output structure.
class Operation
def self.parse(http_resp)
data = Types::OperationOutput.new
payload = http_resp.body.read
data.blob = payload unless payload.empty?
data
end
end
See Smithy Documentation for more details.
Binds a map of key-value pairs to prefixed HTTP headers.
structure MyOperationInput {
@httpPrefixHeaders("X-Foo-")
fooMap: StringMap,
}
map StringMap {
key: String,
value: String
}
For each key-value pair, the headers are set on the HTTP request object in the protocol builder. The generated code is:
# builders.rb
class MyOperation
def self.build(http_req, input:)
...
input[:foo_map]&.each do |key, value|
http_req.headers["X-Foo-#{key}"] = value unless value.nil? || value.empty?
end
end
end
See Smithy Documentation for more details.
Binds an operation input structure member to a query string parameter.
structure MyOperationInput {
@httpQuery("baz")
baz: String,
@httpQuery("maybeSet")
maybeSet: String,
}
The query parameter is appended to the HTTP request URI in the protocol builder. The generated code is:
class ConstantAndVariableQueryString
def self.build(http_req, input:)
...
params = Hearth::Query::ParamList.new
params['baz'] = input[:baz].to_s unless input[:baz].nil?
params['maybeSet'] = input[:maybe_set].to_s unless input[:maybe_set].nil?
end
end
See Smithy Documentation for more details.
Binds a map of key-value pairs to query string parameters.
structure ListThingsInput {
@httpQueryParams()
myParams: MapOfStrings,
@httpQuery("color")
color: String
}
map MapOfStrings {
key: String,
value: String
}
For an Input shape, the keys and values of my_params
are iterated and appended to the query string. Query params set this way are done before individual httpQuery
bindings, so that user data from the map does not wipe away necessary bindings. The generated code is:
class ListThings
def self.build(http_req, input:)
...
params = Hearth::Query::ParamList.new
unless input[:my_params].nil? || input[:my_params].empty?
input[:my_params].each do |k, v|
params[k] = v.to_s unless v.nil?
end
end
params['color'] = input[:color].to_s unless input[:color].nil?
http_req.append_query_param_list(params)
end
end
See Smithy Documentation for more details.
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.
structure HttpResponseCodeOutput {
@httpResponseCode
Status: Integer
}
The generated code is:
class HttpResponseCode
def self.parse(http_resp)
data = Types::HttpResponseCode.new
data.status = http_resp.status_code
data
end
end
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. The checksum is calculated and applied to the header in the request builders. The Hearth::Checksums
module is used for calculating checksums.
@httpChecksumRequired
operation PutSomething {
input: PutSomethingInput,
output: PutSomethingOutput
}
The generated code is:
# client.rb in some operation
stack.use(Hearth::HTTP::Middleware::ContentMD5)
See Smithy Documentation for more details.
Defines how a service supports cross-origin resource sharing. This trait does not influence client code generation.
See Smithy Documentation for more details.