Skip to content

Commit

Permalink
Read service specific endpoints from env/config (#1014)
Browse files Browse the repository at this point in the history
  • Loading branch information
trivikr authored Oct 10, 2023
1 parent 34b7f7b commit f64c4c2
Show file tree
Hide file tree
Showing 9 changed files with 164 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/cool-mugs-design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@smithy/middleware-endpoint": minor
---

Read service specific endpoints from env/config
7 changes: 7 additions & 0 deletions packages/middleware-endpoint/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"license": "Apache-2.0",
"dependencies": {
"@smithy/middleware-serde": "workspace:^",
"@smithy/node-config-provider": "workspace:^",
"@smithy/types": "workspace:^",
"@smithy/url-parser": "workspace:^",
"@smithy/util-middleware": "workspace:^",
Expand All @@ -49,6 +50,12 @@
"files": [
"dist-*/**"
],
"browser": {
"./dist-es/adaptors/getEndpointFromConfig": "./dist-es/adaptors/getEndpointFromConfig.browser"
},
"react-native": {
"./dist-es/adaptors/getEndpointFromConfig": "./dist-es/adaptors/getEndpointFromConfig.browser"
},
"homepage": "https://github.com/awslabs/smithy-typescript/tree/main/packages/middleware-endpoint",
"repository": {
"type": "git",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const getEndpointFromConfig = async (serviceId: string) => undefined;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { loadConfig } from "@smithy/node-config-provider";

import { getEndpointUrlConfig } from "./getEndpointUrlConfig";

export const getEndpointFromConfig = async (serviceId: string) => loadConfig(getEndpointUrlConfig(serviceId))();
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { EndpointResolvedConfig } from "../resolveEndpointConfig";
import { resolveParamsForS3 } from "../service-customizations";
import { EndpointParameterInstructions } from "../types";
import { createConfigValueProvider } from "./createConfigValueProvider";
import { getEndpointFromConfig } from "./getEndpointFromConfig";
import { toEndpointV1 } from "./toEndpointV1";

/**
* @internal
Expand Down Expand Up @@ -36,6 +38,13 @@ export const getEndpointFromInstructions = async <
clientConfig: Partial<EndpointResolvedConfig<T>> & Config,
context?: HandlerExecutionContext
): Promise<EndpointV2> => {
if (!clientConfig.endpoint) {
const endpointFromConfig = await getEndpointFromConfig(clientConfig.serviceId || "");
if (endpointFromConfig) {
clientConfig.endpoint = () => Promise.resolve(toEndpointV1(endpointFromConfig));
}
}

const endpointParams = await resolveParams(commandInput, instructionsSupplier, clientConfig);

if (typeof clientConfig.endpointProvider !== "function") {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { CONFIG_PREFIX_SEPARATOR } from "@smithy/shared-ini-file-loader";

import { getEndpointUrlConfig } from "./getEndpointUrlConfig";

const ENV_ENDPOINT_URL = "AWS_ENDPOINT_URL";
const CONFIG_ENDPOINT_URL = "endpoint_url";

describe(getEndpointUrlConfig.name, () => {
const serviceId = "foo";
const endpointUrlConfig = getEndpointUrlConfig(serviceId);

const mockEndpoint = "https://mock-endpoint.com";
const ORIGINAL_ENV = process.env;

beforeEach(() => {
process.env = {};
});

afterEach(() => {
process.env = ORIGINAL_ENV;
});

describe("environmentVariableSelector", () => {
beforeEach(() => {
process.env[ENV_ENDPOINT_URL] = mockEndpoint;
});

it.each([
["foo", `${ENV_ENDPOINT_URL}_FOO`],
["foobar", `${ENV_ENDPOINT_URL}_FOOBAR`],
["foo bar", `${ENV_ENDPOINT_URL}_FOO_BAR`],
])("returns endpoint for '%s' from environment variable %s", (serviceId, envKey) => {
const serviceMockEndpoint = `${mockEndpoint}/${envKey}`;
process.env[envKey] = serviceMockEndpoint;

const endpointUrlConfig = getEndpointUrlConfig(serviceId);
expect(endpointUrlConfig.environmentVariableSelector(process.env)).toEqual(serviceMockEndpoint);
});

it(`returns endpoint from environment variable ${ENV_ENDPOINT_URL}`, () => {
expect(endpointUrlConfig.environmentVariableSelector(process.env)).toEqual(mockEndpoint);
});

it("returns undefined, if endpoint not available in environment variables", () => {
process.env[ENV_ENDPOINT_URL] = undefined;
expect(endpointUrlConfig.environmentVariableSelector(process.env)).toBeUndefined();
});
});

describe("configFileSelector", () => {
it.each([
["foo", "foo"],
["foobar", "foobar"],
["foo bar", "foo_bar"],
])("returns endpoint for '%s' from config file '%s'", (serviceId, serviceConfigId) => {
const servicesSectionPrefix = "services";
const servicesSectionName = "config-services";
const serviceMockEndpoint = `${mockEndpoint}/${serviceConfigId}`;

const profile = {
[servicesSectionPrefix]: servicesSectionName,
[CONFIG_ENDPOINT_URL]: mockEndpoint,
};

const config = {
[serviceId]: profile,
[[servicesSectionPrefix, servicesSectionName].join(CONFIG_PREFIX_SEPARATOR)]: {
[[serviceConfigId, CONFIG_ENDPOINT_URL].join(CONFIG_PREFIX_SEPARATOR)]: serviceMockEndpoint,
},
};

const endpointUrlConfig = getEndpointUrlConfig(serviceId);
expect(endpointUrlConfig.configFileSelector(profile, config)).toEqual(serviceMockEndpoint);
});

it(`returns endpoint from config ${CONFIG_ENDPOINT_URL}`, () => {
const profile = { [CONFIG_ENDPOINT_URL]: mockEndpoint };
expect(endpointUrlConfig.configFileSelector(profile)).toEqual(mockEndpoint);
});

it("returns undefined, if endpoint not available in config", () => {
expect(endpointUrlConfig.environmentVariableSelector({})).toBeUndefined();
});
});

it("returns undefined by default", () => {
expect(endpointUrlConfig.default).toBeUndefined();
});
});
41 changes: 41 additions & 0 deletions packages/middleware-endpoint/src/adaptors/getEndpointUrlConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { LoadedConfigSelectors } from "@smithy/node-config-provider";
import { CONFIG_PREFIX_SEPARATOR } from "@smithy/shared-ini-file-loader";

const ENV_ENDPOINT_URL = "AWS_ENDPOINT_URL";
const CONFIG_ENDPOINT_URL = "endpoint_url";

export const getEndpointUrlConfig = (serviceId: string): LoadedConfigSelectors<string | undefined> => ({
environmentVariableSelector: (env) => {
// The value provided by a service-specific environment variable.
const serviceSuffixParts = serviceId.split(" ").map((w) => w.toUpperCase());
const serviceEndpointUrl = env[[ENV_ENDPOINT_URL, ...serviceSuffixParts].join("_")];
if (serviceEndpointUrl) return serviceEndpointUrl;

// The value provided by the global endpoint environment variable.
const endpointUrl = env[ENV_ENDPOINT_URL];
if (endpointUrl) return endpointUrl;

return undefined;
},

configFileSelector: (profile, config) => {
// The value provided by a service-specific parameter from a services definition section
if (config && profile.services) {
const servicesSection = config[["services", profile.services].join(CONFIG_PREFIX_SEPARATOR)];
if (servicesSection) {
const servicePrefixParts = serviceId.split(" ").map((w) => w.toLowerCase());
const endpointUrl =
servicesSection[[servicePrefixParts.join("_"), CONFIG_ENDPOINT_URL].join(CONFIG_PREFIX_SEPARATOR)];
if (endpointUrl) return endpointUrl;
}
}

// The value provided by the global parameter from a profile in the shared configuration file.
const endpointUrl = profile[CONFIG_ENDPOINT_URL];
if (endpointUrl) return endpointUrl;

return undefined;
},

default: undefined,
});
6 changes: 6 additions & 0 deletions packages/middleware-endpoint/src/resolveEndpointConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,12 @@ export interface EndpointResolvedConfig<T extends EndpointParameters = EndpointP
* Resolved value for input {@link EndpointsInputConfig.useFipsEndpoint}
*/
useFipsEndpoint: Provider<boolean>;

/**
* Unique service identifier.
* @internal
*/
serviceId?: string;
}

/**
Expand Down
1 change: 1 addition & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2071,6 +2071,7 @@ __metadata:
resolution: "@smithy/middleware-endpoint@workspace:packages/middleware-endpoint"
dependencies:
"@smithy/middleware-serde": "workspace:^"
"@smithy/node-config-provider": "workspace:^"
"@smithy/types": "workspace:^"
"@smithy/url-parser": "workspace:^"
"@smithy/util-middleware": "workspace:^"
Expand Down

0 comments on commit f64c4c2

Please sign in to comment.