Skip to content

Commit 425c003

Browse files
authored
chore(core/protocols): correct x-amz-target header in schema protocols (#7248)
* chore: generate CWL in schema serde * fix(core/protocols): x-amz-target in rpc protocols * fix(core/protocols): construction of x-amz-target header
1 parent 2cea144 commit 425c003

File tree

15 files changed

+222
-29
lines changed

15 files changed

+222
-29
lines changed

codegen/sdk-codegen/build.gradle.kts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,9 @@ tasks.register("generate-smithy-build") {
109109
val useLegacyAuthServices = setOf<String>(
110110
// e.g. "S3" - use this as exclusion list if needed.
111111
)
112+
val useSchemaSerde = setOf<String>(
113+
// "CloudWatch Logs"
114+
)
112115
val projectionContents = Node.objectNodeBuilder()
113116
.withMember("imports", Node.fromStrings("${models.getAbsolutePath()}${File.separator}${file.name}"))
114117
.withMember("plugins", Node.objectNode()
@@ -121,6 +124,8 @@ tasks.register("generate-smithy-build") {
121124
+ clientName + " Client for Node.js, Browser and React Native")
122125
.withMember("useLegacyAuth",
123126
useLegacyAuthServices.contains(serviceTrait.sdkId))
127+
.withMember("generateSchemas",
128+
useSchemaSerde.contains(serviceTrait.sdkId))
124129
.build()))
125130
.build()
126131
projectionsBuilder.withMember(sdkId + "." + version.toLowerCase(), projectionContents)

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

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ public AddProtocolConfig() {
3737
SchemaGenerationAllowlist.allow("com.amazonaws.s3#AmazonS3");
3838
SchemaGenerationAllowlist.allow("com.amazonaws.dynamodb#DynamoDB_20120810");
3939
SchemaGenerationAllowlist.allow("com.amazonaws.lambda#AWSGirApiService");
40+
SchemaGenerationAllowlist.allow("com.amazonaws.cloudwatchlogs#Logs_20140328");
4041

4142
// protocol tests
4243
SchemaGenerationAllowlist.allow("aws.protocoltests.json10#JsonRpc10");
@@ -69,6 +70,7 @@ public Map<String, Consumer<TypeScriptWriter>> getRuntimeConfigWriters(
6970
return Collections.emptyMap();
7071
}
7172
String namespace = settings.getService().getNamespace();
73+
String rpcTarget = settings.getService().getName();
7274
String xmlns = settings.getService(model)
7375
.getTrait(XmlNamespaceTrait.class)
7476
.map(XmlNamespaceTrait::getUri)
@@ -144,7 +146,11 @@ public Map<String, Consumer<TypeScriptWriter>> getRuntimeConfigWriters(
144146
writer.addImportSubmodule(
145147
"AwsJson1_0Protocol", null,
146148
AwsDependency.AWS_SDK_CORE, "/protocols");
147-
writer.write("new AwsJson1_0Protocol({ defaultNamespace: $S })", namespace);
149+
writer.write(
150+
"new AwsJson1_0Protocol({ defaultNamespace: $S, serviceTarget: $S })",
151+
namespace,
152+
rpcTarget
153+
);
148154
}
149155
);
150156
} else if (Objects.equals(settings.getProtocol(), AwsJson1_1Trait.ID)) {
@@ -153,7 +159,11 @@ public Map<String, Consumer<TypeScriptWriter>> getRuntimeConfigWriters(
153159
writer.addImportSubmodule(
154160
"AwsJson1_1Protocol", null,
155161
AwsDependency.AWS_SDK_CORE, "/protocols");
156-
writer.write("new AwsJson1_1Protocol({ defaultNamespace: $S })", namespace);
162+
writer.write(
163+
"new AwsJson1_1Protocol({ defaultNamespace: $S, serviceTarget: $S })",
164+
namespace,
165+
rpcTarget
166+
);
157167
}
158168
);
159169
}

packages/core/src/submodules/protocols/json/AwsJson1_0Protocol.spec.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ describe(AwsJson1_0Protocol.name, () => {
3030
it("serializes blobs and timestamps", () => {
3131
const protocol = new AwsJson1_0Protocol({
3232
defaultNamespace: "namespace",
33+
serviceTarget: "JsonRpc10",
3334
});
3435
protocol.setSerdeContext(serdeContext);
3536
const codec = protocol.getPayloadCodec();
@@ -55,6 +56,7 @@ describe(AwsJson1_0Protocol.name, () => {
5556
it("deserializes blobs and timestamps", async () => {
5657
const protocol = new AwsJson1_0Protocol({
5758
defaultNamespace: "namespace",
59+
serviceTarget: "JsonRpc10",
5860
});
5961
protocol.setSerdeContext(serdeContext);
6062
const codec = protocol.getPayloadCodec();
@@ -73,6 +75,7 @@ describe(AwsJson1_0Protocol.name, () => {
7375
it("ignores JSON name and HTTP bindings", async () => {
7476
const protocol = new AwsJson1_0Protocol({
7577
defaultNamespace: "namespace",
78+
serviceTarget: "JsonRpc10",
7679
});
7780
protocol.setSerdeContext(serdeContext);
7881

packages/core/src/submodules/protocols/json/AwsJson1_0Protocol.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ import { AwsJsonRpcProtocol } from "./AwsJsonRpcProtocol";
55
* @see https://smithy.io/2.0/aws/protocols/aws-json-1_1-protocol.html#differences-between-awsjson1-0-and-awsjson1-1
66
*/
77
export class AwsJson1_0Protocol extends AwsJsonRpcProtocol {
8-
public constructor({ defaultNamespace }: { defaultNamespace: string }) {
8+
public constructor({ defaultNamespace, serviceTarget }: { defaultNamespace: string; serviceTarget: string }) {
99
super({
1010
defaultNamespace,
11+
serviceTarget,
1112
});
1213
}
1314

@@ -18,4 +19,11 @@ export class AwsJson1_0Protocol extends AwsJsonRpcProtocol {
1819
protected getJsonRpcVersion() {
1920
return "1.0" as const;
2021
}
22+
23+
/**
24+
* @override
25+
*/
26+
protected getDefaultContentType(): string {
27+
return "application/x-amz-json-1.0";
28+
}
2129
}

packages/core/src/submodules/protocols/json/AwsJson1_1Protocol.spec.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,24 @@ import { HttpResponse } from "@smithy/protocol-http";
22
import { describe, expect, test as it } from "vitest";
33

44
import { context, deleteObjects } from "../test-schema.spec";
5-
import { AwsJson1_0Protocol } from "./AwsJson1_0Protocol";
5+
import { AwsJson1_1Protocol } from "./AwsJson1_1Protocol";
66

77
/**
88
* These tests are cursory since most coverage is provided by protocol tests.
99
*/
10-
describe(AwsJson1_0Protocol, () => {
10+
describe(AwsJson1_1Protocol, () => {
1111
it("is 1.0", async () => {
12-
const protocol = new AwsJson1_0Protocol({
12+
const protocol = new AwsJson1_1Protocol({
1313
defaultNamespace: "",
14+
serviceTarget: "JsonRpc11",
1415
});
15-
expect(protocol.getShapeId()).toEqual("aws.protocols#awsJson1_0");
16+
expect(protocol.getShapeId()).toEqual("aws.protocols#awsJson1_1");
1617
});
1718

1819
it("serializes a request", async () => {
19-
const protocol = new AwsJson1_0Protocol({
20+
const protocol = new AwsJson1_1Protocol({
2021
defaultNamespace: "",
22+
serviceTarget: "JsonRpc11",
2123
});
2224
const httpRequest = await protocol.serializeRequest(
2325
deleteObjects,
@@ -59,8 +61,9 @@ describe(AwsJson1_0Protocol, () => {
5961
headers: {},
6062
});
6163

62-
const protocol = new AwsJson1_0Protocol({
64+
const protocol = new AwsJson1_1Protocol({
6365
defaultNamespace: "",
66+
serviceTarget: "JsonRpc11",
6467
});
6568

6669
const output = await protocol.deserializeResponse(deleteObjects, context, httpResponse);

packages/core/src/submodules/protocols/json/AwsJson1_1Protocol.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ import { AwsJsonRpcProtocol } from "./AwsJsonRpcProtocol";
55
* @see https://smithy.io/2.0/aws/protocols/aws-json-1_1-protocol.html#differences-between-awsjson1-0-and-awsjson1-1
66
*/
77
export class AwsJson1_1Protocol extends AwsJsonRpcProtocol {
8-
public constructor({ defaultNamespace }: { defaultNamespace: string }) {
8+
public constructor({ defaultNamespace, serviceTarget }: { defaultNamespace: string; serviceTarget: string }) {
99
super({
1010
defaultNamespace,
11+
serviceTarget,
1112
});
1213
}
1314

@@ -18,4 +19,11 @@ export class AwsJson1_1Protocol extends AwsJsonRpcProtocol {
1819
protected getJsonRpcVersion() {
1920
return "1.1" as const;
2021
}
22+
23+
/**
24+
* @override
25+
*/
26+
protected getDefaultContentType(): string {
27+
return "application/x-amz-json-1.1";
28+
}
2129
}

packages/core/src/submodules/protocols/json/AwsJsonRpcProtocol.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ describe(AwsJsonRpcProtocol.name, () => {
77
it("has expected codec settings", async () => {
88
const protocol = new (class extends AwsJsonRpcProtocol {
99
constructor() {
10-
super({ defaultNamespace: "" });
10+
super({ defaultNamespace: "", serviceTarget: "" });
1111
}
1212

1313
getShapeId(): string {

packages/core/src/submodules/protocols/json/AwsJsonRpcProtocol.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,14 @@ import { loadRestJsonErrorCode } from "./parseJsonBody";
2222
export abstract class AwsJsonRpcProtocol extends RpcProtocol {
2323
protected serializer: ShapeSerializer<string | Uint8Array>;
2424
protected deserializer: ShapeDeserializer<string | Uint8Array>;
25+
protected serviceTarget: string;
2526
private codec: JsonCodec;
2627

27-
protected constructor({ defaultNamespace }: { defaultNamespace: string }) {
28+
protected constructor({ defaultNamespace, serviceTarget }: { defaultNamespace: string; serviceTarget: string }) {
2829
super({
2930
defaultNamespace,
3031
});
32+
this.serviceTarget = serviceTarget;
3133
this.codec = new JsonCodec({
3234
timestampFormat: {
3335
useTrait: true,
@@ -50,9 +52,7 @@ export abstract class AwsJsonRpcProtocol extends RpcProtocol {
5052
}
5153
Object.assign(request.headers, {
5254
"content-type": `application/x-amz-json-${this.getJsonRpcVersion()}`,
53-
"x-amz-target":
54-
(this.getJsonRpcVersion() === "1.0" ? `JsonRpc10.` : `JsonProtocol.`) +
55-
NormalizedSchema.of(operationSchema).getName(),
55+
"x-amz-target": `${this.serviceTarget}.${NormalizedSchema.of(operationSchema).getName()}`,
5656
});
5757
if (deref(operationSchema.input) === "unit" || !request.body) {
5858
request.body = "{}";

packages/core/src/submodules/protocols/json/AwsRestJsonProtocol.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,15 +81,15 @@ export class AwsRestJsonProtocol extends HttpBindingProtocol {
8181
} else if (httpPayloadMember.isBlobSchema()) {
8282
request.headers["content-type"] = "application/octet-stream";
8383
} else {
84-
request.headers["content-type"] = "application/json";
84+
request.headers["content-type"] = this.getDefaultContentType();
8585
}
8686
} else if (!inputSchema.isUnitSchema()) {
8787
const hasBody = Object.values(members).find((m) => {
8888
const { httpQuery, httpQueryParams, httpHeader, httpLabel, httpPrefixHeaders } = m.getMergedTraits();
8989
return !httpQuery && !httpQueryParams && !httpHeader && !httpLabel && httpPrefixHeaders === void 0;
9090
});
9191
if (hasBody) {
92-
request.headers["content-type"] = "application/json";
92+
request.headers["content-type"] = this.getDefaultContentType();
9393
}
9494
}
9595
}
@@ -157,4 +157,11 @@ export class AwsRestJsonProtocol extends HttpBindingProtocol {
157157

158158
throw exception;
159159
}
160+
161+
/**
162+
* @override
163+
*/
164+
protected getDefaultContentType(): string {
165+
return "application/json";
166+
}
160167
}

packages/core/src/submodules/protocols/query/AwsQueryProtocol.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,4 +212,11 @@ export class AwsQueryProtocol extends RpcProtocol {
212212
const errorData = this.loadQueryError(data);
213213
return errorData?.message ?? errorData?.Message ?? data.message ?? data.Message ?? "Unknown";
214214
}
215+
216+
/**
217+
* @override
218+
*/
219+
protected getDefaultContentType(): string {
220+
return "application/x-www-form-urlencoded";
221+
}
215222
}

0 commit comments

Comments
 (0)