From acc56f83dfc01e791fbd57408fe5df3c1febd11b Mon Sep 17 00:00:00 2001 From: david-perez Date: Tue, 8 Feb 2022 19:45:42 +0100 Subject: [PATCH] Always set `Content-Type` header in RestJson1 responses (#1131) The protocol specifies it should be set by default to `application/json` in HTTP responses, even when there are no output shape members, since in that case an empty JSON payload `{}` is serialized. There are server protocol tests asserting this behavior. To implement this behavior, the `RestJsonHttpBindingResolver` class has been introduced, which mostly delegates to the `HttpTraitHttpBindingResolver`, but tweaks the response `Content-Type` header. Note this behavior is different than the client's, which should not serialize a JSON payload if there are no input shape members to be serialized to the body, and as such does not need to set the `Content-Type` header. This commit also deletes the `ServerRestJson` and `ServerRestXml` classes, since they were exact copies of their client counterparts. The latter was hosted in `ServerRustXml.kt`, which has been renamed to `ServerRestXml.kt`. --- .../protocol/ServerProtocolTestGenerator.kt | 3 - .../protocols/ServerHttpProtocolGenerator.kt | 2 +- .../server/smithy/protocols/ServerRestJson.kt | 81 +------------ .../server/smithy/protocols/ServerRestXml.kt | 42 +++++++ .../server/smithy/protocols/ServerRustXml.kt | 106 ------------------ .../protocol/MakeOperationGenerator.kt | 2 +- .../rust/codegen/smithy/protocols/AwsJson.kt | 2 +- .../smithy/protocols/HttpBindingResolver.kt | 2 +- .../rust/codegen/smithy/protocols/Protocol.kt | 4 +- .../rust/codegen/smithy/protocols/RestJson.kt | 21 +++- .../serialize/JsonSerializerGenerator.kt | 2 +- 11 files changed, 73 insertions(+), 194 deletions(-) create mode 100644 codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerRestXml.kt delete mode 100644 codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/protocols/ServerRustXml.kt 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 f422404ea..3b3510791 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 69b5ff766..804616b96 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 e83718884..76c19531b 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 { - 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 - 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 000000000..9dea31be9 --- /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 { + 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 09cd29fab..000000000 --- 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 { - 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() - 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 5f1fe0ee6..016578ba4 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 7fb0ae610..43f68a8d7 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> = + override fun additionalRequestHeaders(operationShape: OperationShape): List> = 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 ef1402545..3cc9e050d 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 ef51ca66b..e89d4bdf6 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> = emptyList() + /** Returns additional HTTP headers that should be included in HTTP requests for the given operation for this protocol. */ + fun additionalRequestHeaders(operationShape: OperationShape): List> = 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 5f3a9209e..ed98a2078 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 { } } +/** + * 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 567f29884..df46f9b88 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) -- GitLab