Skip to content

Commit 5a56762

Browse files
authored
feat(core/protocols): make protocol selection easier (#1812)
1 parent 2043a99 commit 5a56762

File tree

12 files changed

+148
-68
lines changed

12 files changed

+148
-68
lines changed

.changeset/eighty-peas-think.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@smithy/smithy-client": minor
3+
"@smithy/types": minor
4+
"@smithy/core": minor
5+
---
6+
7+
make protocol selection easier

packages/core/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414
"extract:docs": "api-extractor run --local",
1515
"test:cbor:perf": "node ./scripts/cbor-perf.mjs",
1616
"test": "yarn g:vitest run",
17-
"test:watch": "yarn g:vitest watch"
17+
"test:watch": "yarn g:vitest watch",
18+
"test:integration": "yarn g:vitest run -c vitest.config.integ.mts",
19+
"test:integration:watch": "yarn g:vitest watch -c vitest.config.integ.mts"
1820
},
1921
"main": "./dist-cjs/index.js",
2022
"module": "./dist-es/index.js",
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { SmithyRpcV2CborProtocol } from "@smithy/core/cbor";
2+
import type { HttpProtocol } from "@smithy/core/protocols";
3+
import { RpcV2ProtocolClient } from "@smithy/smithy-rpcv2-cbor-schema";
4+
import { describe, expect, test as it } from "vitest";
5+
6+
describe("@smithy/core", () => {
7+
it("should normalize the config.protocol field", () => {
8+
const withInstance = new RpcV2ProtocolClient({
9+
endpoint: "https://localhost",
10+
protocol: new SmithyRpcV2CborProtocol({
11+
defaultNamespace: "smithy.protocoltests.rpcv2Cbor",
12+
}),
13+
});
14+
15+
expect(withInstance.config.protocol).toBeInstanceOf(SmithyRpcV2CborProtocol);
16+
expect((withInstance.config.protocol as HttpProtocol).options.defaultNamespace).toEqual(
17+
"smithy.protocoltests.rpcv2Cbor"
18+
);
19+
20+
const withCtor = new RpcV2ProtocolClient({
21+
endpoint: "https://localhost",
22+
protocol: SmithyRpcV2CborProtocol,
23+
});
24+
25+
expect(withCtor.config.protocol).toBeInstanceOf(SmithyRpcV2CborProtocol);
26+
expect((withCtor.config.protocol as HttpProtocol).options.defaultNamespace).toEqual(
27+
"smithy.protocoltests.rpcv2Cbor"
28+
);
29+
30+
const withSettings = new RpcV2ProtocolClient({
31+
endpoint: "https://localhost",
32+
protocolSettings: {
33+
defaultNamespace: "ns",
34+
},
35+
});
36+
37+
expect(withCtor.config.protocol).toBeInstanceOf(SmithyRpcV2CborProtocol);
38+
expect((withSettings.config.protocol as HttpProtocol).options.defaultNamespace).toEqual("ns");
39+
});
40+
});
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { defineConfig } from "vitest/config";
2+
3+
export default defineConfig({
4+
test: {
5+
exclude: ["**/*.{e2e,browser}.spec.ts"],
6+
include: ["**/*.integ.spec.ts"],
7+
environment: "node",
8+
hideSkippedTests: true,
9+
},
10+
});

packages/smithy-client/src/client.ts

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1+
import { SerdeContext } from "@smithy/core/protocols";
12
import { constructStack } from "@smithy/middleware-stack";
23
import type {
4+
$ClientProtocol,
5+
$ClientProtocolCtor,
36
Client as IClient,
7+
ClientProtocol,
8+
ClientProtocolCtor,
49
Command,
510
FetchHttpHandlerOptions,
611
Handler,
@@ -14,17 +19,15 @@ import type {
1419
* @public
1520
*/
1621
export interface SmithyConfiguration<HandlerOptions> {
22+
/**
23+
* @public
24+
*/
1725
requestHandler:
1826
| RequestHandler<any, any, HandlerOptions>
1927
| NodeHttpHandlerOptions
2028
| FetchHttpHandlerOptions
2129
| Record<string, unknown>;
22-
/**
23-
* The API version set internally by the SDK, and is
24-
* not planned to be used by customer code.
25-
* @internal
26-
*/
27-
readonly apiVersion: string;
30+
2831
/**
2932
* @public
3033
*
@@ -41,15 +44,51 @@ export interface SmithyConfiguration<HandlerOptions> {
4144
* and not needing middleware modifications between requests.
4245
*/
4346
cacheMiddleware?: boolean;
47+
48+
/**
49+
* A client request/response protocol or constructor of one.
50+
* A protocol in this context is not e.g. https.
51+
* It is the combined implementation of how to (de)serialize and create
52+
* the messages (e.g. http requests/responses) that are being exchanged.
53+
*
54+
* @public
55+
*/
56+
protocol?:
57+
| ClientProtocol<any, any>
58+
| $ClientProtocol<any, any>
59+
| ClientProtocolCtor<any, any>
60+
| $ClientProtocolCtor<any, any>;
61+
62+
/**
63+
* These are automatically generated and will be passed to the
64+
* config.protocol if given as a constructor.
65+
* @internal
66+
*/
67+
protocolSettings?: {
68+
defaultNamespace?: string;
69+
[setting: string]: unknown;
70+
};
71+
72+
/**
73+
* The API version set internally by the SDK, and is
74+
* not planned to be used by customer code.
75+
* @internal
76+
*/
77+
readonly apiVersion: string;
4478
}
4579

4680
/**
4781
* @internal
4882
*/
4983
export type SmithyResolvedConfiguration<HandlerOptions> = {
5084
requestHandler: RequestHandler<any, any, HandlerOptions>;
51-
readonly apiVersion: string;
5285
cacheMiddleware?: boolean;
86+
protocol: ClientProtocol<any, any> | $ClientProtocol<any, any>;
87+
protocolSettings?: {
88+
defaultNamespace?: string;
89+
[setting: string]: unknown;
90+
};
91+
readonly apiVersion: string;
5392
};
5493

5594
/**
@@ -78,7 +117,15 @@ export class Client<
78117
*/
79118
private handlers?: WeakMap<Function, Handler<any, any>> | undefined;
80119

81-
constructor(public readonly config: ResolvedClientConfiguration) {}
120+
constructor(public readonly config: ResolvedClientConfiguration) {
121+
const { protocol, protocolSettings } = config;
122+
if (protocolSettings) {
123+
if (typeof protocol === "function") {
124+
// assumed to be a constructor
125+
config.protocol = new (protocol as any)(protocolSettings);
126+
}
127+
}
128+
}
82129

83130
send<InputType extends ClientInput, OutputType extends ClientOutput>(
84131
command: Command<ClientInput, InputType, ClientOutput, OutputType, SmithyResolvedConfiguration<HandlerOptions>>,

packages/types/src/schema/schema-deprecated.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,3 +167,11 @@ export interface ClientProtocol<Request, Response> extends ConfigurableSerdeCont
167167
response: Response
168168
): Promise<Output>;
169169
}
170+
171+
/**
172+
* @public
173+
* @deprecated use $ClientProtocolCtor.
174+
*/
175+
export interface ClientProtocolCtor<Request, Response> {
176+
new (args: any): ClientProtocol<Request, Response>;
177+
}

packages/types/src/schema/schema.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,13 @@ export interface $ClientProtocol<Request, Response> extends ConfigurableSerdeCon
277277
): Promise<Output>;
278278
}
279279

280+
/**
281+
* @public
282+
*/
283+
export interface $ClientProtocolCtor<Request, Response> {
284+
new (args: any): $ClientProtocol<Request, Response>;
285+
}
286+
280287
/**
281288
* Allows a protocol, codec, or serde utility to accept the serdeContext
282289
* from a client configuration or request/response handlerExecutionContext.

private/my-local-model-schema/src/XYZServiceClient.ts

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,11 @@ import type {
3636
BodyLengthCalculator as __BodyLengthCalculator,
3737
CheckOptionalClientConfig as __CheckOptionalClientConfig,
3838
ChecksumConstructor as __ChecksumConstructor,
39-
ClientProtocol,
4039
Decoder as __Decoder,
4140
Encoder as __Encoder,
4241
EventStreamSerdeProvider as __EventStreamSerdeProvider,
4342
HashConstructor as __HashConstructor,
4443
HttpHandlerOptions as __HttpHandlerOptions,
45-
HttpRequest,
46-
HttpResponse,
4744
Logger as __Logger,
4845
Provider as __Provider,
4946
StreamCollector as __StreamCollector,
@@ -175,16 +172,6 @@ export interface ClientDefaults extends Partial<__SmithyConfiguration<__HttpHand
175172
*/
176173
extensions?: RuntimeExtension[];
177174

178-
/**
179-
* The protocol controlling the message type (e.g. HTTP) and format (e.g. JSON)
180-
* may be overridden. A default will always be set by the client.
181-
* Available options depend on the service's supported protocols and will not be validated by
182-
* the client.
183-
* @alpha
184-
*
185-
*/
186-
protocol?: ClientProtocol<HttpRequest, HttpResponse>;
187-
188175
/**
189176
* The function that provides necessary utilities for generating and parsing event stream
190177
*/

private/my-local-model-schema/src/runtimeConfig.shared.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@ export const getRuntimeConfig = (config: XYZServiceClientConfig) => {
3232
},
3333
],
3434
logger: config?.logger ?? new NoOpLogger(),
35-
protocol: config?.protocol ?? new SmithyRpcV2CborProtocol({ defaultNamespace: "org.xyz.v1" }),
35+
protocol: config?.protocol ?? SmithyRpcV2CborProtocol,
36+
protocolSettings: config?.protocolSettings ?? {
37+
defaultNamespace: "org.xyz.v1",
38+
},
3639
urlParser: config?.urlParser ?? parseUrl,
3740
utf8Decoder: config?.utf8Decoder ?? fromUtf8,
3841
utf8Encoder: config?.utf8Encoder ?? toUtf8,

private/smithy-rpcv2-cbor-schema/src/RpcV2ProtocolClient.ts

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,10 @@ import type {
3131
BodyLengthCalculator as __BodyLengthCalculator,
3232
CheckOptionalClientConfig as __CheckOptionalClientConfig,
3333
ChecksumConstructor as __ChecksumConstructor,
34-
ClientProtocol,
3534
Decoder as __Decoder,
3635
Encoder as __Encoder,
3736
HashConstructor as __HashConstructor,
3837
HttpHandlerOptions as __HttpHandlerOptions,
39-
HttpRequest,
40-
HttpResponse,
4138
Logger as __Logger,
4239
Provider as __Provider,
4340
StreamCollector as __StreamCollector,
@@ -226,16 +223,6 @@ export interface ClientDefaults extends Partial<__SmithyConfiguration<__HttpHand
226223
*/
227224
extensions?: RuntimeExtension[];
228225

229-
/**
230-
* The protocol controlling the message type (e.g. HTTP) and format (e.g. JSON)
231-
* may be overridden. A default will always be set by the client.
232-
* Available options depend on the service's supported protocols and will not be validated by
233-
* the client.
234-
* @alpha
235-
*
236-
*/
237-
protocol?: ClientProtocol<HttpRequest, HttpResponse>;
238-
239226
/**
240227
* The {@link @smithy/smithy-client#DefaultsMode} that will be used to determine how certain default configuration options are resolved in the SDK.
241228
*/

0 commit comments

Comments
 (0)