Skip to content

Commit 45d352d

Browse files
gosarJordonPhillips
authored andcommitted
Support generating non-AWS client (aws#2222)
* feat(config-resolver): make region optional for non-AWS client * feat(codegen): skip integrations that are not relevant for non-AWS services This is an initial version to get a working version of generated code that compiles without manual edits in smithy-typescript-ssdk-demo. I expect to make updates to this logic. * chore(codegen): address code comments The minor ones from adamthom-amzn#1 * fix(codegen): use SigV4Trait check instead of ServiceTrait AddAwsRuntimeConfigTest is checking for some behaviors from AddAwsAuthPlugin too, which was failing with missing aws.auth#sigv4 trait after my change. Added the trait for now to the test, but unit tests will need to be added/refactored for all these changes. * chore(codegen): move isAwsService check to utils class * chore(codegen): code style formatting * chore(codegen): check SigV4 trait for including region
1 parent 4d41040 commit 45d352d

File tree

10 files changed

+151
-52
lines changed

10 files changed

+151
-52
lines changed

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

+14-7
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.isSigV4Service;
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

@@ -46,6 +47,7 @@
4647
/**
4748
* Configure clients with AWS auth configurations and plugin.
4849
*/
50+
// TODO: Think about AWS Auth supported for only some operations and not all, when not AWS service, with say @auth([])
4951
public final class AddAwsAuthPlugin implements TypeScriptIntegration {
5052
static final String STS_CLIENT_PREFIX = "sts-client-";
5153
static final String ROLE_ASSUMERS_FILE = "defaultRoleAssumers";
@@ -59,6 +61,9 @@ public void addConfigInterfaceFields(
5961
TypeScriptWriter writer
6062
) {
6163
ServiceShape service = settings.getService(model);
64+
if (!isSigV4Service(service)) {
65+
return;
66+
}
6267
if (!areAllOptionalAuthOperations(model, service)) {
6368
writer.addImport("Credentials", "__Credentials", TypeScriptDependency.AWS_SDK_TYPES.packageName);
6469
writer.writeDocs("Default credentials provider; Not available in browser runtime.")
@@ -71,7 +76,9 @@ public List<RuntimeClientPlugin> getClientPlugins() {
7176
return ListUtils.of(
7277
RuntimeClientPlugin.builder()
7378
.withConventions(AwsDependency.MIDDLEWARE_SIGNING.dependency, "AwsAuth", HAS_CONFIG)
74-
.servicePredicate((m, s) -> !areAllOptionalAuthOperations(m, s) && !testServiceId(s, "STS"))
79+
.servicePredicate((m, s) -> isSigV4Service(s)
80+
&& !areAllOptionalAuthOperations(m, s)
81+
&& !testServiceId(s, "STS"))
7582
.build(),
7683
RuntimeClientPlugin.builder()
7784
.withConventions(AwsDependency.STS_MIDDLEWARE.dependency,
@@ -83,7 +90,7 @@ public List<RuntimeClientPlugin> getClientPlugins() {
8390
.withConventions(AwsDependency.MIDDLEWARE_SIGNING.dependency, "AwsAuth", HAS_MIDDLEWARE)
8491
// See operationUsesAwsAuth() below for AwsAuth Middleware customizations.
8592
.servicePredicate(
86-
(m, s) -> !testServiceId(s, "STS") && !hasOptionalAuthOperation(m, s)
93+
(m, s) -> !testServiceId(s, "STS") && isSigV4Service(s) && !hasOptionalAuthOperation(m, s)
8794
).build(),
8895
RuntimeClientPlugin.builder()
8996
.withConventions(AwsDependency.MIDDLEWARE_SIGNING.dependency, "AwsAuth", HAS_MIDDLEWARE)
@@ -100,7 +107,7 @@ public Map<String, Consumer<TypeScriptWriter>> getRuntimeConfigWriters(
100107
LanguageTarget target
101108
) {
102109
ServiceShape service = settings.getService(model);
103-
if (areAllOptionalAuthOperations(model, service)) {
110+
if (!isSigV4Service(service) || areAllOptionalAuthOperations(model, service)) {
104111
return Collections.emptyMap();
105112
}
106113
switch (target) {
@@ -187,8 +194,8 @@ private static boolean operationUsesAwsAuth(Model model, ServiceShape service, O
187194
}
188195

189196
// optionalAuth trait doesn't require authentication.
190-
if (hasOptionalAuthOperation(model, service)) {
191-
return !operation.getTrait(OptionalAuthTrait.class).isPresent();
197+
if (isSigV4Service(service) && hasOptionalAuthOperation(model, service)) {
198+
return !operation.hasTrait(OptionalAuthTrait.class);
192199
}
193200
return false;
194201
}
@@ -197,7 +204,7 @@ private static boolean hasOptionalAuthOperation(Model model, ServiceShape servic
197204
TopDownIndex topDownIndex = TopDownIndex.of(model);
198205
Set<OperationShape> operations = topDownIndex.getContainedOperations(service);
199206
for (OperationShape operation : operations) {
200-
if (operation.getTrait(OptionalAuthTrait.class).isPresent()) {
207+
if (operation.hasTrait(OptionalAuthTrait.class)) {
201208
return true;
202209
}
203210
}
@@ -208,7 +215,7 @@ private static boolean areAllOptionalAuthOperations(Model model, ServiceShape se
208215
TopDownIndex topDownIndex = TopDownIndex.of(model);
209216
Set<OperationShape> operations = topDownIndex.getContainedOperations(service);
210217
for (OperationShape operation : operations) {
211-
if (!operation.getTrait(OptionalAuthTrait.class).isPresent()) {
218+
if (!operation.hasTrait(OptionalAuthTrait.class)) {
212219
return false;
213220
}
214221
}

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

+60-38
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515

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

18+
import static software.amazon.smithy.aws.typescript.codegen.AwsTraitsUtils.isAwsService;
19+
import static software.amazon.smithy.aws.typescript.codegen.AwsTraitsUtils.isSigV4Service;
20+
1821
import java.util.Collections;
1922
import java.util.HashMap;
2023
import java.util.Map;
@@ -31,6 +34,9 @@
3134
import software.amazon.smithy.typescript.codegen.integration.TypeScriptIntegration;
3235
import software.amazon.smithy.utils.MapUtils;
3336

37+
// TODO: This javadoc is specific to needs of AWS client. However it has elements that would be needed by non-AWS
38+
// clients too, like logger, region for SigV4. We should refactor these into different Integration or rename this
39+
// class to be generic.
3440
/**
3541
* AWS clients need to know the service name for collecting metrics, the
3642
* region name used to resolve endpoints, the max attempt to retry a request
@@ -82,10 +88,14 @@ public void addConfigInterfaceFields(
8288
writer.addImport("Provider", "__Provider", TypeScriptDependency.AWS_SDK_TYPES.packageName);
8389
writer.addImport("Logger", "__Logger", TypeScriptDependency.AWS_SDK_TYPES.packageName);
8490

85-
writer.writeDocs("Unique service identifier.\n@internal")
86-
.write("serviceId?: string;\n");
87-
writer.writeDocs("The AWS region to which this client will send requests")
88-
.write("region?: string | __Provider<string>;\n");
91+
if (isAwsService(settings, model)) {
92+
writer.writeDocs("Unique service identifier.\n@internal")
93+
.write("serviceId?: string;\n");
94+
}
95+
if (isSigV4Service(settings, model)) {
96+
writer.writeDocs("The AWS region to which this client will send requests or use as signingRegion")
97+
.write("region?: string | __Provider<string>;\n");
98+
}
8999
writer.writeDocs("Value for how many times a request will be made at most in case of retry.")
90100
.write("maxAttempts?: number | __Provider<number>;\n");
91101
writer.writeDocs("Optional logger for logging debug/info/warn/error.")
@@ -114,11 +124,17 @@ public Map<String, Consumer<TypeScriptWriter>> getRuntimeConfigWriters(
114124
+ "trait was found on " + service.getId());
115125
}
116126
}
117-
runtimeConfigs.putAll(getDefaultConfig(target));
127+
runtimeConfigs.putAll(getDefaultConfig(target, settings, model));
118128
return runtimeConfigs;
119129
}
120130

121-
private Map<String, Consumer<TypeScriptWriter>> getDefaultConfig(LanguageTarget target) {
131+
private Map<String, Consumer<TypeScriptWriter>> getDefaultConfig(
132+
LanguageTarget target,
133+
TypeScriptSettings settings,
134+
Model model
135+
) {
136+
Map<String, Consumer<TypeScriptWriter>> defaultConfigs = new HashMap();
137+
boolean isSigV4Service = isSigV4Service(settings, model);
122138
switch (target) {
123139
case SHARED:
124140
return MapUtils.of(
@@ -128,40 +144,46 @@ private Map<String, Consumer<TypeScriptWriter>> getDefaultConfig(LanguageTarget
128144
}
129145
);
130146
case BROWSER:
131-
return MapUtils.of(
132-
"region", writer -> {
133-
writer.addDependency(TypeScriptDependency.INVALID_DEPENDENCY);
134-
writer.addImport("invalidProvider", "invalidProvider",
135-
TypeScriptDependency.INVALID_DEPENDENCY.packageName);
136-
writer.write("region: invalidProvider(\"Region is missing\"),");
137-
},
138-
"maxAttempts", writer -> {
139-
writer.addDependency(TypeScriptDependency.MIDDLEWARE_RETRY);
140-
writer.addImport("DEFAULT_MAX_ATTEMPTS", "DEFAULT_MAX_ATTEMPTS",
141-
TypeScriptDependency.MIDDLEWARE_RETRY.packageName);
142-
writer.write("maxAttempts: DEFAULT_MAX_ATTEMPTS,");
143-
}
144-
);
147+
if (isSigV4Service) {
148+
defaultConfigs.put("region", writer -> {
149+
writer.addDependency(TypeScriptDependency.INVALID_DEPENDENCY);
150+
writer.addImport("invalidProvider", "invalidProvider",
151+
TypeScriptDependency.INVALID_DEPENDENCY.packageName);
152+
writer.write("region: invalidProvider(\"Region is missing\"),");
153+
});
154+
}
155+
defaultConfigs.put("maxAttempts", writer -> {
156+
writer.addDependency(TypeScriptDependency.MIDDLEWARE_RETRY);
157+
writer.addImport("DEFAULT_MAX_ATTEMPTS", "DEFAULT_MAX_ATTEMPTS",
158+
TypeScriptDependency.MIDDLEWARE_RETRY.packageName);
159+
writer.write("maxAttempts: DEFAULT_MAX_ATTEMPTS,");
160+
});
161+
return defaultConfigs;
145162
case NODE:
146-
return MapUtils.of(
147-
"region", writer -> {
148-
writer.addDependency(AwsDependency.NODE_CONFIG_PROVIDER);
149-
writer.addImport("loadConfig", "loadNodeConfig",
150-
AwsDependency.NODE_CONFIG_PROVIDER.packageName);
151-
writer.addDependency(TypeScriptDependency.CONFIG_RESOLVER);
152-
writer.addImport("NODE_REGION_CONFIG_OPTIONS", "NODE_REGION_CONFIG_OPTIONS",
153-
TypeScriptDependency.CONFIG_RESOLVER.packageName);
154-
writer.addImport("NODE_REGION_CONFIG_FILE_OPTIONS", "NODE_REGION_CONFIG_FILE_OPTIONS",
155-
TypeScriptDependency.CONFIG_RESOLVER.packageName);
156-
writer.write(
163+
if (isSigV4Service) {
164+
// TODO: For non-AWS service, figure out how the region should be configured.
165+
defaultConfigs.put("region", writer -> {
166+
writer.addDependency(AwsDependency.NODE_CONFIG_PROVIDER);
167+
writer.addImport("loadConfig", "loadNodeConfig",
168+
AwsDependency.NODE_CONFIG_PROVIDER.packageName);
169+
writer.addDependency(TypeScriptDependency.CONFIG_RESOLVER);
170+
writer.addImport("NODE_REGION_CONFIG_OPTIONS", "NODE_REGION_CONFIG_OPTIONS",
171+
TypeScriptDependency.CONFIG_RESOLVER.packageName);
172+
writer.addImport("NODE_REGION_CONFIG_FILE_OPTIONS", "NODE_REGION_CONFIG_FILE_OPTIONS",
173+
TypeScriptDependency.CONFIG_RESOLVER.packageName);
174+
writer.write(
157175
"region: loadNodeConfig(NODE_REGION_CONFIG_OPTIONS, NODE_REGION_CONFIG_FILE_OPTIONS),");
158-
},
159-
"maxAttempts", writer -> {
160-
writer.addImport("NODE_MAX_ATTEMPT_CONFIG_OPTIONS", "NODE_MAX_ATTEMPT_CONFIG_OPTIONS",
161-
TypeScriptDependency.MIDDLEWARE_RETRY.packageName);
162-
writer.write("maxAttempts: loadNodeConfig(NODE_MAX_ATTEMPT_CONFIG_OPTIONS),");
163-
}
164-
);
176+
});
177+
}
178+
defaultConfigs.put("maxAttempts", writer -> {
179+
writer.addDependency(AwsDependency.NODE_CONFIG_PROVIDER);
180+
writer.addImport("loadConfig", "loadNodeConfig",
181+
AwsDependency.NODE_CONFIG_PROVIDER.packageName);
182+
writer.addImport("NODE_MAX_ATTEMPT_CONFIG_OPTIONS", "NODE_MAX_ATTEMPT_CONFIG_OPTIONS",
183+
TypeScriptDependency.MIDDLEWARE_RETRY.packageName);
184+
writer.write("maxAttempts: loadNodeConfig(NODE_MAX_ATTEMPT_CONFIG_OPTIONS),");
185+
});
186+
return defaultConfigs;
165187
default:
166188
return Collections.emptyMap();
167189
}

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

+2
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.isAwsService;
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

@@ -44,6 +45,7 @@ public List<RuntimeClientPlugin> getClientPlugins() {
4445
return ListUtils.of(
4546
RuntimeClientPlugin.builder()
4647
.withConventions(TypeScriptDependency.CONFIG_RESOLVER.dependency, "Region", HAS_CONFIG)
48+
.servicePredicate((m, s) -> isAwsService(s))
4749
.build(),
4850
RuntimeClientPlugin.builder()
4951
.withConventions(TypeScriptDependency.CONFIG_RESOLVER.dependency, "Endpoints", HAS_CONFIG)

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

+12-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

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

18+
import static software.amazon.smithy.aws.typescript.codegen.AwsTraitsUtils.isAwsService;
19+
1820
import java.util.Collections;
1921
import java.util.List;
2022
import java.util.Map;
@@ -33,12 +35,15 @@
3335
/**
3436
* Add client plubins and configs to support injecting user agent.
3537
*/
38+
// TODO: Looks to add this back for non-AWS service clients, by fixing the dependency on ClientSharedValues.serviceId
3639
public class AddUserAgentDependency implements TypeScriptIntegration {
3740
@Override
3841
public List<RuntimeClientPlugin> getClientPlugins() {
3942
return ListUtils.of(
4043
RuntimeClientPlugin.builder()
41-
.withConventions(AwsDependency.MIDDLEWARE_USER_AGENT.dependency, "UserAgent").build());
44+
.withConventions(AwsDependency.MIDDLEWARE_USER_AGENT.dependency, "UserAgent")
45+
.servicePredicate((m, s) -> isAwsService(s))
46+
.build());
4247
}
4348

4449
@Override
@@ -48,6 +53,9 @@ public void addConfigInterfaceFields(
4853
SymbolProvider symbolProvider,
4954
TypeScriptWriter writer
5055
) {
56+
if (!isAwsService(settings, model)) {
57+
return;
58+
}
5159
writer.addImport("Provider", "Provider", TypeScriptDependency.AWS_SDK_TYPES.packageName);
5260
writer.addImport("UserAgent", "__UserAgent", TypeScriptDependency.AWS_SDK_TYPES.packageName);
5361
writer.writeDocs("The provider populating default tracking information to be sent with `user-agent`, "
@@ -62,6 +70,9 @@ public Map<String, Consumer<TypeScriptWriter>> getRuntimeConfigWriters(
6270
SymbolProvider symbolProvider,
6371
LanguageTarget target
6472
) {
73+
if (!isAwsService(settings, model)) {
74+
return Collections.emptyMap();
75+
}
6576
switch (target) {
6677
case NODE:
6778
return MapUtils.of(

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

+5-3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

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

18+
import static software.amazon.smithy.aws.typescript.codegen.AwsTraitsUtils.isAwsService;
19+
1820
import java.util.Collections;
1921
import java.util.Map;
2022
import java.util.function.BiConsumer;
@@ -39,7 +41,7 @@ public void writeAdditionalFiles(
3941
SymbolProvider symbolProvider,
4042
BiConsumer<String, Consumer<TypeScriptWriter>> writerFactory
4143
) {
42-
if (!settings.generateClient()) {
44+
if (!settings.generateClient() || !isAwsService(settings, model)) {
4345
return;
4446
}
4547

@@ -55,7 +57,7 @@ public void addConfigInterfaceFields(
5557
SymbolProvider symbolProvider,
5658
TypeScriptWriter writer
5759
) {
58-
if (!settings.generateClient()) {
60+
if (!settings.generateClient() || !isAwsService(settings, model)) {
5961
return;
6062
}
6163

@@ -71,7 +73,7 @@ public Map<String, Consumer<TypeScriptWriter>> getRuntimeConfigWriters(
7173
SymbolProvider symbolProvider,
7274
LanguageTarget target
7375
) {
74-
if (!settings.generateClient()) {
76+
if (!settings.generateClient() || !isAwsService(settings, model)) {
7577
return Collections.emptyMap();
7678
}
7779

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

+4-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

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

18+
import static software.amazon.smithy.aws.typescript.codegen.AwsTraitsUtils.isAwsService;
19+
1820
import java.util.Arrays;
1921
import java.util.Calendar;
2022
import java.util.function.BiConsumer;
@@ -56,7 +58,8 @@ public void writeAdditionalFiles(
5658
writer.write(resource);
5759
});
5860

59-
if (!settings.generateClient()) {
61+
// TODO: May need to generate a different/modified README.md for these cases
62+
if (!settings.generateClient() || !isAwsService(settings, model)) {
6063
return;
6164
}
6265

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

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public SymbolProvider decorateSymbolProvider(
4444
return symbol;
4545
}
4646

47+
// TODO: Should this WARNING be avoided somehow if client is not for an AWS service?
4748
// If the SDK service ID trait is present, use that, otherwise fall back to
4849
// the default naming strategy for the service.
4950
return shape.getTrait(ServiceTrait.class)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.smithy.aws.typescript.codegen;
17+
18+
import software.amazon.smithy.aws.traits.ServiceTrait;
19+
import software.amazon.smithy.aws.traits.auth.SigV4Trait;
20+
import software.amazon.smithy.model.Model;
21+
import software.amazon.smithy.model.shapes.ServiceShape;
22+
import software.amazon.smithy.typescript.codegen.TypeScriptSettings;
23+
24+
/**
25+
* Utility methods related to AWS traits.
26+
*/
27+
final class AwsTraitsUtils {
28+
29+
private AwsTraitsUtils() {}
30+
31+
static boolean isAwsService(TypeScriptSettings settings, Model model) {
32+
return isAwsService(settings.getService(model));
33+
}
34+
35+
static boolean isAwsService(ServiceShape serviceShape) {
36+
return serviceShape.hasTrait(ServiceTrait.class);
37+
}
38+
39+
static boolean isSigV4Service(TypeScriptSettings settings, Model model) {
40+
return isSigV4Service(settings.getService(model));
41+
}
42+
43+
static boolean isSigV4Service(ServiceShape serviceShape) {
44+
return serviceShape.hasTrait(SigV4Trait.class);
45+
}
46+
}

0 commit comments

Comments
 (0)