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
Provide one class/interface for all clients #5856
Comments
What parts of the client does your middleware interact with? Why not use a structural subset?
|
We own many different middleware integrations for different purpose. For example extracting logs/metrics from all aws-sdk calls. I did not know that
the imports changed over time for example from |
We do not have a base type because no particular behavior is guaranteed for a client based on the Smithy code generators, despite there being things that for practical purposes exist on all clients. Below is an outline of what I recommend, which is to declare any required types of your middleware application function on that function's signature. import type { LambdaClient } from "@aws-sdk/client-lambda";
import type { S3Client } from "@aws-sdk/client-s3";
import type { AwsCredentialIdentityProvider, Client } from "@smithy/types"; // same as Client @aws-sdk/types.
/**
* The most generic client is one that has no restrictions on input/output,
* and no requirements for the resolved config.
*/
type BaseClient = Client<any, any, {}>;
const s3 = null as any as S3Client;
const lambda = null as any as LambdaClient;
/**
* SDK clients are assignable to this most generic client.
*/
let generic: BaseClient = s3;
generic = lambda;
/**
* However, I would guess that you're looking for a configuration subset that is guaranteed for
* all clients.
*
* We have not established this type because while Smithy code generation does generate certain
* config fields for (in practice) all clients like systemClockOffset or requestHandler, it does so explicitly
* for each client rather than to meet any particular base type.
*
* Therefore, there are no particular fields that are in fact guaranteed for all potential
* clients.
*/
/**
* In order to create a middleware applicator, you should specify exactly what you require.
*/
type MinimalGenericClient = BaseClient & {
config: {
credentials: AwsCredentialIdentityProvider;
systemClockOffset: number;
};
};
async function addMiddleware(client: MinimalGenericClient) {
console.log(client.config.systemClockOffset);
await client.config.credentials();
client.middlewareStack.add(null as any, null as any);
client.middlewareStack.addRelativeTo(null as any, null as any);
}
addMiddleware(s3);
addMiddleware(lambda);
/**
* For handling changed internals, discern with union.
*/
type ImplementationAlphaIsAvailable = {
config: {
propertyA: AwsCredentialIdentityProvider; // pretend this only exists on some SDK versions.
};
};
type ImplementationBetaIsAvailable = {
config: {
propertyB: AwsCredentialIdentityProvider; // pretend this only exists on other SDK versions.
};
};
type ClientWithDivergentImplementations = BaseClient & (ImplementationAlphaIsAvailable | ImplementationBetaIsAvailable);
/**
* Middleware applicator handling potentially divergent SDK config implementations.
*/
async function addMiddlewareChecked(client: ClientWithDivergentImplementations) {
if (hasImplementationAlpha(client)) {
await client.config.propertyA();
client.middlewareStack.add(null as any, null as any);
} else {
await client.config.propertyB();
client.middlewareStack.add(null as any, null as any);
}
}
function hasImplementationAlpha(client: any): client is ImplementationAlphaIsAvailable {
return !!client?.config?.propertyA;
} |
Thanks for this suggestion. That's a good temporary solution but I don't think this should be hard-coded by aws-sdk consumers. It might not be possible to provide something for generic smithy generated clients but at least for aws-sdk clients the list of config values and middleware stack is known (example: https://github.com/aws/aws-sdk-js-v3/blame/main/clients/client-appconfig/src/AppConfigClient.ts#L605-L628 ). Why is it not possible to ship in
That does not solve the full problem because for example moving |
In what way is middleware not working across the package migration of smithy-client? |
We cannot use |
Hi @workeitel - checking in here if you still have any other questions we can answer. |
The problem is not really resolved. For example a middleware accessing the retry strategy similar to:
would again not work as I understand for a generic smithy client that's not possible but aws-sdk clients are more uniform. I understand you can't guarantee the types won't change between releases but at least the import parts should really stay as otherwise consumers always need a code change. |
Describe the feature
Passing aws clients around in TypeScript requires knowing their type. This is easy for one client like
DynamoDB
but becomes impossible for any client. The fact that there is no single type makes for example middleware helpers difficult.Use Case
Writing a middleware typically requires knowing the TypeScript type:
But typing the
addMyMiddleware
is difficult as the type of an AWS Client is difficult to describe:This is in particular bad as the types change between aws-sdk versions. For example
Client
was originally part of@aws-sdk/smithy-client
but changed between versions to@smithy/smithy-client
. Providing aaddMyMiddleware
method which works with all aws-sdk-js-v3 versions makes typing impossible.Proposed Solution
I want to have one class/interface which describes all aws-sdk clients such as:
This new type is stable across aws-sdk versions so the middleware does not need to be modified on aws-sdk updates.
Other Information
Writing a middleware for a specific aws-sdk-js-v3 version is not a problem. This feature is in particular helpful for vending middleware to many consumers with different aws-sdk-js-v3 versions.
Acknowledgements
SDK version used
all of them
Environment details (OS name and version, etc.)
all of them
The text was updated successfully, but these errors were encountered: