2323import java .util .List ;
2424import java .util .Locale ;
2525import java .util .Map ;
26+ import java .util .Optional ;
2627import java .util .Set ;
2728import java .util .TreeMap ;
2829import java .util .TreeSet ;
5354import software .amazon .smithy .model .shapes .StringShape ;
5455import software .amazon .smithy .model .shapes .StructureShape ;
5556import software .amazon .smithy .model .shapes .TimestampShape ;
56- import software .amazon .smithy .model .shapes .ToShapeId ;
5757import software .amazon .smithy .model .shapes .UnionShape ;
5858import software .amazon .smithy .model .traits .EndpointTrait ;
5959import 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