Skip to content

Commit 08e578c

Browse files
committed
feat: integrate clients with endpoint.ts
1 parent cfb3342 commit 08e578c

File tree

9 files changed

+182
-35
lines changed

9 files changed

+182
-35
lines changed

clients/client-rds-data/RDSDataClient.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ import {
5454
HttpHandlerOptions as __HttpHandlerOptions,
5555
Provider as __Provider,
5656
StreamCollector as __StreamCollector,
57-
UrlParser as __UrlParser
57+
UrlParser as __UrlParser,
58+
RegionInfoProvider
5859
} from "@aws-sdk/types";
5960

6061
export type ServiceInputTypes =
@@ -140,6 +141,11 @@ export interface ClientDefaults
140141
* Provider function that return promise of a region string
141142
*/
142143
regionDefaultProvider?: (input: any) => __Provider<string>;
144+
145+
/**
146+
* Fetch hostname, signing name or signing region of given region
147+
*/
148+
regionInfoProvider?: RegionInfoProvider;
143149
}
144150

145151
export type RDSDataClientConfig = Partial<
@@ -184,7 +190,6 @@ export class RDSDataClient extends __Client<
184190

185191
constructor(configuration: RDSDataClientConfig) {
186192
let _config_0 = {
187-
service: "rds-data", //TODO: remove this
188193
...__ClientDefaultValues,
189194
...configuration
190195
};

clients/client-rds-data/endpoints.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { RegionInfoProvider } from "@aws-sdk/types";
2+
3+
// Partition default templates
4+
const AWS_TEMPLATE = "rds-data.{region}.amazonaws.com";
5+
const AWS_CN_TEMPLATE = "rds-data.{region}.amazonaws.com.cn";
6+
const AWS_ISO_TEMPLATE = "rds-data.{region}.c2s.ic.gov";
7+
const AWS_ISO_B_TEMPLATE = "rds-data.{region}.sc2s.sgov.gov";
8+
const AWS_US_GOV_TEMPLATE = "rds-data.{region}.amazonaws.com";
9+
10+
// Partition regions
11+
const AWS_REGIONS = new Set([
12+
"ap-south-1",
13+
"eu-north-1",
14+
"eu-west-3",
15+
"eu-west-2",
16+
"eu-west-1",
17+
"ap-northeast-2",
18+
"ap-northeast-1",
19+
"me-south-1",
20+
"ca-central-1",
21+
"sa-east-1",
22+
"ap-east-1",
23+
"ap-southeast-1",
24+
"ap-southeast-2",
25+
"eu-central-1",
26+
"us-east-1",
27+
"us-east-2",
28+
"us-west-1",
29+
"us-west-2"
30+
]);
31+
const AWS_CN_REGIONS = new Set(["cn-north-1", "cn-northwest-1"]);
32+
const AWS_ISO_REGIONS = new Set(["us-iso-east-1"]);
33+
const AWS_ISO_B_REGIONS = new Set(["us-isob-east-1"]);
34+
const AWS_US_GOV_REGIONS = new Set(["us-gov-west-1", "us-gov-east-1"]);
35+
36+
export let defaultRegionInfoProvider: RegionInfoProvider;
37+
defaultRegionInfoProvider = function(region: string, options?: any) {
38+
switch (region) {
39+
// First, try to match exact region names.
40+
// Next, try to match partition endpoints.
41+
default:
42+
if (region in AWS_REGIONS) {
43+
return {
44+
hostname: AWS_TEMPLATE.replace("{region}", region)
45+
};
46+
}
47+
if (region in AWS_CN_REGIONS) {
48+
return {
49+
hostname: AWS_CN_TEMPLATE.replace("{region}", region)
50+
};
51+
}
52+
if (region in AWS_ISO_REGIONS) {
53+
return {
54+
hostname: AWS_ISO_TEMPLATE.replace("{region}", region)
55+
};
56+
}
57+
if (region in AWS_ISO_B_REGIONS) {
58+
return {
59+
hostname: AWS_ISO_B_TEMPLATE.replace("{region}", region)
60+
};
61+
}
62+
if (region in AWS_US_GOV_REGIONS) {
63+
return {
64+
hostname: AWS_US_GOV_TEMPLATE.replace("{region}", region)
65+
};
66+
}
67+
// Finally, assume it's an AWS partition endpoint.
68+
return {
69+
hostname: AWS_TEMPLATE.replace("{region}", region)
70+
};
71+
}
72+
};
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
import { defaultRegionInfoProvider } from "./endpoints";
12
export const ClientSharedValues = {
23
apiVersion: "2018-08-01",
34
signingName: "rds-data",
5+
regionInfoProvider: defaultRegionInfoProvider
46
};

codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddBuiltinPlugins.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,10 @@ public List<RuntimeClientPlugin> getClientPlugins() {
5858
.withConventions(TypeScriptDependency.CONFIG_RESOLVER.dependency, "Region", HAS_CONFIG)
5959
.build(),
6060
RuntimeClientPlugin.builder()
61-
.withConventions(AwsDependency.MIDDLEWARE_SIGNING.dependency, "AwsAuth")
61+
.withConventions(TypeScriptDependency.CONFIG_RESOLVER.dependency, "Endpoints", HAS_CONFIG)
6262
.build(),
6363
RuntimeClientPlugin.builder()
64-
.withConventions(TypeScriptDependency.CONFIG_RESOLVER.dependency, "Endpoints", HAS_CONFIG)
64+
.withConventions(AwsDependency.MIDDLEWARE_SIGNING.dependency, "AwsAuth")
6565
.build(),
6666
RuntimeClientPlugin.builder()
6767
.withConventions(TypeScriptDependency.MIDDLEWARE_RETRY.dependency, "Retry")

codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/EndpointGenerator.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,10 +129,11 @@ private void writePartitionRegions() {
129129
}
130130

131131
private void writeEndpointProviderFunction() {
132-
writer.write("export let defaultEndpointProvider: EndpointProvider;");
133-
writer.openBlock("defaultEndpointProvider = function(\n"
132+
writer.addImport("RegionInfoProvider", "RegionInfoProvider", "@aws-sdk/types");
133+
writer.write("export const defaultRegionInfoProvider: RegionInfoProvider;");
134+
writer.openBlock("defaultRegionInfoProvider = function(\n"
134135
+ " region: string,\n"
135-
+ " options?: EndpointOptions\n"
136+
+ " options?: any\n"
136137
+ ") {", "}", () -> {
137138
writer.openBlock("switch (region) {", "}", () -> {
138139
writer.write("// First, try to match exact region names.");

packages/config-resolver/src/EndpointsConfig.ts

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import { Provider, UrlParser, Endpoint } from "@aws-sdk/types";
1+
import {
2+
Provider,
3+
UrlParser,
4+
Endpoint,
5+
RegionInfoProvider,
6+
RegionInfo
7+
} from "@aws-sdk/types";
28

39
export function normalizeEndpoint(
410
endpoint?: string | Endpoint | Provider<Endpoint>,
@@ -20,20 +26,15 @@ export interface EndpointsInputConfig {
2026
*/
2127
endpoint?: string | Endpoint | Provider<Endpoint>;
2228

23-
/**
24-
* The endpoint provider to call if no endpoint is provided
25-
*/
26-
endpointProvider?: any;
27-
2829
/**
2930
* Whether TLS is enabled for requests.
3031
*/
3132
tls?: boolean;
3233
}
3334
interface PreviouslyResolved {
35+
regionInfoProvider: RegionInfoProvider;
3436
urlParser: UrlParser;
3537
region: Provider<string>;
36-
service: string;
3738
}
3839
export interface EndpointsResolvedConfig
3940
extends Required<EndpointsInputConfig> {
@@ -43,18 +44,21 @@ export function resolveEndpointsConfig<T>(
4344
input: T & EndpointsInputConfig & PreviouslyResolved
4445
): T & EndpointsResolvedConfig {
4546
const tls = input.tls || true;
46-
const defaultProvider = (tls: boolean, region: string) => ({
47-
protocol: tls ? "https:" : "http:",
48-
path: "/",
49-
hostname: `${input.service}.${region}.amazonaws.com`
50-
});
51-
const endpointProvider = input.endpointProvider || defaultProvider;
5247
const endpoint: Provider<Endpoint> = input.endpoint
5348
? normalizeEndpoint(input.endpoint, input.urlParser)
54-
: () => input.region().then(region => endpointProvider(tls, region));
49+
: () =>
50+
input.region().then(region => {
51+
const hostname = (
52+
input.regionInfoProvider(region) || ({} as RegionInfo)
53+
).hostname;
54+
if (!hostname)
55+
throw new Error("Cannot resolve hostname from client config");
56+
const endpoint = input.urlParser(hostname);
57+
endpoint.protocol = tls ? "https:" : "http:";
58+
return endpoint;
59+
});
5560
return {
5661
...input,
57-
endpointProvider,
5862
endpoint,
5963
tls
6064
};

packages/middleware-signing/src/configurations.ts

Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ import {
22
RequestSigner,
33
Credentials,
44
Provider,
5-
HashConstructor
5+
HashConstructor,
6+
RegionInfoProvider,
7+
RegionInfo
68
} from "@aws-sdk/types";
79
import { SignatureV4 } from "@aws-sdk/signature-v4";
810

@@ -15,7 +17,7 @@ export interface AwsAuthInputConfig {
1517
/**
1618
* The signer to use when signing requests.
1719
*/
18-
signer?: RequestSigner;
20+
signer?: RequestSigner | Provider<RequestSigner>;
1921

2022
/**
2123
* Whether to escape request path when signing the request.
@@ -26,16 +28,23 @@ export interface AwsAuthInputConfig {
2628
* An offset value in milliseconds to apply to all signing times.
2729
*/
2830
systemClockOffset?: number;
31+
32+
/**
33+
* The region where you want to sign your request against. This
34+
* can be different to the region in the endpoint.
35+
*/
36+
signingRegion?: string;
2937
}
3038
interface PreviouslyResolved {
3139
credentialDefaultProvider: (input: any) => Provider<Credentials>;
3240
region: string | Provider<string>;
41+
regionInfoProvider: RegionInfoProvider;
3342
signingName: string;
3443
sha256: HashConstructor;
3544
}
3645
export interface AwsAuthResolvedConfig {
3746
credentials: Provider<Credentials>;
38-
signer: RequestSigner;
47+
signer: Provider<RequestSigner>;
3948
signingEscapePath: boolean;
4049
systemClockOffset: number;
4150
}
@@ -45,20 +54,49 @@ export function resolveAwsAuthConfig<T>(
4554
let credentials =
4655
input.credentials || input.credentialDefaultProvider(input as any);
4756
const normalizedCreds = normalizeProvider(credentials);
48-
const signingEscapePath = input.signingEscapePath || false;
49-
const systemClockOffset = input.systemClockOffset || 0;
57+
const {
58+
signingEscapePath = false,
59+
systemClockOffset = input.systemClockOffset || 0,
60+
sha256
61+
} = input;
62+
let signer: Provider<RequestSigner>;
63+
if (input.signer) signer = normalizeProvider(input.signer);
64+
else {
65+
signer = () =>
66+
normalizeProvider(input.region)()
67+
.then(
68+
region =>
69+
[input.regionInfoProvider(region) || {}, region] as [
70+
RegionInfo,
71+
string
72+
]
73+
)
74+
.then(([regionInfo, region]) => {
75+
const {
76+
signingRegion = input.signingRegion,
77+
signingService = input.signingName
78+
} = regionInfo;
79+
//update client's resolved config if it's resolved
80+
//resolution: user supplied signingRegion -> endpoints.js inferred region -> client region
81+
input.signingRegion = input.signingRegion || signingRegion || region;
82+
input.signingName = input.signingName || signingService;
83+
84+
return new SignatureV4({
85+
credentials: normalizedCreds,
86+
region: input.signingRegion,
87+
service: input.signingName,
88+
sha256,
89+
uriEscapePath: signingEscapePath
90+
});
91+
});
92+
}
93+
5094
return {
5195
...input,
5296
systemClockOffset,
5397
signingEscapePath,
5498
credentials: normalizedCreds,
55-
signer: new SignatureV4({
56-
credentials: normalizedCreds,
57-
region: input.region,
58-
service: input.signingName,
59-
sha256: input.sha256,
60-
uriEscapePath: signingEscapePath
61-
})
99+
signer
62100
};
63101
}
64102

packages/middleware-signing/src/middleware.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,13 @@ export function awsAuthMiddleware<Input extends object, Output extends object>(
2727
args: FinalizeHandlerArguments<Input>
2828
): Promise<FinalizeHandlerOutput<Output>> {
2929
if (!HttpRequest.isInstance(args.request)) return next(args);
30+
const signer =
31+
typeof options.signer === "function"
32+
? await options.signer()
33+
: options.signer;
3034
const output = await next({
3135
...args,
32-
request: await options.signer.sign(args.request, {
36+
request: await signer.sign(args.request, {
3337
signingDate: new Date(Date.now() + options.systemClockOffset)
3438
})
3539
});

packages/types/src/util.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,24 @@ export interface RetryStrategy {
8282
export interface UrlParser {
8383
(url: string): Endpoint;
8484
}
85+
86+
/**
87+
* Object containing regionalization information of
88+
* AWS services.
89+
*/
90+
export interface RegionInfo {
91+
hostname: string;
92+
path?: string;
93+
signingService?: string;
94+
signingRegion?: string;
95+
}
96+
97+
/**
98+
* Function returns designated service's regionalization
99+
* information from given region. Each service client
100+
* comes with its regionalization provider. it serves
101+
* to provide the default values of related configurations
102+
*/
103+
export interface RegionInfoProvider {
104+
(region: string, options?: any): RegionInfo | undefined;
105+
}

0 commit comments

Comments
 (0)