From 674e15971ee821ab9cf1f54c473d454bf86126fe Mon Sep 17 00:00:00 2001 From: david-perez Date: Mon, 17 Apr 2023 13:54:28 +0200 Subject: [PATCH] Fix server code generation of `@httpPayload`-bound constrained shapes The issue is we're not changing the return type of the payload deserializing function to be the unconstrained type (e.g. the builder in case of an `@httpPayload`-bound structure shape) when the shape is constrained. Yet another example of why code-generating `constraints.smithy` (see #2101) is important. Closes #2583. --- CHANGELOG.next.toml | 6 ++++++ .../common-test-models/constraints.smithy | 15 +++++++++++++++ .../HttpBoundProtocolPayloadGenerator.kt | 6 +++++- .../smithy/protocols/parse/JsonParserGenerator.kt | 7 ++++--- 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.next.toml b/CHANGELOG.next.toml index e07d004d2a..54e0831567 100644 --- a/CHANGELOG.next.toml +++ b/CHANGELOG.next.toml @@ -104,3 +104,9 @@ message = "`aws_smithy_types::date_time::Format` has been re-exported in service references = ["smithy-rs#2534"] meta = { "breaking" = false, "tada" = false, "bug" = false, "target" = "client" } author = "ysaito1001" + +[[smithy-rs]] +message = "Fix server code generation bug affecting constrained shapes bound with `@httpPayload`" +references = ["smithy-rs#2583", "smithy-rs#2584"] +meta = { "breaking" = false, "tada" = false, "bug" = true, "target" = "server" } +author = "david-perez" diff --git a/codegen-core/common-test-models/constraints.smithy b/codegen-core/common-test-models/constraints.smithy index 2651b77335..715f001870 100644 --- a/codegen-core/common-test-models/constraints.smithy +++ b/codegen-core/common-test-models/constraints.smithy @@ -12,7 +12,9 @@ service ConstraintsService { operations: [ ConstrainedShapesOperation, ConstrainedHttpBoundShapesOperation, + ConstrainedHttpPayloadBoundShapeOperation, ConstrainedRecursiveShapesOperation, + // `httpQueryParams` and `httpPrefixHeaders` are structurually // exclusive, so we need one operation per target shape type // combination. @@ -59,6 +61,13 @@ operation ConstrainedHttpBoundShapesOperation { errors: [ValidationException] } +@http(uri: "/constrained-http-payload-bound-shape-operation", method: "POST") +operation ConstrainedHttpPayloadBoundShapeOperation { + input: ConstrainedHttpPayloadBoundShapeOperationInputOutput, + output: ConstrainedHttpPayloadBoundShapeOperationInputOutput, + errors: [ValidationException] +} + @http(uri: "/constrained-recursive-shapes-operation", method: "POST") operation ConstrainedRecursiveShapesOperation { input: ConstrainedRecursiveShapesOperationInputOutput, @@ -311,6 +320,12 @@ structure ConstrainedHttpBoundShapesOperationInputOutput { enumStringListQuery: ListOfEnumString, } +structure ConstrainedHttpPayloadBoundShapeOperationInputOutput { + @required + @httpPayload + httpPayloadBoundConstrainedShape: ConA +} + structure QueryParamsTargetingMapOfPatternStringOperationInputOutput { @httpQueryParams mapOfPatternString: MapOfPatternString diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/HttpBoundProtocolPayloadGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/HttpBoundProtocolPayloadGenerator.kt index 10d4b83cec..6d4e7bf850 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/HttpBoundProtocolPayloadGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/HttpBoundProtocolPayloadGenerator.kt @@ -239,7 +239,11 @@ class HttpBoundProtocolPayloadGenerator( ) { val ref = if (payloadMetadata.takesOwnership) "" else "&" val serializer = protocolFunctions.serializeFn(member, fnNameSuffix = "http_payload") { fnName -> - val outputT = if (member.isStreaming(model)) symbolProvider.toSymbol(member) else RuntimeType.ByteSlab.toSymbol() + val outputT = if (member.isStreaming(model)) { + symbolProvider.toSymbol(member) + } else { + RuntimeType.ByteSlab.toSymbol() + } rustBlockTemplate( "pub fn $fnName(payload: $ref#{Member}) -> Result<#{outputT}, #{BuildError}>", "Member" to symbolProvider.toSymbol(member), diff --git a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/JsonParserGenerator.kt b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/JsonParserGenerator.kt index 1566d84bf3..7d54a57b76 100644 --- a/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/JsonParserGenerator.kt +++ b/codegen-core/src/main/kotlin/software/amazon/smithy/rust/codegen/core/smithy/protocols/parse/JsonParserGenerator.kt @@ -154,14 +154,15 @@ class JsonParserGenerator( override fun payloadParser(member: MemberShape): RuntimeType { val shape = model.expectShape(member.target) + val returnSymbolToParse = returnSymbolToParse(shape) check(shape is UnionShape || shape is StructureShape || shape is DocumentShape) { - "payload parser should only be used on structures & unions" + "Payload parser should only be used on structure shapes, union shapes, and document shapes." } return protocolFunctions.deserializeFn(shape, fnNameSuffix = "payload") { fnName -> rustBlockTemplate( - "pub fn $fnName(input: &[u8]) -> Result<#{Shape}, #{Error}>", + "pub fn $fnName(input: &[u8]) -> Result<#{ReturnType}, #{Error}>", *codegenScope, - "Shape" to symbolProvider.toSymbol(shape), + "ReturnType" to returnSymbolToParse.symbol, ) { val input = if (shape is DocumentShape) { "input"