Skip to content

Commit c7b7d48

Browse files
committed
Add document shape serialization bodies (#431)
This commit adds support for generating the bodies of functions that serialize complex shapes that will be in an HTTP document body.
1 parent 11844a6 commit c7b7d48

File tree

1 file changed

+112
-6
lines changed
  • codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen

1 file changed

+112
-6
lines changed

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

Lines changed: 112 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,18 @@
1818
import java.util.List;
1919
import software.amazon.smithy.codegen.core.SymbolProvider;
2020
import software.amazon.smithy.model.knowledge.HttpBinding;
21+
import software.amazon.smithy.model.knowledge.HttpBinding.Location;
22+
import software.amazon.smithy.model.shapes.CollectionShape;
23+
import software.amazon.smithy.model.shapes.MapShape;
24+
import software.amazon.smithy.model.shapes.MemberShape;
2125
import software.amazon.smithy.model.shapes.OperationShape;
26+
import software.amazon.smithy.model.shapes.Shape;
27+
import software.amazon.smithy.model.shapes.ShapeIndex;
28+
import software.amazon.smithy.model.shapes.SimpleShape;
29+
import software.amazon.smithy.model.shapes.StructureShape;
30+
import software.amazon.smithy.model.shapes.UnionShape;
2231
import software.amazon.smithy.model.traits.JsonNameTrait;
32+
import software.amazon.smithy.model.traits.TimestampFormatTrait.Format;
2333
import software.amazon.smithy.typescript.codegen.TypeScriptWriter;
2434
import software.amazon.smithy.typescript.codegen.integration.HttpBindingProtocolGenerator;
2535

@@ -35,6 +45,11 @@ protected String getDocumentContentType() {
3545
return "application/x-amz-json-1.1";
3646
}
3747

48+
@Override
49+
protected Format getDocumentTimestampFormat() {
50+
return Format.EPOCH_SECONDS;
51+
}
52+
3853
@Override
3954
protected void serializeDocument(
4055
GenerationContext context,
@@ -52,14 +67,105 @@ protected void serializeDocument(
5267
String locationName = binding.getMember().getTrait(JsonNameTrait.class)
5368
.map(JsonNameTrait::getValue)
5469
.orElseGet(binding::getLocationName);
55-
writer.openBlock("if (input.$L !== undefined) {", "}", memberName, () -> {
56-
// TODO: walk the input to serialize appropriately.
57-
// TODO: we need to serialize Date values as epoch-seconds.
58-
// TODO: we need to serialize blob values as base64 encoded strings.
59-
writer.write("bodyParams['$L'] = input.$L;", locationName, memberName);
60-
});
70+
writeDocumentStructureMemberSerialization(context, operation,
71+
memberName, locationName, binding.getMember());
6172
}
6273

6374
writer.write("body = JSON.stringify(bodyParams);");
6475
}
76+
77+
@Override
78+
protected void serializeDocumentStructure(GenerationContext context, StructureShape shape) {
79+
TypeScriptWriter writer = context.getWriter();
80+
81+
writer.write("let bodyParams: any = {};");
82+
shape.getAllMembers().forEach((memberName, memberShape) -> {
83+
// Use the jsonName trait value if present, otherwise use the member name.
84+
String locationName = memberShape.getTrait(JsonNameTrait.class)
85+
.map(JsonNameTrait::getValue)
86+
.orElse(memberName);
87+
writeDocumentStructureMemberSerialization(context, shape, memberName, locationName, memberShape);
88+
});
89+
writer.write("return bodyParams;");
90+
}
91+
92+
private void writeDocumentStructureMemberSerialization(
93+
GenerationContext context,
94+
Shape container,
95+
String memberName,
96+
String locationName,
97+
MemberShape member
98+
) {
99+
TypeScriptWriter writer = context.getWriter();
100+
Shape target = context.getModel().getShapeIndex().getShape(member.getTarget()).get();
101+
102+
// Generate an if statement to set the bodyParam if the member is set.
103+
writer.openBlock("if (input.$L !== undefined) {", "}", memberName, () -> {
104+
writer.write("bodyParams['$L'] = $L;", locationName,
105+
getInputValue(context, Location.DOCUMENT, container, member, target));
106+
});
107+
}
108+
109+
@Override
110+
protected void serializeDocumentCollection(GenerationContext context, CollectionShape shape) {
111+
TypeScriptWriter writer = context.getWriter();
112+
Shape target = context.getModel().getShapeIndex().getShape(shape.getMember().getTarget()).get();
113+
114+
// Validate we have input, then get the right serialization for the member target.
115+
writer.write("input &&");
116+
writer.openBlock("input.map(entry =>", ");", () -> {
117+
writer.write(getInputValue(context, Location.DOCUMENT, shape, shape.getMember(), target));
118+
});
119+
}
120+
121+
@Override
122+
protected void serializeDocumentMap(GenerationContext context, MapShape shape) {
123+
TypeScriptWriter writer = context.getWriter();
124+
Shape target = context.getModel().getShapeIndex().getShape(shape.getValue().getTarget()).get();
125+
126+
// Validate we have input, then get the right serialization for the map value.
127+
writer.write("input.name &&");
128+
writer.openBlock("input.value && {", "};", () -> {
129+
writer.write("name: input.name,");
130+
writer.write("value: $L", getInputValue(context, Location.DOCUMENT, shape, shape.getValue(), target));
131+
});
132+
}
133+
134+
// TODO Collection cleanup point
135+
// This, and the location it is invoked, can be cleaned up if/when a
136+
// centralized way to check for and/or handle these differences is built.
137+
private boolean isSimpleCollection(ShapeIndex index, Shape shape) {
138+
if (shape instanceof CollectionShape) {
139+
Shape target = index.getShape(((CollectionShape) shape).getMember().getTarget()).get();
140+
if (target instanceof CollectionShape) {
141+
return isSimpleCollection(index, target);
142+
}
143+
return target instanceof SimpleShape;
144+
}
145+
return false;
146+
}
147+
148+
@Override
149+
protected void serializeDocumentUnion(GenerationContext context, UnionShape shape) {
150+
SymbolProvider symbolProvider = context.getSymbolProvider();
151+
TypeScriptWriter writer = context.getWriter();
152+
ShapeIndex index = context.getModel().getShapeIndex();
153+
154+
// Visit over the union type, then get the right serialization for the member.
155+
writer.openBlock("$L.visit(input, {", "});", shape.getId().getName(), () -> {
156+
shape.getAllMembers().forEach((name, member) -> {
157+
writer.openBlock("$L: value => {", "},", symbolProvider.toMemberName(member), () -> {
158+
Shape target = index.getShape(member.getTarget()).get();
159+
// TODO See collection cleanup note
160+
// Make sure we invoke the other serialization of union members that need it.
161+
if (!(target instanceof SimpleShape) && !isSimpleCollection(index, target)) {
162+
writer.write("$L;", getInputValue(context, Location.DOCUMENT, shape, member, target));
163+
} else {
164+
writer.write("value;");
165+
}
166+
});
167+
});
168+
writer.openBlock("_: value => {", "}", () -> writer.write("value;"));
169+
});
170+
}
65171
}

0 commit comments

Comments
 (0)