Skip to content

Commit 13c164d

Browse files
Give http protocols ability to set default bodies
This adds a protected method that allows http binding protocols to customize when a default body should be set. This is needed for restJson1 which has some complicated rules around that.
1 parent 6a19573 commit 13c164d

File tree

1 file changed

+42
-10
lines changed

1 file changed

+42
-10
lines changed

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

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.util.List;
2424
import java.util.Locale;
2525
import java.util.Map;
26+
import java.util.Optional;
2627
import java.util.Set;
2728
import java.util.TreeMap;
2829
import java.util.TreeSet;
@@ -53,7 +54,6 @@
5354
import software.amazon.smithy.model.shapes.StringShape;
5455
import software.amazon.smithy.model.shapes.StructureShape;
5556
import software.amazon.smithy.model.shapes.TimestampShape;
56-
import software.amazon.smithy.model.shapes.ToShapeId;
5757
import software.amazon.smithy.model.shapes.UnionShape;
5858
import software.amazon.smithy.model.traits.EndpointTrait;
5959
import software.amazon.smithy.model.traits.ErrorTrait;
@@ -721,8 +721,7 @@ private void writeRequestHeaders(
721721
// Headers are always present either from the default document or the payload.
722722
writer.openBlock("const headers: any = {", "};", () -> {
723723
// Only set the content type if one can be determined.
724-
bindingIndex.determineRequestContentType(operation, getDocumentContentType()).ifPresent(contentType ->
725-
writer.write("'content-type': $S,", contentType));
724+
writeContentTypeHeader(context, operation, true);
726725
writeDefaultHeaders(context, operation, true);
727726

728727
operation.getInput().ifPresent(outputId -> {
@@ -772,17 +771,15 @@ private void writePrefixHeaders(GenerationContext context, HttpBinding binding)
772771

773772
private void writeResponseHeaders(
774773
GenerationContext context,
775-
ToShapeId operationOrError,
774+
Shape operationOrError,
776775
HttpBindingIndex bindingIndex,
777776
Runnable injectExtraHeaders
778777
) {
779778
TypeScriptWriter writer = context.getWriter();
780779

781780
// Headers are always present either from the default document or the payload.
782781
writer.openBlock("const headers: any = {", "};", () -> {
783-
// Only set the content type if one can be determined.
784-
bindingIndex.determineResponseContentType(operationOrError, getDocumentContentType())
785-
.ifPresent(contentType -> writer.write("'content-type': $S,", contentType));
782+
writeContentTypeHeader(context, operationOrError, false);
786783
injectExtraHeaders.run();
787784

788785
for (HttpBinding binding : bindingIndex.getResponseBindings(operationOrError, Location.HEADER)) {
@@ -796,31 +793,66 @@ private void writeResponseHeaders(
796793
});
797794
}
798795

796+
private void writeContentTypeHeader(GenerationContext context, Shape operationOrError, boolean isInput) {
797+
HttpBindingIndex bindingIndex = HttpBindingIndex.of(context.getModel());
798+
Optional<String> optionalContentType;
799+
if (isInput) {
800+
optionalContentType = bindingIndex.determineRequestContentType(operationOrError, getDocumentContentType());
801+
} else {
802+
optionalContentType = bindingIndex.determineResponseContentType(operationOrError, getDocumentContentType());
803+
}
804+
// If we need to write a default body then it needs a content type.
805+
if (!optionalContentType.isPresent() && shouldWriteDefaultBody(context, operationOrError, isInput)) {
806+
optionalContentType = Optional.of(getDocumentContentType());
807+
}
808+
optionalContentType.ifPresent(contentType -> context.getWriter().write("'content-type': $S,", contentType));
809+
}
810+
799811
private List<HttpBinding> writeRequestBody(
800812
GenerationContext context,
801813
OperationShape operation,
802814
HttpBindingIndex bindingIndex
803815
) {
804816
List<HttpBinding> payloadBindings = bindingIndex.getRequestBindings(operation, Location.PAYLOAD);
805817
List<HttpBinding> documentBindings = bindingIndex.getRequestBindings(operation, Location.DOCUMENT);
806-
boolean shouldWriteDefaultBody = bindingIndex.getRequestBindings(operation).isEmpty();
818+
boolean shouldWriteDefaultBody = shouldWriteDefaultBody(context, operation, true);
807819
return writeBody(context, operation, payloadBindings, documentBindings, shouldWriteDefaultBody, true);
808820
}
809821

810822
private List<HttpBinding> writeResponseBody(
811823
GenerationContext context,
812-
ToShapeId operationOrError,
824+
Shape operationOrError,
813825
HttpBindingIndex bindingIndex
814826
) {
815827
// We just make one up here since it's not actually used by consumers.
816828
// TODO: remove the need for this at all
817829
OperationShape operation = OperationShape.builder().id("ns.foo#bar").build();
818830
List<HttpBinding> payloadBindings = bindingIndex.getResponseBindings(operationOrError, Location.PAYLOAD);
819831
List<HttpBinding> documentBindings = bindingIndex.getResponseBindings(operationOrError, Location.DOCUMENT);
820-
boolean shouldWriteDefaultBody = bindingIndex.getResponseBindings(operationOrError).isEmpty();
832+
boolean shouldWriteDefaultBody = shouldWriteDefaultBody(context, operationOrError, false);
821833
return writeBody(context, operation, payloadBindings, documentBindings, shouldWriteDefaultBody, false);
822834
}
823835

836+
/**
837+
* Given a context, operation/error, and whether the shape is being serialized for input or output,
838+
* should a default body be written. By default no body will be written if there are no members bound
839+
* to the input/output/error.
840+
*
841+
* @param context The generation context.
842+
* @param operationOrError The operation or error being serialized.
843+
* @param isInput Whether the body being generated is for an input or an output.
844+
*
845+
* @return True if a default body should be generated.
846+
*/
847+
protected boolean shouldWriteDefaultBody(GenerationContext context, Shape operationOrError, boolean isInput) {
848+
HttpBindingIndex bindingIndex = HttpBindingIndex.of(context.getModel());
849+
if (isInput) {
850+
return bindingIndex.getRequestBindings(operationOrError).isEmpty();
851+
} else {
852+
return bindingIndex.getResponseBindings(operationOrError).isEmpty();
853+
}
854+
}
855+
824856
private List<HttpBinding> writeBody(
825857
GenerationContext context,
826858
OperationShape operation,

0 commit comments

Comments
 (0)