diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocolTestGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocolTestGenerator.kt
index f422404ea6bdd811e6b1f4ac2b1761af5e6d7783..3b35107914770cbed71c93d47461bdd1aa58ca80 100644
--- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocolTestGenerator.kt
+++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/generators/protocol/ServerProtocolTestGenerator.kt
@@ -506,7 +506,6 @@ class ServerProtocolTestGenerator(
             FailingTest(RestJson, "RestJsonSupportsNaNFloatHeaderInputs", Action.Request),
             FailingTest(RestJson, "RestJsonInputAndOutputWithQuotedStringHeaders", Action.Response),
 
-            FailingTest(RestJson, "RestJsonEmptyInputAndEmptyOutput", Action.Response),
             FailingTest(RestJson, "RestJsonUnitInputAndOutputNoOutput", Action.Response),
             FailingTest(RestJson, "RestJsonSupportsNaNFloatQueryValues", Action.Request),
             FailingTest(RestJson, "DocumentTypeAsPayloadOutput", Action.Response),
@@ -527,10 +526,8 @@ class ServerProtocolTestGenerator(
             FailingTest(RestJson, "RestJsonHttpPayloadTraitsWithMediaTypeWithBlob", Action.Response),
             FailingTest(RestJson, "RestJsonHttpPayloadWithStructure", Action.Response),
             FailingTest(RestJson, "RestJsonSupportsNaNFloatLabels", Action.Request),
-            FailingTest(RestJson, "RestJsonHttpResponseCode", Action.Response),
             FailingTest(RestJson, "StringPayloadResponse", Action.Response),
             FailingTest(RestJson, "RestJsonNoInputAndNoOutput", Action.Response),
-            FailingTest(RestJson, "RestJsonNoInputAndOutputWithJson", Action.Response),
             FailingTest(RestJson, "RestJsonSupportsNaNFloatInputs", Action.Request),
             FailingTest(RestJson, "RestJsonStreamingTraitsRequireLengthWithBlob", Action.Response),
             FailingTest(RestJson, "RestJsonHttpWithEmptyBlobPayload", Action.Request),
diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerHttpProtocolGenerator.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerHttpProtocolGenerator.kt
index 69b5ff766c1ac417fdf81a809057a8e746eab8cc..804616b96ccd61af609b43ae2f12b342eae2b5bb 100644
--- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerHttpProtocolGenerator.kt
+++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerHttpProtocolGenerator.kt
@@ -103,7 +103,7 @@ private class ServerHttpProtocolImplGenerator(
     private val symbolProvider = codegenContext.symbolProvider
     private val model = codegenContext.model
     private val runtimeConfig = codegenContext.runtimeConfig
-    val httpBindingResolver = protocol.httpBindingResolver
+    private val httpBindingResolver = protocol.httpBindingResolver
     private val operationDeserModule = RustModule.private("operation_deser")
     private val operationSerModule = RustModule.private("operation_ser")
 
diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerRestJson.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerRestJson.kt
index e83718884acdf2c6e574e6eb51c4a2046ec65a3c..76c19531b8628aec74d84e402ad79d9b6186fe85 100644
--- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerRestJson.kt
+++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerRestJson.kt
@@ -6,35 +6,21 @@
 package software.amazon.smithy.rust.codegen.server.smithy.protocols
 
 import software.amazon.smithy.model.Model
-import software.amazon.smithy.model.shapes.OperationShape
-import software.amazon.smithy.model.traits.TimestampFormatTrait
-import software.amazon.smithy.rust.codegen.rustlang.CargoDependency
-import software.amazon.smithy.rust.codegen.rustlang.RustModule
-import software.amazon.smithy.rust.codegen.rustlang.asType
-import software.amazon.smithy.rust.codegen.rustlang.rustTemplate
 import software.amazon.smithy.rust.codegen.smithy.CodegenContext
-import software.amazon.smithy.rust.codegen.smithy.RuntimeType
 import software.amazon.smithy.rust.codegen.smithy.generators.protocol.ProtocolSupport
-import software.amazon.smithy.rust.codegen.smithy.protocols.HttpBindingResolver
-import software.amazon.smithy.rust.codegen.smithy.protocols.HttpTraitHttpBindingResolver
 import software.amazon.smithy.rust.codegen.smithy.protocols.Protocol
-import software.amazon.smithy.rust.codegen.smithy.protocols.ProtocolContentTypes
 import software.amazon.smithy.rust.codegen.smithy.protocols.ProtocolGeneratorFactory
-import software.amazon.smithy.rust.codegen.smithy.protocols.parse.JsonParserGenerator
-import software.amazon.smithy.rust.codegen.smithy.protocols.parse.StructuredDataParserGenerator
-import software.amazon.smithy.rust.codegen.smithy.protocols.restJsonFieldName
-import software.amazon.smithy.rust.codegen.smithy.protocols.serialize.JsonSerializerGenerator
-import software.amazon.smithy.rust.codegen.smithy.protocols.serialize.StructuredDataSerializerGenerator
+import software.amazon.smithy.rust.codegen.smithy.protocols.RestJson
 
 /*
- * RestJson1 server-side protocol implementation and details. This factory generates the [ServerHttpProtocolGenerator]
+ * RestJson1 server-side protocol factory. This factory creates the [ServerHttpProtocolGenerator]
  * with RestJson1 specific configurations.
  */
 class ServerRestJsonFactory : ProtocolGeneratorFactory<ServerHttpProtocolGenerator> {
-    override fun protocol(codegenContext: CodegenContext): Protocol = ServerRestJson(codegenContext)
+    override fun protocol(codegenContext: CodegenContext): Protocol = RestJson(codegenContext)
 
     override fun buildProtocolGenerator(codegenContext: CodegenContext): ServerHttpProtocolGenerator =
-        ServerHttpProtocolGenerator(codegenContext, ServerRestJson(codegenContext))
+        ServerHttpProtocolGenerator(codegenContext, RestJson(codegenContext))
 
     override fun transformModel(model: Model): Model = model
 
@@ -53,62 +39,3 @@ class ServerRestJsonFactory : ProtocolGeneratorFactory<ServerHttpProtocolGenerat
         )
     }
 }
-
-/*
- * RestJson1 implementation. This class is fed to the [ServerHttpProtocolGenerator] to configure things like
- * wire-protocol serializers, content-type, etc.
- */
-class ServerRestJson(private val codegenContext: CodegenContext) : Protocol {
-    private val runtimeConfig = codegenContext.runtimeConfig
-    private val errorScope = arrayOf(
-        "Bytes" to RuntimeType.Bytes,
-        "Error" to RuntimeType.GenericError(runtimeConfig),
-        "HeaderMap" to RuntimeType.http.member("HeaderMap"),
-        "JsonError" to CargoDependency.smithyJson(runtimeConfig).asType().member("deserialize::Error"),
-        "Response" to RuntimeType.http.member("Response"),
-        "JsonErrors" to RuntimeType.jsonErrors(runtimeConfig),
-    )
-    private val jsonDeserModule = RustModule.private("json_deser")
-
-    override val httpBindingResolver: HttpBindingResolver =
-        HttpTraitHttpBindingResolver(codegenContext.model, ProtocolContentTypes.consistent("application/json"))
-
-    override val defaultTimestampFormat: TimestampFormatTrait.Format = TimestampFormatTrait.Format.EPOCH_SECONDS
-
-    override fun structuredDataParser(operationShape: OperationShape): StructuredDataParserGenerator {
-        return JsonParserGenerator(codegenContext, httpBindingResolver, ::restJsonFieldName)
-    }
-
-    override fun structuredDataSerializer(operationShape: OperationShape): StructuredDataSerializerGenerator {
-        return JsonSerializerGenerator(codegenContext, httpBindingResolver, ::restJsonFieldName)
-    }
-
-    // NOTE: this method is only needed for the little part of client-codegen we use in tests.
-    override fun parseHttpGenericError(operationShape: OperationShape): RuntimeType {
-        return RuntimeType.forInlineFun("parse_http_generic_error", jsonDeserModule) { writer ->
-            writer.rustTemplate(
-                """
-                pub fn parse_http_generic_error(response: &#{Response}<#{Bytes}>) -> Result<#{Error}, #{JsonError}> {
-                    #{JsonErrors}::parse_generic_error(response.body(), response.headers())
-                }
-                """,
-                *errorScope
-            )
-        }
-    }
-
-    // NOTE: this method is only needed for the little part of client-codegen we use in tests.
-    override fun parseEventStreamGenericError(operationShape: OperationShape): RuntimeType {
-        return RuntimeType.forInlineFun("parse_event_stream_generic_error", jsonDeserModule) { writer ->
-            writer.rustTemplate(
-                """
-                pub fn parse_event_stream_generic_error(payload: &#{Bytes}) -> Result<#{Error}, #{JsonError}> {
-                    // Note: HeaderMap::new() doesn't allocate
-                    #{json_errors}::parse_generic_error(payload, &#{HeaderMap}::new())
-                }
-                """,
-                *errorScope
-            )
-        }
-    }
-}
diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerRestXml.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerRestXml.kt
new file mode 100644
index 0000000000000000000000000000000000000000..9dea31be92abb7dd171fe093c4df55ea27e5db4c
--- /dev/null
+++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerRestXml.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0.
+ */
+
+package software.amazon.smithy.rust.codegen.server.smithy.protocols
+
+import software.amazon.smithy.model.Model
+import software.amazon.smithy.rust.codegen.smithy.CodegenContext
+import software.amazon.smithy.rust.codegen.smithy.generators.protocol.ProtocolSupport
+import software.amazon.smithy.rust.codegen.smithy.protocols.Protocol
+import software.amazon.smithy.rust.codegen.smithy.protocols.ProtocolGeneratorFactory
+import software.amazon.smithy.rust.codegen.smithy.protocols.RestXml
+
+/*
+ * RestXml server-side protocol factory. This factory creates the [ServerHttpProtocolGenerator]
+ * with RestXml specific configurations.
+ */
+class ServerRestXmlFactory(private val generator: (CodegenContext) -> Protocol = { RestXml(it) }) :
+    ProtocolGeneratorFactory<ServerHttpProtocolGenerator> {
+    override fun protocol(codegenContext: CodegenContext): Protocol = generator(codegenContext)
+
+    override fun buildProtocolGenerator(codegenContext: CodegenContext): ServerHttpProtocolGenerator =
+        ServerHttpProtocolGenerator(codegenContext, RestXml(codegenContext))
+
+    override fun transformModel(model: Model): Model = model
+
+    override fun support(): ProtocolSupport {
+        return ProtocolSupport(
+            /* Client support */
+            requestSerialization = false,
+            requestBodySerialization = false,
+            responseDeserialization = false,
+            errorDeserialization = false,
+            /* Server support */
+            requestDeserialization = true,
+            requestBodyDeserialization = true,
+            responseSerialization = true,
+            errorSerialization = true
+        )
+    }
+}
diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerRustXml.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerRustXml.kt
deleted file mode 100644
index 09cd29fabee08d28ad0ee20f9fe9f406a63b1e64..0000000000000000000000000000000000000000
--- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerRustXml.kt
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
- * SPDX-License-Identifier: Apache-2.0.
- */
-
-package software.amazon.smithy.rust.codegen.server.smithy.protocols
-
-import software.amazon.smithy.aws.traits.protocols.RestXmlTrait
-import software.amazon.smithy.model.Model
-import software.amazon.smithy.model.shapes.OperationShape
-import software.amazon.smithy.model.traits.TimestampFormatTrait
-import software.amazon.smithy.rust.codegen.rustlang.CargoDependency
-import software.amazon.smithy.rust.codegen.rustlang.RustModule
-import software.amazon.smithy.rust.codegen.rustlang.asType
-import software.amazon.smithy.rust.codegen.rustlang.rust
-import software.amazon.smithy.rust.codegen.rustlang.rustBlockTemplate
-import software.amazon.smithy.rust.codegen.smithy.CodegenContext
-import software.amazon.smithy.rust.codegen.smithy.RuntimeType
-import software.amazon.smithy.rust.codegen.smithy.generators.protocol.ProtocolSupport
-import software.amazon.smithy.rust.codegen.smithy.protocols.HttpBindingResolver
-import software.amazon.smithy.rust.codegen.smithy.protocols.HttpTraitHttpBindingResolver
-import software.amazon.smithy.rust.codegen.smithy.protocols.Protocol
-import software.amazon.smithy.rust.codegen.smithy.protocols.ProtocolContentTypes
-import software.amazon.smithy.rust.codegen.smithy.protocols.ProtocolGeneratorFactory
-import software.amazon.smithy.rust.codegen.smithy.protocols.parse.RestXmlParserGenerator
-import software.amazon.smithy.rust.codegen.smithy.protocols.parse.StructuredDataParserGenerator
-import software.amazon.smithy.rust.codegen.smithy.protocols.serialize.StructuredDataSerializerGenerator
-import software.amazon.smithy.rust.codegen.smithy.protocols.serialize.XmlBindingTraitSerializerGenerator
-import software.amazon.smithy.rust.codegen.util.expectTrait
-
-class ServerRestXmlFactory(private val generator: (CodegenContext) -> Protocol = { ServerRestXml(it) }) :
-    ProtocolGeneratorFactory<ServerHttpProtocolGenerator> {
-    override fun protocol(codegenContext: CodegenContext): Protocol = generator(codegenContext)
-
-    override fun buildProtocolGenerator(codegenContext: CodegenContext): ServerHttpProtocolGenerator =
-        ServerHttpProtocolGenerator(codegenContext, ServerRestXml(codegenContext))
-
-    override fun transformModel(model: Model): Model = model
-
-    override fun support(): ProtocolSupport {
-        return ProtocolSupport(
-            /* Client support */
-            requestSerialization = false,
-            requestBodySerialization = false,
-            responseDeserialization = false,
-            errorDeserialization = false,
-            /* Server support */
-            requestDeserialization = true,
-            requestBodyDeserialization = true,
-            responseSerialization = true,
-            errorSerialization = true
-        )
-    }
-}
-
-open class ServerRestXml(private val codegenContext: CodegenContext) : Protocol {
-    private val restXml = codegenContext.serviceShape.expectTrait<RestXmlTrait>()
-    private val runtimeConfig = codegenContext.runtimeConfig
-    private val errorScope = arrayOf(
-        "Bytes" to RuntimeType.Bytes,
-        "Error" to RuntimeType.GenericError(runtimeConfig),
-        "HeaderMap" to RuntimeType.http.member("HeaderMap"),
-        "Response" to RuntimeType.http.member("Response"),
-        "XmlError" to CargoDependency.smithyXml(runtimeConfig).asType().member("decode::XmlError")
-    )
-    private val xmlDeserModule = RustModule.private("xml_deser")
-
-    protected val restXmlErrors: RuntimeType = when (restXml.isNoErrorWrapping) {
-        true -> RuntimeType.unwrappedXmlErrors(runtimeConfig)
-        false -> RuntimeType.wrappedXmlErrors(runtimeConfig)
-    }
-
-    override val httpBindingResolver: HttpBindingResolver =
-        HttpTraitHttpBindingResolver(codegenContext.model, ProtocolContentTypes.consistent("application/xml"))
-
-    override val defaultTimestampFormat: TimestampFormatTrait.Format =
-        TimestampFormatTrait.Format.DATE_TIME
-
-    override fun structuredDataParser(operationShape: OperationShape): StructuredDataParserGenerator {
-        return RestXmlParserGenerator(codegenContext, restXmlErrors)
-    }
-
-    override fun structuredDataSerializer(operationShape: OperationShape): StructuredDataSerializerGenerator {
-        return XmlBindingTraitSerializerGenerator(codegenContext, httpBindingResolver)
-    }
-
-    override fun parseHttpGenericError(operationShape: OperationShape): RuntimeType =
-        RuntimeType.forInlineFun("parse_http_generic_error", xmlDeserModule) { writer ->
-            writer.rustBlockTemplate(
-                "pub fn parse_http_generic_error(response: &#{Response}<#{Bytes}>) -> Result<#{Error}, #{XmlError}>",
-                *errorScope
-            ) {
-                rust("#T::parse_generic_error(response.body().as_ref())", restXmlErrors)
-            }
-        }
-
-    override fun parseEventStreamGenericError(operationShape: OperationShape): RuntimeType =
-        RuntimeType.forInlineFun("parse_event_stream_generic_error", xmlDeserModule) { writer ->
-            writer.rustBlockTemplate(
-                "pub fn parse_event_stream_generic_error(payload: &#{Bytes}) -> Result<#{Error}, #{XmlError}>",
-                *errorScope
-            ) {
-                rust("#T::parse_generic_error(payload.as_ref())", restXmlErrors)
-            }
-        }
-}
diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/protocol/MakeOperationGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/protocol/MakeOperationGenerator.kt
index 5f1fe0ee6e343b4a0a4cc21d54009248365ffae4..016578ba4c970d0e77b1496b6d1e7c676bd96838 100644
--- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/protocol/MakeOperationGenerator.kt
+++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/generators/protocol/MakeOperationGenerator.kt
@@ -148,7 +148,7 @@ open class MakeOperationGenerator(
         writer.inRequestBuilderBaseFn(inputShape) {
             Attribute.AllowUnusedMut.render(this)
             writer.rust("let mut builder = update_http_builder(input, #T::new())?;", RuntimeType.HttpRequestBuilder)
-            val additionalHeaders = listOfNotNull(contentType?.let { "content-type" to it }) + protocol.additionalHeaders(operationShape)
+            val additionalHeaders = listOfNotNull(contentType?.let { "content-type" to it }) + protocol.additionalRequestHeaders(operationShape)
             for (header in additionalHeaders) {
                 writer.rustTemplate(
                     """
diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/AwsJson.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/AwsJson.kt
index 7fb0ae6100b514dff8324aafe45c04480cf78375..43f68a8d7cc8822adf04f5f59618545d87dae6c8 100644
--- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/AwsJson.kt
+++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/AwsJson.kt
@@ -148,7 +148,7 @@ class AwsJson(
 
     override val defaultTimestampFormat: TimestampFormatTrait.Format = TimestampFormatTrait.Format.EPOCH_SECONDS
 
-    override fun additionalHeaders(operationShape: OperationShape): List<Pair<String, String>> =
+    override fun additionalRequestHeaders(operationShape: OperationShape): List<Pair<String, String>> =
         listOf("x-amz-target" to "${codegenContext.serviceShape.id.name}.${operationShape.id.name}")
 
     override fun structuredDataParser(operationShape: OperationShape): StructuredDataParserGenerator =
diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/HttpBindingResolver.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/HttpBindingResolver.kt
index ef1402545e09c5a83dde8d83597a02962dfc4102..3cc9e050d821a0ba9290f1df98d4997398bc5568 100644
--- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/HttpBindingResolver.kt
+++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/HttpBindingResolver.kt
@@ -113,7 +113,7 @@ data class ProtocolContentTypes(
 /**
  * An [HttpBindingResolver] that relies on the HttpTrait data in the Smithy models.
  */
-class HttpTraitHttpBindingResolver(
+open class HttpTraitHttpBindingResolver(
     model: Model,
     private val contentTypes: ProtocolContentTypes,
 ) : HttpBindingResolver {
diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/Protocol.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/Protocol.kt
index ef51ca66b0a95fce669972587a58d887bc2334d0..e89d4bdf6292fe9d039463e2aa30de365370c770 100644
--- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/Protocol.kt
+++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/Protocol.kt
@@ -39,8 +39,8 @@ interface Protocol {
     /** The timestamp format that should be used if no override is specified in the model */
     val defaultTimestampFormat: TimestampFormatTrait.Format
 
-    /** Returns additional HTTP headers that should be included for the given operation for this protocol */
-    fun additionalHeaders(operationShape: OperationShape): List<Pair<String, String>> = emptyList()
+    /** Returns additional HTTP headers that should be included in HTTP requests for the given operation for this protocol. */
+    fun additionalRequestHeaders(operationShape: OperationShape): List<Pair<String, String>> = emptyList()
 
     /** Returns a deserialization code generator for this protocol */
     fun structuredDataParser(operationShape: OperationShape): StructuredDataParserGenerator
diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/RestJson.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/RestJson.kt
index 5f3a9209efc87f532350fca302f4d9e883f3b279..ed98a20785182f7bab44eb444894108d923f8ece 100644
--- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/RestJson.kt
+++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/RestJson.kt
@@ -47,6 +47,25 @@ class RestJsonFactory : ProtocolGeneratorFactory<HttpBoundProtocolGenerator> {
     }
 }
 
+/**
+ * This [HttpBindingResolver] implementation mostly delegates to the [HttpTraitHttpBindingResolver] class, since the
+ * RestJson1 protocol can be almost entirely described by Smithy's HTTP binding traits
+ * (https://awslabs.github.io/smithy/1.0/spec/core/http-traits.html).
+ * The only protocol-specific behavior that is truly custom is the response `Content-Type` header, which defaults to
+ * `application/json` if not overridden.
+ */
+class RestJsonHttpBindingResolver(
+    model: Model,
+    contentTypes: ProtocolContentTypes,
+) : HttpTraitHttpBindingResolver(model, contentTypes) {
+    /**
+     * In the RestJson1 protocol, HTTP responses have a default `Content-Type: application/json` header if it is not
+     * overridden by a specific mechanism (e.g. an output shape member is targeted with `httpPayload` or `mediaType` traits.
+     */
+    override fun responseContentType(operationShape: OperationShape): String =
+        super.responseContentType(operationShape) ?: "application/json"
+}
+
 class RestJson(private val codegenContext: CodegenContext) : Protocol {
     private val runtimeConfig = codegenContext.runtimeConfig
     private val errorScope = arrayOf(
@@ -60,7 +79,7 @@ class RestJson(private val codegenContext: CodegenContext) : Protocol {
     private val jsonDeserModule = RustModule.private("json_deser")
 
     override val httpBindingResolver: HttpBindingResolver =
-        HttpTraitHttpBindingResolver(codegenContext.model, ProtocolContentTypes.consistent("application/json"))
+        RestJsonHttpBindingResolver(codegenContext.model, ProtocolContentTypes.consistent("application/json"))
 
     override val defaultTimestampFormat: TimestampFormatTrait.Format = TimestampFormatTrait.Format.EPOCH_SECONDS
 
diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/serialize/JsonSerializerGenerator.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/serialize/JsonSerializerGenerator.kt
index 567f29884dcafe08dd40e0b8c6bc144983d29ad6..df46f9b88fe6f58a31f6c63f0189b369af663bc7 100644
--- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/serialize/JsonSerializerGenerator.kt
+++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/protocols/serialize/JsonSerializerGenerator.kt
@@ -267,7 +267,7 @@ class JsonSerializerGenerator(
         }
     }
 
-    override fun serverOutputSerializer(operationShape: OperationShape): RuntimeType? {
+    override fun serverOutputSerializer(operationShape: OperationShape): RuntimeType {
         val outputShape = operationShape.outputShape(model)
         val includedMembers = httpBindingResolver.responseMembers(operationShape, HttpLocation.DOCUMENT)
         val fnName = symbolProvider.serializeFunctionName(outputShape)