Skip to content

Commit f0fda09

Browse files
committed
fix bug, passes test
1 parent 6b6e115 commit f0fda09

File tree

1 file changed

+45
-7
lines changed

1 file changed

+45
-7
lines changed

smithy-openapi/src/main/java/software/amazon/smithy/openapi/fromsmithy/protocols/AbstractRestProtocol.java

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,12 @@
3333
import software.amazon.smithy.model.shapes.OperationShape;
3434
import software.amazon.smithy.model.shapes.ServiceShape;
3535
import software.amazon.smithy.model.shapes.Shape;
36+
import software.amazon.smithy.model.shapes.ShapeId;
3637
import software.amazon.smithy.model.shapes.StructureShape;
3738
import software.amazon.smithy.model.traits.ErrorTrait;
3839
import software.amazon.smithy.model.traits.ExamplesTrait;
3940
import software.amazon.smithy.model.traits.HttpChecksumRequiredTrait;
41+
import software.amazon.smithy.model.traits.HttpErrorTrait;
4042
import software.amazon.smithy.model.traits.HttpTrait;
4143
import software.amazon.smithy.model.traits.TimestampFormatTrait;
4244
import software.amazon.smithy.model.traits.Trait;
@@ -302,6 +304,7 @@ private Map<String, Node> createErrorExamplesForMembersWithHttpTraits(
302304
* This method is used for converting the Smithy examples to OpenAPI examples for non-payload HTTP message body.
303305
*/
304306
private Map<String, Node> createBodyExamples(
307+
Context<T> context,
305308
Shape operationOrError,
306309
List<HttpBinding> bindings,
307310
MessageType type,
@@ -312,7 +315,7 @@ private Map<String, Node> createBodyExamples(
312315
}
313316

314317
if (type == MessageType.ERROR) {
315-
return createErrorBodyExamples(operationOrError, bindings, operation);
318+
return createErrorBodyExamples(context, operationOrError, bindings, operation);
316319
} else {
317320
Map<String, Node> examples = new TreeMap<>();
318321
// unique numbering for unique example names in OpenAPI.
@@ -342,6 +345,7 @@ private Map<String, Node> createBodyExamples(
342345
}
343346

344347
private Map<String, Node> createErrorBodyExamples(
348+
Context<T> context,
345349
Shape error,
346350
List<HttpBinding> bindings,
347351
OperationShape operation
@@ -350,14 +354,15 @@ private Map<String, Node> createErrorBodyExamples(
350354
// unique numbering for unique example names in OpenAPI.
351355
int uniqueNum = 1;
352356
Optional<ExamplesTrait> examplesTrait = operation.getTrait(ExamplesTrait.class);
357+
358+
Set<ShapeId> errorShapeIds = getErrorShapeIdsForMatching(context, error, operation);
359+
353360
for (ExamplesTrait.Example example : examplesTrait.map(ExamplesTrait::getExamples)
354361
.orElse(Collections.emptyList())) {
355362
String name = operation.getId().getName() + "_example" + uniqueNum++;
356-
// this has to be checked because an operation can have more than one error linked to it.
357363
if (example.getError().isPresent()
358-
&& example.getError().get().getShapeId() == error.toShapeId()) {
359-
// get members included in bindings
360-
ObjectNode values = getMembersWithHttpBindingTrait(bindings, example.getError().get().getContent());
364+
&& errorShapeIds.contains(example.getError().get().getShapeId())) {
365+
ObjectNode values = example.getError().get().getContent();
361366
examples.put(name,
362367
ExampleObject.builder()
363368
.summary(example.getTitle())
@@ -370,6 +375,39 @@ private Map<String, Node> createErrorBodyExamples(
370375
return examples;
371376
}
372377

378+
private Set<ShapeId> getErrorShapeIdsForMatching(Context<T> context, Shape error, OperationShape operation) {
379+
Set<ShapeId> errorShapeIds = new LinkedHashSet<>();
380+
String errorName = error.getId().getName();
381+
382+
if (errorName.matches(".*\\d+Error$")) {
383+
if (error instanceof StructureShape && context.getModel() != null) {
384+
String statusCode = extractStatusCodeFromSyntheticErrorName(errorName);
385+
context.getModel().shapes(StructureShape.class)
386+
.filter(shape -> shape.hasTrait(ErrorTrait.class))
387+
.filter(shape -> getHttpStatusCode(shape).equals(statusCode))
388+
.forEach(shape -> errorShapeIds.add(shape.getId()));
389+
}
390+
} else {
391+
errorShapeIds.add(error.toShapeId());
392+
}
393+
394+
return errorShapeIds;
395+
}
396+
397+
private String extractStatusCodeFromSyntheticErrorName(String errorName) {
398+
if (errorName.matches(".*\\d+Error$")) {
399+
return errorName.replaceAll(".*?(\\d+)Error$", "$1");
400+
}
401+
return "400";
402+
}
403+
404+
private String getHttpStatusCode(StructureShape errorShape) {
405+
return errorShape.getTrait(HttpErrorTrait.class)
406+
.map(trait -> String.valueOf(trait.getCode()))
407+
.orElse(errorShape.hasTrait(ErrorTrait.class) && "client".equals(
408+
errorShape.expectTrait(ErrorTrait.class).getValue()) ? "400" : "500");
409+
}
410+
373411
/*
374412
* Returns a modified copy of [inputOrOutput] only containing members bound to a HttpBinding trait in [bindings].
375413
*/
@@ -598,7 +636,7 @@ private Optional<RequestBodyObject> createRequestDocument(
598636
String pointer = context.putSynthesizedSchema(synthesizedName, schema);
599637
MediaTypeObject mediaTypeObject = MediaTypeObject.builder()
600638
.schema(Schema.builder().ref(pointer).build())
601-
.examples(createBodyExamples(operation, bindings, MessageType.REQUEST, null))
639+
.examples(createBodyExamples(context, operation, bindings, MessageType.REQUEST, null))
602640
.build();
603641

604642
// If any of the top level bindings are required, then the body itself must be required.
@@ -840,7 +878,7 @@ private void createResponseDocumentIfNeeded(
840878
String pointer = context.putSynthesizedSchema(synthesizedName, schema);
841879
MediaTypeObject mediaTypeObject = MediaTypeObject.builder()
842880
.schema(Schema.builder().ref(pointer).build())
843-
.examples(createBodyExamples(operationOrError, bindings, messageType, operation))
881+
.examples(createBodyExamples(context, operationOrError, bindings, messageType, operation))
844882
.build();
845883

846884
responseBuilder.putContent(mediaType, mediaTypeObject);

0 commit comments

Comments
 (0)