Skip to content

Commit 8376b3e

Browse files
authored
chore(util-endpoints): add utility to read service specific endpoints (#5324)
1 parent 9712aa7 commit 8376b3e

File tree

3 files changed

+128
-0
lines changed

3 files changed

+128
-0
lines changed

packages/util-endpoints/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"license": "Apache-2.0",
2424
"dependencies": {
2525
"@aws-sdk/types": "*",
26+
"@smithy/node-config-provider": "^2.0.13",
2627
"tslib": "^2.5.0"
2728
},
2829
"engines": {
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import { getEndpointUrlConfig } from "./getEndpointUrlConfig";
2+
3+
const ENV_ENDPOINT_URL = "AWS_ENDPOINT_URL";
4+
const CONFIG_ENDPOINT_URL = "endpoint_url";
5+
6+
describe(getEndpointUrlConfig.name, () => {
7+
const serviceId = "mockServiceId";
8+
const endpointUrlConfig = getEndpointUrlConfig(serviceId);
9+
10+
const mockEndpoint = "https://mock-endpoint.com";
11+
const ORIGINAL_ENV = process.env;
12+
13+
beforeEach(() => {
14+
process.env = {};
15+
});
16+
17+
afterEach(() => {
18+
process.env = ORIGINAL_ENV;
19+
});
20+
21+
describe("environmentVariableSelector", () => {
22+
beforeEach(() => {
23+
process.env[ENV_ENDPOINT_URL] = mockEndpoint;
24+
});
25+
26+
it.each([
27+
["foo", `${ENV_ENDPOINT_URL}_FOO`],
28+
["foobar", `${ENV_ENDPOINT_URL}_FOOBAR`],
29+
["foo bar", `${ENV_ENDPOINT_URL}_FOO_BAR`],
30+
])("returns endpoint for '%s' from environment variable %s", (serviceId, envKey) => {
31+
const serviceMockEndpoint = `${mockEndpoint}/${envKey}`;
32+
process.env[envKey] = serviceMockEndpoint;
33+
34+
const endpointUrlConfig = getEndpointUrlConfig(serviceId);
35+
expect(endpointUrlConfig.environmentVariableSelector(process.env)).toEqual(serviceMockEndpoint);
36+
});
37+
38+
it(`returns endpoint from environment variable ${ENV_ENDPOINT_URL}`, () => {
39+
expect(endpointUrlConfig.environmentVariableSelector(process.env)).toEqual(mockEndpoint);
40+
});
41+
42+
it("returns undefined, if endpoint not available in environment variables", () => {
43+
process.env[ENV_ENDPOINT_URL] = undefined;
44+
expect(endpointUrlConfig.environmentVariableSelector(process.env)).toBeUndefined();
45+
});
46+
});
47+
48+
describe("configFileSelector", () => {
49+
const profile = { [CONFIG_ENDPOINT_URL]: mockEndpoint };
50+
51+
// ToDo: Enable once support for services section is added.
52+
it.skip.each([
53+
["foo", "foo"],
54+
["foobar", "foobar"],
55+
["foo bar", "foo_bar"],
56+
])("returns endpoint for '%s' from config file '%s'", (serviceId, serviceConfigId) => {
57+
const serviceMockEndpoint = `${mockEndpoint}/${serviceConfigId}`;
58+
const serviceSectionName = `services ${serviceConfigId}_dev`;
59+
60+
const profileWithServices = {
61+
...profile,
62+
services: serviceSectionName,
63+
};
64+
const parsedIni = {
65+
profileName: profileWithServices,
66+
[serviceSectionName]: {
67+
[serviceConfigId]: {
68+
[CONFIG_ENDPOINT_URL]: serviceMockEndpoint,
69+
},
70+
},
71+
};
72+
73+
// @ts-ignore
74+
expect(endpointUrlConfig.environmentVariableSelector(profileWithServices, parsedIni)).toEqual(
75+
serviceMockEndpoint
76+
);
77+
});
78+
79+
it("returns endpoint from config file, if available", () => {
80+
expect(endpointUrlConfig.configFileSelector(profile)).toEqual(mockEndpoint);
81+
});
82+
83+
it("returns undefined, if endpoint not available in config", () => {
84+
expect(endpointUrlConfig.environmentVariableSelector({})).toBeUndefined();
85+
});
86+
});
87+
88+
it("returns undefined by default", () => {
89+
expect(endpointUrlConfig.default).toBeUndefined();
90+
});
91+
});
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { IniSection } from "@aws-sdk/types";
2+
import { LoadedConfigSelectors } from "@smithy/node-config-provider";
3+
4+
const ENV_ENDPOINT_URL = "AWS_ENDPOINT_URL";
5+
const CONFIG_ENDPOINT_URL = "endpoint_url";
6+
7+
export const getEndpointUrlConfig = (serviceId: string): LoadedConfigSelectors<string | undefined> => ({
8+
environmentVariableSelector: (env: NodeJS.ProcessEnv) => {
9+
// The value provided by a service-specific environment variable.
10+
const serviceEndpointUrlSections = [ENV_ENDPOINT_URL, ...serviceId.split(" ").map((w) => w.toUpperCase())];
11+
const serviceEndpointUrl = env[serviceEndpointUrlSections.join("_")];
12+
if (serviceEndpointUrl) return serviceEndpointUrl;
13+
14+
// The value provided by the global endpoint environment variable.
15+
const endpointUrl = env[ENV_ENDPOINT_URL];
16+
if (endpointUrl) return endpointUrl;
17+
18+
return undefined;
19+
},
20+
21+
configFileSelector: (profile: IniSection) => {
22+
// The value provided by a service-specific parameter from a services definition section
23+
// referenced in a profile in the shared configuration file.
24+
25+
// ToDo: profile is selected one. It does not have access to other 'services' section.
26+
// The configFileSelector interface needs to be modified to pass ParsedIniData as optional second parameter.
27+
28+
// The value provided by the global parameter from a profile in the shared configuration file.
29+
const endpointUrl = profile[CONFIG_ENDPOINT_URL];
30+
if (endpointUrl) return endpointUrl;
31+
32+
return undefined;
33+
},
34+
35+
default: undefined,
36+
});

0 commit comments

Comments
 (0)