diff --git a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/fromsmithy/protocols/AbstractRestProtocol.java b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/fromsmithy/protocols/AbstractRestProtocol.java index 74702c50c05..9f11884ea83 100644 --- a/smithy-openapi/src/main/java/software/amazon/smithy/openapi/fromsmithy/protocols/AbstractRestProtocol.java +++ b/smithy-openapi/src/main/java/software/amazon/smithy/openapi/fromsmithy/protocols/AbstractRestProtocol.java @@ -29,6 +29,7 @@ import software.amazon.smithy.model.knowledge.HttpBinding; import software.amazon.smithy.model.knowledge.HttpBindingIndex; import software.amazon.smithy.model.knowledge.OperationIndex; +import software.amazon.smithy.model.pattern.SmithyPattern; import software.amazon.smithy.model.shapes.CollectionShape; import software.amazon.smithy.model.shapes.MemberShape; import software.amazon.smithy.model.shapes.OperationShape; @@ -38,6 +39,7 @@ import software.amazon.smithy.model.traits.HttpTrait; import software.amazon.smithy.model.traits.TimestampFormatTrait; import software.amazon.smithy.model.traits.Trait; +import software.amazon.smithy.openapi.OpenApiException; import software.amazon.smithy.openapi.fromsmithy.Context; import software.amazon.smithy.openapi.fromsmithy.OpenApiProtocol; import software.amazon.smithy.openapi.model.MediaTypeObject; @@ -120,10 +122,26 @@ public Optional createOperation(Context context, OperationShape op private List createPathParameters(Context context, OperationShape operation) { List result = new ArrayList<>(); HttpBindingIndex bindingIndex = HttpBindingIndex.of(context.getModel()); + HttpTrait httpTrait = operation.expectTrait(HttpTrait.class); for (HttpBinding binding : bindingIndex.getRequestBindings(operation, HttpBinding.Location.LABEL)) { Schema schema = createPathParameterSchema(context, binding); + String memberName = binding.getMemberName(); + + SmithyPattern.Segment label = httpTrait.getUri() + .getLabel(memberName) + .orElseThrow(() -> new OpenApiException(String.format( + "Unable to find URI label on %s for %s: %s", + operation.getId(), + binding.getMemberName(), + httpTrait.getUri()))); + + // Greedy labels in OpenAPI need to include the label in the generated parameter. + // For example, given "/{foo+}", the parameter name must be "foo+". + String name = label.isGreedyLabel() ? label.getContent() + "+" : label.getContent(); + result.add(ModelUtils.createParameterMember(context, binding.getMember()) + .name(name) .in("path") .schema(schema) .build()); diff --git a/smithy-openapi/src/test/java/software/amazon/smithy/openapi/fromsmithy/protocols/AwsRestJson1ProtocolTest.java b/smithy-openapi/src/test/java/software/amazon/smithy/openapi/fromsmithy/protocols/AwsRestJson1ProtocolTest.java index 9234dff56e6..120259a4f4f 100644 --- a/smithy-openapi/src/test/java/software/amazon/smithy/openapi/fromsmithy/protocols/AwsRestJson1ProtocolTest.java +++ b/smithy-openapi/src/test/java/software/amazon/smithy/openapi/fromsmithy/protocols/AwsRestJson1ProtocolTest.java @@ -27,7 +27,8 @@ public class AwsRestJson1ProtocolTest { "adds-header-mediatype-format.json", "supports-payloads.json", "aws-rest-json-uses-jsonname.json", - "synthesizes-contents.json" + "synthesizes-contents.json", + "greedy-labels.json" }) public void testProtocolResult(String smithy) { diff --git a/smithy-openapi/src/test/resources/software/amazon/smithy/openapi/fromsmithy/protocols/greedy-labels.json b/smithy-openapi/src/test/resources/software/amazon/smithy/openapi/fromsmithy/protocols/greedy-labels.json new file mode 100644 index 00000000000..c3c37946577 --- /dev/null +++ b/smithy-openapi/src/test/resources/software/amazon/smithy/openapi/fromsmithy/protocols/greedy-labels.json @@ -0,0 +1,48 @@ +{ + "smithy": "1.0", + "shapes": { + "smithy.example#Service": { + "type": "service", + "version": "2006-03-01", + "operations": [ + { + "target": "smithy.example#Operation" + } + ], + "traits": { + "aws.protocols#restJson1": {} + } + }, + "smithy.example#Operation": { + "type": "operation", + "input": { + "target": "smithy.example#OperationInput" + }, + "traits": { + "smithy.api#http": { + "uri": "/{foo}/{baz+}", + "method": "POST" + } + } + }, + "smithy.example#OperationInput": { + "type": "structure", + "members": { + "foo": { + "target": "smithy.api#String", + "traits": { + "smithy.api#required": {}, + "smithy.api#httpLabel": {} + } + }, + "baz": { + "target": "smithy.api#String", + "traits": { + "smithy.api#required": {}, + "smithy.api#httpLabel": {} + } + } + } + } + } +} diff --git a/smithy-openapi/src/test/resources/software/amazon/smithy/openapi/fromsmithy/protocols/greedy-labels.openapi.json b/smithy-openapi/src/test/resources/software/amazon/smithy/openapi/fromsmithy/protocols/greedy-labels.openapi.json new file mode 100644 index 00000000000..f677f0b1b04 --- /dev/null +++ b/smithy-openapi/src/test/resources/software/amazon/smithy/openapi/fromsmithy/protocols/greedy-labels.openapi.json @@ -0,0 +1,37 @@ +{ + "openapi": "3.0.2", + "info": { + "title": "Service", + "version": "2006-03-01" + }, + "paths": { + "/{foo}/{baz+}": { + "post": { + "operationId": "Operation", + "parameters": [ + { + "name": "foo", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + }, + { + "name": "baz+", + "in": "path", + "schema": { + "type": "string" + }, + "required": true + } + ], + "responses": { + "200": { + "description": "Operation response" + } + } + } + } + } +}