Skip to content

Commit 16d6c57

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 c97b52e commit 16d6c57

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;
@@ -708,8 +708,7 @@ private void writeRequestHeaders(
708708
// Headers are always present either from the default document or the payload.
709709
writer.openBlock("const headers: any = {", "};", () -> {
710710
// Only set the content type if one can be determined.
711-
bindingIndex.determineRequestContentType(operation, getDocumentContentType()).ifPresent(contentType ->
712-
writer.write("'content-type': $S,", contentType));
711+
writeContentTypeHeader(context, operation, true);
713712
writeDefaultHeaders(context, operation, true);
714713

715714
operation.getInput().ifPresent(outputId -> {
@@ -759,17 +758,15 @@ private void writePrefixHeaders(GenerationContext context, HttpBinding binding)
759758

760759
private void writeResponseHeaders(
761760
GenerationContext context,
762-
ToShapeId operationOrError,
761+
Shape operationOrError,
763762
HttpBindingIndex bindingIndex,
764763
Runnable injectExtraHeaders
765764
) {
766765
TypeScriptWriter writer = context.getWriter();
767766

768767
// Headers are always present either from the default document or the payload.
769768
writer.openBlock("const headers: any = {", "};", () -> {
770-
// Only set the content type if one can be determined.
771-
bindingIndex.determineResponseContentType(operationOrError, getDocumentContentType())
772-
.ifPresent(contentType -> writer.write("'content-type': $S,", contentType));
769+
writeContentTypeHeader(context, operationOrError, false);
773770
injectExtraHeaders.run();
774771

775772
for (HttpBinding binding : bindingIndex.getResponseBindings(operationOrError, Location.HEADER)) {
@@ -783,31 +780,66 @@ private void writeResponseHeaders(
783780
});
784781
}
785782

783+
private void writeContentTypeHeader(GenerationContext context, Shape operationOrError, boolean isInput) {
784+
HttpBindingIndex bindingIndex = HttpBindingIndex.of(context.getModel());
785+
Optional<String> optionalContentType;
786+
if (isInput) {
787+
optionalContentType = bindingIndex.determineRequestContentType(operationOrError, getDocumentContentType());
788+
} else {
789+
optionalContentType = bindingIndex.determineResponseContentType(operationOrError, getDocumentContentType());
790+
}
791+
// If we need to write a default body then it needs a content type.
792+
if (!optionalContentType.isPresent() && shouldWriteDefaultBody(context, operationOrError, isInput)) {
793+
optionalContentType = Optional.of(getDocumentContentType());
794+
}
795+
optionalContentType.ifPresent(contentType -> context.getWriter().write("'content-type': $S,", contentType));
796+
}
797+
786798
private List<HttpBinding> writeRequestBody(
787799
GenerationContext context,
788800
OperationShape operation,
789801
HttpBindingIndex bindingIndex
790802
) {
791803
List<HttpBinding> payloadBindings = bindingIndex.getRequestBindings(operation, Location.PAYLOAD);
792804
List<HttpBinding> documentBindings = bindingIndex.getRequestBindings(operation, Location.DOCUMENT);
793-
boolean shouldWriteDefaultBody = bindingIndex.getRequestBindings(operation).isEmpty();
805+
boolean shouldWriteDefaultBody = shouldWriteDefaultBody(context, operation, true);
794806
return writeBody(context, operation, payloadBindings, documentBindings, shouldWriteDefaultBody, true);
795807
}
796808

797809
private List<HttpBinding> writeResponseBody(
798810
GenerationContext context,
799-
ToShapeId operationOrError,
811+
Shape operationOrError,
800812
HttpBindingIndex bindingIndex
801813
) {
802814
// We just make one up here since it's not actually used by consumers.
803815
// TODO: remove the need for this at all
804816
OperationShape operation = OperationShape.builder().id("ns.foo#bar").build();
805817
List<HttpBinding> payloadBindings = bindingIndex.getResponseBindings(operationOrError, Location.PAYLOAD);
806818
List<HttpBinding> documentBindings = bindingIndex.getResponseBindings(operationOrError, Location.DOCUMENT);
807-
boolean shouldWriteDefaultBody = bindingIndex.getResponseBindings(operationOrError).isEmpty();
819+
boolean shouldWriteDefaultBody = shouldWriteDefaultBody(context, operationOrError, false);
808820
return writeBody(context, operation, payloadBindings, documentBindings, shouldWriteDefaultBody, false);
809821
}
810822

823+
/**
824+
* Given a context, operation/error, and whether the shape is being serialized for input or output,
825+
* should a default body be written. By default no body will be written if there are no members bound
826+
* to the input/output/error.
827+
*
828+
* @param context The generation context.
829+
* @param operationOrError The operation or error being serialized.
830+
* @param isInput Whether the body being generated is for an input or an output.
831+
*
832+
* @return True if a default body should be generated.
833+
*/
834+
protected boolean shouldWriteDefaultBody(GenerationContext context, Shape operationOrError, boolean isInput) {
835+
HttpBindingIndex bindingIndex = HttpBindingIndex.of(context.getModel());
836+
if (isInput) {
837+
return bindingIndex.getRequestBindings(operationOrError).isEmpty();
838+
} else {
839+
return bindingIndex.getResponseBindings(operationOrError).isEmpty();
840+
}
841+
}
842+
811843
private List<HttpBinding> writeBody(
812844
GenerationContext context,
813845
OperationShape operation,

0 commit comments

Comments
 (0)