Skip to content

Commit a566ea5

Browse files
authored
Consume httpQueryParams trait (#311)
1 parent de36124 commit a566ea5

File tree

1 file changed

+64
-12
lines changed

1 file changed

+64
-12
lines changed

smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/integration/HttpBindingProtocolGenerator.java

Lines changed: 64 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -299,36 +299,55 @@ private boolean writeRequestQueryString(
299299
HttpTrait trait
300300
) {
301301
TypeScriptWriter writer = context.getWriter();
302-
SymbolProvider symbolProvider = context.getSymbolProvider();
303302
List<HttpBinding> queryBindings = bindingIndex.getRequestBindings(operation, Location.QUERY);
303+
List<HttpBinding> queryParamsBindings = bindingIndex.getRequestBindings(operation, Location.QUERY_PARAMS);
304304

305305
// Build the initial query bag.
306306
Map<String, String> queryLiterals = trait.getUri().getQueryLiterals();
307-
if (!queryLiterals.isEmpty() || !queryBindings.isEmpty()) {
307+
if (!queryLiterals.isEmpty() || !queryBindings.isEmpty() || !queryParamsBindings.isEmpty()) {
308308
writer.openBlock("const query: any = {", "};", () -> {
309309
if (!queryLiterals.isEmpty()) {
310310
// Write any query literals present in the uri.
311311
queryLiterals.forEach((k, v) -> writer.write("$S: $S,", k, v));
312312
}
313+
// Handle any additional query params bindings.
314+
// If query string parameter is also present in httpQuery, it would be overwritten.
315+
// Serializing HTTP messages https://awslabs.github.io/smithy/1.0/spec/core/http-traits.html#serializing-http-messages
316+
if (!queryParamsBindings.isEmpty()) {
317+
SymbolProvider symbolProvider = context.getSymbolProvider();
318+
String memberName = symbolProvider.toMemberName(queryParamsBindings.get(0).getMember());
319+
writer.write("...(input.$1L !== undefined && input.$1L),", memberName);
320+
}
313321
// Handle any additional query bindings.
314322
if (!queryBindings.isEmpty()) {
315-
Model model = context.getModel();
316323
for (HttpBinding binding : queryBindings) {
317-
String memberName = symbolProvider.toMemberName(binding.getMember());
318-
writer.addImport("extendedEncodeURIComponent", "__extendedEncodeURIComponent",
319-
"@aws-sdk/smithy-client");
320-
Shape target = model.expectShape(binding.getMember().getTarget());
321-
String queryValue = getInputValue(context, binding.getLocation(), "input." + memberName,
322-
binding.getMember(), target);
323-
writer.write("...(input.$L !== undefined && { $S: $L }),", memberName,
324-
binding.getLocationName(), queryValue);
324+
writeRequestQueryParam(context, binding);
325325
}
326326
}
327327
});
328328
}
329329

330330
// Any binding or literal means we generated a query bag.
331-
return !queryBindings.isEmpty() || !queryLiterals.isEmpty();
331+
return !queryBindings.isEmpty() || !queryLiterals.isEmpty() || !queryParamsBindings.isEmpty();
332+
}
333+
334+
private void writeRequestQueryParam(
335+
GenerationContext context,
336+
HttpBinding binding
337+
) {
338+
Model model = context.getModel();
339+
TypeScriptWriter writer = context.getWriter();
340+
SymbolProvider symbolProvider = context.getSymbolProvider();
341+
342+
String memberName = symbolProvider.toMemberName(binding.getMember());
343+
writer.addImport("extendedEncodeURIComponent", "__extendedEncodeURIComponent",
344+
"@aws-sdk/smithy-client");
345+
346+
Shape target = model.expectShape(binding.getMember().getTarget());
347+
String queryValue = getInputValue(context, binding.getLocation(), "input." + memberName,
348+
binding.getMember(), target);
349+
writer.write("...(input.$L !== undefined && { $S: $L }),", memberName,
350+
binding.getLocationName(), queryValue);
332351
}
333352

334353
private void writeHeaders(
@@ -454,6 +473,8 @@ protected String getInputValue(
454473
return getCollectionInputParam(context, bindingType, dataSource, (CollectionShape) target);
455474
} else if (target instanceof StructureShape || target instanceof UnionShape) {
456475
return getNamedMembersInputParam(context, bindingType, dataSource, target);
476+
} else if (target instanceof MapShape) {
477+
return getMapInputParam(context, bindingType, dataSource, (MapShape) target);
457478
}
458479

459480
throw new CodegenException(String.format(
@@ -544,6 +565,7 @@ private String getCollectionInputParam(
544565
case HEADER:
545566
return iteratedParam + ".join(', ')";
546567
case QUERY:
568+
case QUERY_PARAMS:
547569
return iteratedParam;
548570
default:
549571
throw new CodegenException("Unexpected collection binding location `" + bindingType + "`");
@@ -587,6 +609,36 @@ private String getNamedMembersInputParam(
587609
}
588610
}
589611

612+
/**
613+
* Given context and a source of data, generate an input value provider for the
614+
* map.
615+
*
616+
* @param context The generation context.
617+
* @param bindingType How this value is bound to the operation input.
618+
* @param dataSource The in-code location of the data to provide an input of
619+
* ({@code input.foo}, {@code entry}, etc.)
620+
* @param target The shape of the value being provided.
621+
* @return Returns a value or expression of the input collection.
622+
*/
623+
private String getMapInputParam(
624+
GenerationContext context,
625+
Location bindingType,
626+
String dataSource,
627+
MapShape target
628+
) {
629+
Model model = context.getModel();
630+
MemberShape mapMember = target.getValue();
631+
SymbolProvider symbolProvider = context.getSymbolProvider();
632+
633+
String valueString = getInputValue(context, bindingType, "value", mapMember,
634+
model.expectShape(mapMember.getTarget()));
635+
return "Object.entries(" + dataSource + " || {}).reduce("
636+
+ "(acc: any, [key, value]: [string, " + symbolProvider.toSymbol(mapMember) + "]) => ({"
637+
+ "...acc,"
638+
+ "[key]: " + valueString + ","
639+
+ "}), {})";
640+
}
641+
590642
/**
591643
* Given context and a source of data, generate an input value provider for the
592644
* shape. This uses the format specified, converting to strings when in a header,

0 commit comments

Comments
 (0)