RFC: Service-specific middleware
Status: Implemented
For a summarized list of proposed changes, see the Changes Checklist section.
Currently, all services use a centralized AwsMiddleware
that is defined in the (poorly named) aws-hyper
crate. This
poses a number of long term risks and limitations:
- When creating a Smithy Client directly for a given service, customers are forced to implicitly assume that the
service uses stock
AwsMiddleware
. This prevents us from ever changing the middleware stack for a service in the future. - It is impossible / impractical in the current situation to alter the middleware stack for a given service. For services like S3, we will almost certainly want to customize endpoint middleware in a way that is currently impossible.
In light of these limitations, this RFC proposes moving middleware into each generated service. aws-inlineable
will be
used to host and test the middleware stack. Each service will then define a public middleware
module containing their
middleware stack.
Terminology
- Middleware: A tower layer that augments
operation::Request -> operation::Response
for things like signing and endpoint resolution. - Aws Middleware: A specific middleware stack that meets the requirements for AWS services.
- Smithy Client: A
aws_smithy_client::Client<C, M, R>
struct that is responsible for gluing together the connector, middleware, and retry policy. This is not generated and lives in theaws-smithy-client
crate. - Fluent Client: A code-generated
Client<C, M, R>
that has methods for each service operation on it. A fluent builder is generated alongside it to make construction easier. - AWS Client: A specialized Fluent Client that defaults to using a
DynConnector
,AwsMiddleware
, andStandard
retry policy. - Shared Config: An
aws_types::Config
struct that is responsible for storing shared configuration data that is used across all services. This is not generated and lives in theaws-types
crate. - Service-specific Config: A code-generated
Config
that has methods for setting service-specific configuration. EachConfig
is defined in theconfig
module of its parent service. For example, the S3-specific config struct isuse
able fromaws_sdk_s3::config::Config
and re-exported asaws_sdk_s3::Config
.
Detailed Design
Currently, AwsMiddleware
is defined in aws-hyper
. As part of this change, an aws-inlineable
dependency will be
added containing code that is largely identical. This will be exposed in a public middleware
module in all generated
services. At some future point, we could even expose a baseline set of default middleware for whitelabel Smithy services
to make them easier to use out-of-the-box.
The ClientGenerics
parameter of the AwsFluentClientGenerator
will be updated to become a RuntimeType
, enabling
loading the type directly. This has the advantage of making it fairly easy to do per-service middleware stacks since we
can easily configure AwsFluentClientGenerator
to insert different types based on the service id.
Changes Checklist
- Move aws-hyper into aws-inlineable. Update comments as needed including with a usage example about how customers can augment it.
-
Refactor
ClientGenerics
to contain a RuntimeType instead of a string and configure. UpdateAwsFluentClientDecorator
. -
Update all code and examples that use
aws-hyper
to use service-specific middleware. - Push an updated README to aws-hyper deprecating the package, explaining what happened. Do not yank previous versions since those will be relied on by older SDK versions.