Skip to content

Commit 4b32da4

Browse files
authored
feat(endpoint): endpoints v2 codegen (#3942)
* feat(endpoint): endpoints v2 codegen * feat(endpoint): codegen formatting * feat(endpoint): formatting
1 parent a044789 commit 4b32da4

File tree

8 files changed

+179
-108
lines changed

8 files changed

+179
-108
lines changed

Diff for: codegen/sdk-codegen/build.gradle.kts

+6-1
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@ import software.amazon.smithy.model.shapes.ServiceShape
1818
import software.amazon.smithy.model.node.Node
1919
import software.amazon.smithy.gradle.tasks.SmithyBuild
2020
import software.amazon.smithy.aws.traits.ServiceTrait
21+
import java.util.stream.Stream
2122
import kotlin.streams.toList
2223

2324
buildscript {
2425
repositories {
26+
mavenLocal()
2527
mavenCentral()
2628
}
2729
dependencies {
@@ -62,7 +64,10 @@ tasks.register("generate-smithy-build") {
6264
val model = Model.assembler()
6365
.addImport(file.absolutePath)
6466
.assemble().result.get();
65-
val services = model.shapes(ServiceShape::class.javaObjectType).sorted().toList();
67+
val servicesStream: Stream<ServiceShape> = model.shapes(ServiceShape::class.javaObjectType)
68+
val servicesStreamSorted: Stream<ServiceShape> = servicesStream.sorted()
69+
val services: List<ServiceShape> = servicesStreamSorted.toList()
70+
6671
if (services.size != 1) {
6772
throw Exception("There must be exactly one service in each aws model file, but found " +
6873
"${services.size} in ${file.name}: ${services.map { it.id }}");

Diff for: codegen/smithy-aws-typescript-codegen/build.gradle.kts

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ dependencies {
3636
api("software.amazon.smithy:smithy-aws-iam-traits:${rootProject.extra["smithyVersion"]}")
3737
api("software.amazon.smithy:smithy-protocol-test-traits:${rootProject.extra["smithyVersion"]}")
3838
api("software.amazon.smithy:smithy-model:${rootProject.extra["smithyVersion"]}")
39+
api("software.amazon.smithy:smithy-rules-engine:${rootProject.extra["smithyVersion"]}")
3940
api("software.amazon.smithy.typescript:smithy-typescript-codegen:0.11.0")
4041
}
4142

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

+77-69
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package software.amazon.smithy.aws.typescript.codegen;
1717

1818
import static software.amazon.smithy.aws.typescript.codegen.AwsTraitsUtils.isAwsService;
19+
import static software.amazon.smithy.aws.typescript.codegen.AwsTraitsUtils.isEndpointsV2Service;
1920
import static software.amazon.smithy.aws.typescript.codegen.AwsTraitsUtils.isSigV4Service;
2021
import static software.amazon.smithy.typescript.codegen.integration.RuntimeClientPlugin.Convention.HAS_CONFIG;
2122
import static software.amazon.smithy.typescript.codegen.integration.RuntimeClientPlugin.Convention.HAS_MIDDLEWARE;
@@ -46,82 +47,89 @@ public List<RuntimeClientPlugin> getClientPlugins() {
4647
// Note that order is significant because configurations might
4748
// rely on previously resolved values.
4849
return ListUtils.of(
49-
RuntimeClientPlugin.builder()
50-
.withConventions(TypeScriptDependency.CONFIG_RESOLVER.dependency, "Region", HAS_CONFIG)
51-
.servicePredicate((m, s) -> isAwsService(s) || isSigV4Service(s))
52-
.build(),
53-
// Only one of Endpoints or CustomEndpoints should be used
54-
RuntimeClientPlugin.builder()
55-
.withConventions(TypeScriptDependency.CONFIG_RESOLVER.dependency, "Endpoints", HAS_CONFIG)
56-
.servicePredicate((m, s) -> isAwsService(s))
57-
.build(),
58-
RuntimeClientPlugin.builder()
59-
.withConventions(TypeScriptDependency.CONFIG_RESOLVER.dependency, "CustomEndpoints", HAS_CONFIG)
60-
.servicePredicate((m, s) -> !isAwsService(s))
61-
.build(),
62-
RuntimeClientPlugin.builder()
63-
.withConventions(TypeScriptDependency.MIDDLEWARE_RETRY.dependency, "Retry")
64-
.build(),
65-
RuntimeClientPlugin.builder()
66-
.withConventions(TypeScriptDependency.MIDDLEWARE_CONTENT_LENGTH.dependency, "ContentLength",
67-
HAS_MIDDLEWARE)
68-
.build(),
69-
RuntimeClientPlugin.builder()
70-
.withConventions(AwsDependency.ACCEPT_HEADER.dependency, "AcceptHeader",
71-
HAS_MIDDLEWARE)
72-
.servicePredicate((m, s) -> testServiceId(s, "API Gateway"))
73-
.build(),
74-
RuntimeClientPlugin.builder()
75-
.withConventions(AwsDependency.GLACIER_MIDDLEWARE.dependency,
76-
"Glacier", HAS_MIDDLEWARE)
77-
.servicePredicate((m, s) -> testServiceId(s, "Glacier"))
78-
.build(),
79-
RuntimeClientPlugin.builder()
80-
.withConventions(AwsDependency.EC2_MIDDLEWARE.dependency,
81-
"CopySnapshotPresignedUrl", HAS_MIDDLEWARE)
82-
.operationPredicate((m, s, o) -> o.getId().getName(s).equals("CopySnapshot")
83-
&& testServiceId(s, "EC2"))
84-
.build(),
85-
RuntimeClientPlugin.builder()
86-
.withConventions(AwsDependency.MACHINELEARNING_MIDDLEWARE.dependency, "PredictEndpoint",
87-
HAS_MIDDLEWARE)
88-
.operationPredicate((m, s, o) -> o.getId().getName(s).equals("Predict")
89-
&& testServiceId(s, "Machine Learning"))
90-
.build(),
91-
RuntimeClientPlugin.builder()
92-
.withConventions(AwsDependency.ROUTE53_MIDDLEWARE.dependency,
93-
"ChangeResourceRecordSets", HAS_MIDDLEWARE)
94-
.operationPredicate((m, s, o) -> o.getId().getName(s).equals("ChangeResourceRecordSets")
95-
&& testServiceId(s, "Route 53"))
96-
.build(),
97-
RuntimeClientPlugin.builder()
98-
.withConventions(AwsDependency.ROUTE53_MIDDLEWARE.dependency, "IdNormalizer",
99-
HAS_MIDDLEWARE)
100-
.operationPredicate((m, s, o) -> testInputContainsMember(m, o, ROUTE_53_ID_MEMBERS)
101-
&& testServiceId(s, "Route 53"))
102-
.build(),
103-
RuntimeClientPlugin.builder()
104-
.withConventions(AwsDependency.MIDDLEWARE_HOST_HEADER.dependency, "HostHeader")
105-
.build(),
106-
RuntimeClientPlugin.builder()
107-
.withConventions(AwsDependency.MIDDLEWARE_LOGGER.dependency, "Logger", HAS_MIDDLEWARE)
108-
.build(),
109-
RuntimeClientPlugin.builder()
110-
.withConventions(AwsDependency.RECURSION_DETECTION_MIDDLEWARE.dependency,
111-
"RecursionDetection", HAS_MIDDLEWARE)
112-
.build()
50+
RuntimeClientPlugin.builder()
51+
.withConventions(TypeScriptDependency.CONFIG_RESOLVER.dependency, "Region", HAS_CONFIG)
52+
.servicePredicate((m, s) -> isAwsService(s) || isSigV4Service(s))
53+
.build(),
54+
// Only one of Endpoints or CustomEndpoints should be used
55+
RuntimeClientPlugin.builder()
56+
.withConventions(
57+
TypeScriptDependency.CONFIG_RESOLVER.dependency, "Endpoints", HAS_CONFIG)
58+
.servicePredicate((m, s) -> isAwsService(s) && !isEndpointsV2Service(s))
59+
.build(),
60+
RuntimeClientPlugin.builder()
61+
.withConventions(
62+
TypeScriptDependency.CONFIG_RESOLVER.dependency, "CustomEndpoints", HAS_CONFIG)
63+
.servicePredicate((m, s) -> !isAwsService(s) && !isEndpointsV2Service(s))
64+
.build(),
65+
RuntimeClientPlugin.builder()
66+
.withConventions(
67+
TypeScriptDependency.MIDDLEWARE_ENDPOINTS_V2.dependency, "Endpoint", HAS_CONFIG)
68+
.servicePredicate((m, s) -> isAwsService(s) && isEndpointsV2Service(s))
69+
.build(),
70+
RuntimeClientPlugin.builder()
71+
.withConventions(TypeScriptDependency.MIDDLEWARE_RETRY.dependency, "Retry")
72+
.build(),
73+
RuntimeClientPlugin.builder()
74+
.withConventions(TypeScriptDependency.MIDDLEWARE_CONTENT_LENGTH.dependency, "ContentLength",
75+
HAS_MIDDLEWARE)
76+
.build(),
77+
RuntimeClientPlugin.builder()
78+
.withConventions(AwsDependency.ACCEPT_HEADER.dependency, "AcceptHeader",
79+
HAS_MIDDLEWARE)
80+
.servicePredicate((m, s) -> testServiceId(s, "API Gateway"))
81+
.build(),
82+
RuntimeClientPlugin.builder()
83+
.withConventions(AwsDependency.GLACIER_MIDDLEWARE.dependency,
84+
"Glacier", HAS_MIDDLEWARE)
85+
.servicePredicate((m, s) -> testServiceId(s, "Glacier"))
86+
.build(),
87+
RuntimeClientPlugin.builder()
88+
.withConventions(AwsDependency.EC2_MIDDLEWARE.dependency,
89+
"CopySnapshotPresignedUrl", HAS_MIDDLEWARE)
90+
.operationPredicate((m, s, o) -> o.getId().getName(s).equals("CopySnapshot")
91+
&& testServiceId(s, "EC2"))
92+
.build(),
93+
RuntimeClientPlugin.builder()
94+
.withConventions(AwsDependency.MACHINELEARNING_MIDDLEWARE.dependency, "PredictEndpoint",
95+
HAS_MIDDLEWARE)
96+
.operationPredicate((m, s, o) -> o.getId().getName(s).equals("Predict")
97+
&& testServiceId(s, "Machine Learning"))
98+
.build(),
99+
RuntimeClientPlugin.builder()
100+
.withConventions(AwsDependency.ROUTE53_MIDDLEWARE.dependency,
101+
"ChangeResourceRecordSets", HAS_MIDDLEWARE)
102+
.operationPredicate((m, s, o) -> o.getId().getName(s).equals("ChangeResourceRecordSets")
103+
&& testServiceId(s, "Route 53"))
104+
.build(),
105+
RuntimeClientPlugin.builder()
106+
.withConventions(AwsDependency.ROUTE53_MIDDLEWARE.dependency, "IdNormalizer",
107+
HAS_MIDDLEWARE)
108+
.operationPredicate((m, s, o) -> testInputContainsMember(m, o, ROUTE_53_ID_MEMBERS)
109+
&& testServiceId(s, "Route 53"))
110+
.build(),
111+
RuntimeClientPlugin.builder()
112+
.withConventions(AwsDependency.MIDDLEWARE_HOST_HEADER.dependency, "HostHeader")
113+
.build(),
114+
RuntimeClientPlugin.builder()
115+
.withConventions(AwsDependency.MIDDLEWARE_LOGGER.dependency, "Logger", HAS_MIDDLEWARE)
116+
.build(),
117+
RuntimeClientPlugin.builder()
118+
.withConventions(AwsDependency.RECURSION_DETECTION_MIDDLEWARE.dependency,
119+
"RecursionDetection", HAS_MIDDLEWARE)
120+
.build()
113121
);
114122
}
115123

116124
private static boolean testInputContainsMember(
117-
Model model,
118-
OperationShape operationShape,
119-
Set<String> expectedMemberNames
125+
Model model,
126+
OperationShape operationShape,
127+
Set<String> expectedMemberNames
120128
) {
121129
OperationIndex operationIndex = OperationIndex.of(model);
122130
return operationIndex.getInput(operationShape)
123-
.filter(input -> input.getMemberNames().stream().anyMatch(expectedMemberNames::contains))
124-
.isPresent();
131+
.filter(input -> input.getMemberNames().stream().anyMatch(expectedMemberNames::contains))
132+
.isPresent();
125133
}
126134

127135
private static boolean testServiceId(Shape serviceShape, String expectedId) {

Diff for: codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddS3Config.java

+40-28
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
package software.amazon.smithy.aws.typescript.codegen;
1717

18+
import static software.amazon.smithy.aws.typescript.codegen.AwsTraitsUtils.isEndpointsV2Service;
1819
import static software.amazon.smithy.typescript.codegen.integration.RuntimeClientPlugin.Convention.HAS_CONFIG;
1920
import static software.amazon.smithy.typescript.codegen.integration.RuntimeClientPlugin.Convention.HAS_MIDDLEWARE;
2021

@@ -77,7 +78,7 @@ public final class AddS3Config implements TypeScriptIntegration {
7778
@Override
7879
public Model preprocessModel(Model model, TypeScriptSettings settings) {
7980
ServiceShape serviceShape = settings.getService(model);
80-
if (!testServiceId(serviceShape)) {
81+
if (!isS3(serviceShape)) {
8182
return model;
8283
}
8384
Model.Builder modelBuilder = model.toBuilder();
@@ -106,9 +107,14 @@ public Model preprocessModel(Model model, TypeScriptSettings settings) {
106107
}
107108

108109
@Override
109-
public void addConfigInterfaceFields(TypeScriptSettings settings, Model model, SymbolProvider symbolProvider,
110-
TypeScriptWriter writer) {
111-
if (!testServiceId(settings.getService(model))) {
110+
public void addConfigInterfaceFields(
111+
TypeScriptSettings settings,
112+
Model model,
113+
SymbolProvider symbolProvider,
114+
TypeScriptWriter writer
115+
) {
116+
ServiceShape service = settings.getService(model);
117+
if (!isS3(service)) {
112118
return;
113119
}
114120
writer.writeDocs("Whether to escape request path when signing the request.")
@@ -123,7 +129,7 @@ public void addConfigInterfaceFields(TypeScriptSettings settings, Model model, S
123129
@Override
124130
public Map<String, Consumer<TypeScriptWriter>> getRuntimeConfigWriters(TypeScriptSettings settings, Model model,
125131
SymbolProvider symbolProvider, LanguageTarget target) {
126-
if (!testServiceId(settings.getService(model))) {
132+
if (!isS3(settings.getService(model))) {
127133
return Collections.emptyMap();
128134
}
129135
switch (target) {
@@ -158,62 +164,68 @@ public List<RuntimeClientPlugin> getClientPlugins() {
158164
RuntimeClientPlugin.builder()
159165
.withConventions(AwsDependency.S3_MIDDLEWARE.dependency, "ValidateBucketName",
160166
HAS_MIDDLEWARE)
161-
.servicePredicate((m, s) -> testServiceId(s))
167+
.servicePredicate((m, s) -> isS3(s))
162168
.build(),
163169
RuntimeClientPlugin.builder()
164170
.withConventions(AwsDependency.S3_MIDDLEWARE.dependency, "CheckContentLengthHeader",
165171
HAS_MIDDLEWARE)
166-
.operationPredicate((m, s, o) -> testServiceId(s) && o.getId().getName(s).equals("PutObject"))
172+
.operationPredicate((m, s, o) -> isS3(s) && o.getId().getName(s).equals("PutObject"))
167173
.build(),
168174
RuntimeClientPlugin.builder()
169-
.withConventions(AwsDependency.S3_MIDDLEWARE.dependency, "throw200Exceptions",
170-
HAS_MIDDLEWARE)
171-
.operationPredicate(
172-
(m, s, o) -> EXCEPTIONS_OF_200_OPERATIONS.contains(o.getId().getName(s))
173-
&& testServiceId(s))
174-
.build(),
175+
.withConventions(AwsDependency.S3_MIDDLEWARE.dependency, "throw200Exceptions",
176+
HAS_MIDDLEWARE)
177+
.operationPredicate(
178+
(m, s, o) -> EXCEPTIONS_OF_200_OPERATIONS.contains(o.getId().getName(s))
179+
&& isS3(s))
180+
.build(),
175181
RuntimeClientPlugin.builder()
176-
.withConventions(AwsDependency.S3_MIDDLEWARE.dependency,
177-
"WriteGetObjectResponseEndpoint", HAS_MIDDLEWARE)
178-
.operationPredicate((m, s, o) -> testServiceId(s)
179-
&& o.getId().getName(s).equals("WriteGetObjectResponse"))
180-
.build(),
182+
.withConventions(AwsDependency.S3_MIDDLEWARE.dependency,
183+
"WriteGetObjectResponseEndpoint", HAS_MIDDLEWARE)
184+
.operationPredicate((m, s, o) -> isS3(s)
185+
&& o.getId().getName(s).equals("WriteGetObjectResponse"))
186+
.build(),
181187
RuntimeClientPlugin.builder()
182188
.withConventions(AwsDependency.ADD_EXPECT_CONTINUE.dependency, "AddExpectContinue",
183189
HAS_MIDDLEWARE)
184-
.servicePredicate((m, s) -> testServiceId(s))
190+
.servicePredicate((m, s) -> isS3(s))
185191
.build(),
186192
RuntimeClientPlugin.builder()
187193
.withConventions(AwsDependency.SSEC_MIDDLEWARE.dependency, "Ssec", HAS_MIDDLEWARE)
188-
.operationPredicate((m, s, o) -> testInputContainsMember(m, o, SSEC_INPUT_KEYS)
189-
&& testServiceId(s))
194+
.operationPredicate((m, s, o) -> containsInputMembers(m, o, SSEC_INPUT_KEYS)
195+
&& isS3(s))
190196
.build(),
191197
RuntimeClientPlugin.builder()
192198
.withConventions(AwsDependency.LOCATION_CONSTRAINT.dependency, "LocationConstraint",
193199
HAS_MIDDLEWARE)
194200
.operationPredicate((m, s, o) -> o.getId().getName(s).equals("CreateBucket")
195-
&& testServiceId(s))
201+
&& isS3(s))
196202
.build(),
197-
/**
203+
RuntimeClientPlugin.builder()
204+
.withConventions(AwsDependency.S3_MIDDLEWARE.dependency, "S3",
205+
HAS_CONFIG)
206+
.servicePredicate((m, s) -> isS3(s) && isEndpointsV2Service(s))
207+
.build(),
208+
/*
198209
* BUCKET_ENDPOINT_MIDDLEWARE needs two separate plugins. The first resolves the config in the client.
199210
* The second applies the middleware to bucket endpoint operations.
200211
*/
201212
RuntimeClientPlugin.builder()
202213
.withConventions(AwsDependency.BUCKET_ENDPOINT_MIDDLEWARE.dependency, "BucketEndpoint",
203214
HAS_CONFIG)
204-
.servicePredicate((m, s) -> testServiceId(s))
215+
.servicePredicate((m, s) -> isS3(s) && !isEndpointsV2Service(s))
205216
.build(),
206217
RuntimeClientPlugin.builder()
207218
.withConventions(AwsDependency.BUCKET_ENDPOINT_MIDDLEWARE.dependency, "BucketEndpoint",
208219
HAS_MIDDLEWARE)
209220
.operationPredicate((m, s, o) -> !NON_BUCKET_ENDPOINT_OPERATIONS.contains(o.getId().getName(s))
210-
&& testServiceId(s)
211-
&& testInputContainsMember(m, o, BUCKET_ENDPOINT_INPUT_KEYS))
221+
&& isS3(s)
222+
&& !isEndpointsV2Service(s)
223+
&& containsInputMembers(m, o, BUCKET_ENDPOINT_INPUT_KEYS))
212224
.build()
213225
);
214226
}
215227

216-
private static boolean testInputContainsMember(
228+
private static boolean containsInputMembers(
217229
Model model,
218230
OperationShape operationShape,
219231
Set<String> expectedMemberNames
@@ -224,7 +236,7 @@ private static boolean testInputContainsMember(
224236
.isPresent();
225237
}
226238

227-
private static boolean testServiceId(Shape serviceShape) {
239+
private static boolean isS3(Shape serviceShape) {
228240
return serviceShape.getTrait(ServiceTrait.class).map(ServiceTrait::getSdkId).orElse("").equals("S3");
229241
}
230242
}

0 commit comments

Comments
 (0)