Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add httpQueryParams trait #735

Merged
merged 22 commits into from
Mar 15, 2021
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/source/1.0/spec/aws/aws-restjson1-protocol.rst
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,8 @@ that affect serialization:
prefixed HTTP headers.
* - :ref:`httpQuery <httpQuery-trait>`
- Binds a top-level input structure member to a query string parameter.
* - :ref:`httpQueryParams <httpQueryParams-trait>`
- Binds a map of key-value pairs to query string parameters.
* - :ref:`jsonName <jsonName-trait>`
- By default, the JSON property names used in serialized structures are
the same as a structure member name. The ``jsonName`` trait changes
Expand Down
2 changes: 2 additions & 0 deletions docs/source/1.0/spec/aws/aws-restxml-protocol.rst
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@ that affect serialization:
prefixed HTTP headers.
* - :ref:`httpQuery <httpQuery-trait>`
- Binds a top-level input structure member to a query string parameter.
* - :ref:`httpQueryParams <httpQueryParams-trait>`
- Binds a map of key-value pairs to query string parameters.
* - :ref:`xmlAttribute <xmlAttribute-trait>`
- Serializes an object property as an XML attribute rather than a nested
XML element.
Expand Down
85 changes: 76 additions & 9 deletions docs/source/1.0/spec/core/http-traits.rst
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,7 @@ Value type
Conflicts with
:ref:`httpLabel-trait`,
:ref:`httpQuery-trait`,
:ref:`httpQueryParams-trait`,
:ref:`httpPrefixHeaders-trait`,
:ref:`httpPayload-trait`,
:ref:`httpResponseCode-trait`
Expand Down Expand Up @@ -609,6 +610,7 @@ Value type
Conflicts with
:ref:`httpHeader-trait`,
:ref:`httpQuery-trait`,
:ref:`httpQueryParams-trait`,
:ref:`httpPrefixHeaders-trait`,
:ref:`httpPayload-trait`,
:ref:`httpResponseCode-trait`
Expand Down Expand Up @@ -693,7 +695,7 @@ Trait selector
Value type
Annotation trait.
Conflicts with
:ref:`httpLabel-trait`, :ref:`httpQuery-trait`,
:ref:`httpLabel-trait`, :ref:`httpQuery-trait`, :ref:`httpQueryParams-trait`,
:ref:`httpHeader-trait`, :ref:`httpPrefixHeaders-trait`,
:ref:`httpResponseCode-trait`
Structurally exclusive
Expand Down Expand Up @@ -739,7 +741,7 @@ be bound 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 :ref:`httpLabel-trait`, :ref:`httpHeader-trait`,
:ref:`httpPrefixHeaders-trait`, or :ref:`httpQuery-trait`.
:ref:`httpPrefixHeaders-trait`, :ref:`httpQueryParams-trait`, or :ref:`httpQuery-trait`.

If the ``httpPayload`` trait is present on the structure referenced by the
output of an operation or a structure targeted by the :ref:`error-trait`,
Expand Down Expand Up @@ -778,7 +780,7 @@ Value type
of 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
:ref:`httpLabel-trait`, :ref:`httpQuery-trait`,
:ref:`httpLabel-trait`, :ref:`httpQuery-trait`, :ref:`httpQueryParams-trait`,
:ref:`httpHeader-trait`, :ref:`httpPayload-trait`,
:ref:`httpResponseCode-trait`
Structurally exclusive
Expand Down Expand Up @@ -858,7 +860,7 @@ Value type
parameter. The query string parameter name MUST be case-sensitively unique
across all other members marked with the ``httpQuery`` trait.
Conflicts with
:ref:`httpLabel-trait`, :ref:`httpHeader-trait`,
:ref:`httpLabel-trait`, :ref:`httpHeader-trait`, :ref:`httpQueryParams-trait`,
:ref:`httpPrefixHeaders-trait`, :ref:`httpPayload-trait`,
:ref:`httpResponseCode-trait`

Expand Down Expand Up @@ -932,6 +934,69 @@ 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.

.. _httpQueryParams-trait:

``httpQueryParams`` trait
=========================

Summary
Binds a map of key-value pairs to query string parameters.
Trait selector
.. code-block:: none

structure > member
:test(> map > member[id|member=value] > :test(string, collection > member > string))

The ``httpQueryParams`` trait can be applied to ``structure`` members
that target a ``map`` of ``string``, or a ``map`` of ``list``/``set`` of
``string``.

Value type
Annotation trait.
Conflicts with
:ref:`httpLabel-trait`, :ref:`httpHeader-trait`, :ref:`httpQuery-trait`,
:ref:`httpPrefixHeaders-trait`, :ref:`httpPayload-trait`,
:ref:`httpResponseCode-trait`

The following example defines an operation that optionally sends the
target input map as query string parameters in an HTTP request:

.. tabs::

.. code-tab:: smithy

@readonly
@http(method: "GET", uri: "/things")
operation ListThings {
input: ListThingsInput,
output: ListThingsOutput, // omitted for brevity
}

structure ListThingsInput {
@httpQueryParams()
myParams: MapOfStrings,
}

map MapOfStrings {
key: String,
value: String
}

.. rubric:: ``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
:ref:`protocol-specific document <http-protocol-document-payloads>` sent in
the body of the response.

.. rubric:: Serialization rules

See the :ref:`httpQuery-trait` serialization rules that define how the keys and values of the
mtdowling marked this conversation as resolved.
Show resolved Hide resolved
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 :ref:`httpQuery-trait`, including the
requirement that reserved characters MUST be percent-encoded_.

.. _httpResponseCode-trait:

Expand All @@ -954,7 +1019,7 @@ Value type
Conflicts with
:ref:`httpLabel-trait`, :ref:`httpHeader-trait`,
:ref:`httpPrefixHeaders-trait`, :ref:`httpPayload-trait`,
:ref:`httpQuery-trait`
:ref:`httpQuery-trait`, :ref:`httpQueryParams-trait`,

.. rubric:: ``httpResponseCode`` use cases

Expand Down Expand Up @@ -1046,13 +1111,15 @@ parameters:
1. If the member has the ``httpLabel`` trait, expand the value into the URI.
2. If the member has the ``httpQuery`` trait, serialize the value into the
HTTP request as a query string parameter.
3. If the member has the ``httpHeader`` trait, serialize the value in an
3. If the member has the ``httpQueryParams`` trait, serialize the values into
the HTTP request as query string parameters.
4. If the member has the ``httpHeader`` trait, serialize the value in an
HTTP header using the value of the ``httpHeader`` trait.
4. If the member has the ``httpPrefixHeaders`` trait and the value is a map,
5. If the member has the ``httpPrefixHeaders`` trait and the value is a map,
serialize the map key value pairs as prefixed HTTP headers.
5. If the member has the ``httpPayload`` trait, serialize the value as the
6. If the member has the ``httpPayload`` trait, serialize the value as the
body of the request.
6. If the member has no bindings, serialize the key-value pair as part of a
7. 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.

The following steps are taken to serialize an HTTP response given a map of
Expand Down
130 changes: 129 additions & 1 deletion smithy-aws-protocol-tests/model/restJson1/http-query.smithy
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// This file defines test cases that test HTTP query string bindings.
// See: https://awslabs.github.io/smithy/1.0/spec/http.html#httpquery-trait
// See: https://awslabs.github.io/smithy/1.0/spec/http.html#httpquery-trait and
// https://awslabs.github.io/smithy/1.0/spec/http.html#httpqueryparams-trait

$version: "1.0"

Expand All @@ -13,6 +14,8 @@ use aws.protocoltests.shared#FooEnumList
use aws.protocoltests.shared#IntegerList
use aws.protocoltests.shared#IntegerSet
use aws.protocoltests.shared#StringList
use aws.protocoltests.shared#StringListMap
use aws.protocoltests.shared#StringMap
use aws.protocoltests.shared#StringSet
use aws.protocoltests.shared#TimestampList
use smithy.test#httpRequestTests
Expand Down Expand Up @@ -68,6 +71,8 @@ apply AllQueryStringTypes @httpRequestTests([
"EnumList=Foo",
"EnumList=Baz",
"EnumList=Bar",
"QueryParamsStringKeyA=Foo",
"QueryParamsStringKeyB=Bar",
],
params: {
queryString: "Hello there",
Expand All @@ -88,6 +93,10 @@ apply AllQueryStringTypes @httpRequestTests([
queryTimestampList: [1, 2, 3],
queryEnum: "Foo",
queryEnumList: ["Foo", "Baz", "Bar"],
queryParamsMapOfStrings: {
"QueryParamsStringKeyA": "Foo",
"QueryParamsStringKeyB": "Bar"
},
}
}
])
Expand Down Expand Up @@ -146,6 +155,9 @@ structure AllQueryStringTypesInput {

@httpQuery("EnumList")
queryEnumList: FooEnumList,

@httpQueryParams
queryParamsMapOfStrings: StringMap,
}

/// This example uses a constant query string parameters and a label.
Expand Down Expand Up @@ -365,3 +377,119 @@ structure QueryIdempotencyTokenAutoFillInput {
@idempotencyToken
token: String,
}

// Clients must make named query members take precedence over unnamed members
// and servers must use all query params in the unnamed map.
@http(uri: "/Precedence", method: "POST")
operation QueryPrecedence {
input: QueryPrecedenceInput
}

apply QueryPrecedence @httpRequestTests([
{
id: "RestJsonQueryPrecedence",
documentation: "Prefer named query parameters when serializing",
protocol: restJson1,
method: "POST",
uri: "/Precedence",
body: "",
queryParams: [
"bar=named",
"qux=alsoFromMap"
],
params: {
foo: "named",
baz: {
foo: "fromMap",
srchase marked this conversation as resolved.
Show resolved Hide resolved
qux: "alsoFromMap"
}
},
appliesTo: "client",
},
{
id: "RestJsonServersPutAllQueryParamsInMap",
documentation: "Servers put all query params in map",
protocol: restJson1,
method: "POST",
uri: "/Precedence",
body: "",
queryParams: [
"bar=named",
"qux=fromMap"
],
params: {
foo: "named",
baz: {
bar: "named",
qux: "fromMap"
}
},
appliesTo: "server",
}
])

structure QueryPrecedenceInput {
@httpQuery("bar")
foo: String,

@httpQueryParams
baz: StringMap
}

// httpQueryParams as Map of ListStrings
@http(uri: "/StringListMap", method: "POST")
operation QueryParamsAsStringListMap {
input: QueryParamsAsStringListMapInput
}

apply QueryParamsAsStringListMap @httpRequestTests([
{
id: "RestJsonQueryParamsStringListMap",
documentation: "Serialize query params from map of list strings",
protocol: restJson1,
method: "POST",
uri: "/StringListMap",
body: "",
queryParams: [
"corge=named",
"baz=bar",
"baz=qux"
],
params: {
qux: "named",
foo: {
"baz": ["bar", "qux"]
}
},
appliesTo: "client"
},
{
id: "RestJsonServersQueryParamsStringListMap",
documentation: "Servers put all query params in map",
protocol: restJson1,
method: "POST",
uri: "/StringListMap",
body: "",
queryParams: [
"corge=named",
"baz=bar",
"baz=qux"
],
params: {
qux: "named",
foo: {
"corge": ["named"],
"baz": ["bar", "qux"]
}
},
appliesTo: "server"
}
])

structure QueryParamsAsStringListMapInput {
@httpQuery("corge")
qux: String,

@httpQueryParams
foo: StringListMap
}
4 changes: 3 additions & 1 deletion smithy-aws-protocol-tests/model/restJson1/main.smithy
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,15 @@ service RestJson {
HttpRequestWithLabelsAndTimestampFormat,
HttpRequestWithGreedyLabelInPath,

// @httpQuery tests
// @httpQuery and @httpQueryParams tests
AllQueryStringTypes,
ConstantQueryString,
ConstantAndVariableQueryString,
IgnoreQueryParamsInResponse,
OmitsNullSerializesEmptyString,
QueryIdempotencyTokenAutoFill,
QueryPrecedence,
QueryParamsAsStringListMap,

// @httpPrefixHeaders tests
HttpPrefixHeaders,
Expand Down
Loading