Skip to content

Commit 6576cff

Browse files
Give context to OpenAPI value transformer
This updates AbstractRestProtocol's value transformer to take the conversion context and the shape of the value it is transforming.
1 parent a87ffb1 commit 6576cff

File tree

2 files changed

+49
-17
lines changed

2 files changed

+49
-17
lines changed

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

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -109,11 +109,16 @@ abstract Schema createDocumentSchema(
109109
MessageType messageType
110110
);
111111

112+
@Deprecated
113+
Node transformSmithyValueToProtocolValue(Node value) {
114+
return value;
115+
};
116+
112117
/**
113118
* Converts Smithy values in Node form to a data exchange format used by a protocol (e.g., XML).
114119
* Then returns the converted value as a long string (escaping where necessary).
115120
* If data exchange format is JSON (e.g., as in restJson1 protocol),
116-
* method should return values without any modification.
121+
* method should respect the jsonName trait, but otherwise not modify the node.
117122
*
118123
* <p> Used for the value property of OpenAPI example objects.
119124
* For protocols that do not use JSON as data-exchange format,
@@ -122,10 +127,14 @@ abstract Schema createDocumentSchema(
122127
* E.g., for restXML protocol, values would be converted to a large String of XML value / object,
123128
* escaping where necessary.
124129
*
125-
* @param value value to be converted.
130+
* @param context Conversion context.
131+
* @param shape The shape that the value represents.
132+
* @param value value to be converted.
126133
* @return the long string (escaped where necessary) of values in a data exchange format used by a protocol.
127134
*/
128-
abstract Node transformSmithyValueToProtocolValue(Node value);
135+
Node transformSmithyValueToProtocolValue(Context<T> context, Shape shape, Node value) {
136+
return value;
137+
}
129138

130139
@Override
131140
public Set<String> getProtocolRequestHeaders(Context<T> context, OperationShape operationShape) {
@@ -204,6 +213,7 @@ private List<ParameterObject> createPathParameters(Context<T> context, Operation
204213
.in("path")
205214
.schema(schema)
206215
.examples(createExamplesForMembersWithHttpTraits(
216+
context,
207217
operation,
208218
binding,
209219
MessageType.REQUEST,
@@ -219,6 +229,7 @@ private List<ParameterObject> createPathParameters(Context<T> context, Operation
219229
* path parameters, query parameters, header parameters, and payload.
220230
*/
221231
private Map<String, Node> createExamplesForMembersWithHttpTraits(
232+
Context<T> context,
222233
Shape operationOrError,
223234
HttpBinding binding,
224235
MessageType type,
@@ -229,15 +240,17 @@ private Map<String, Node> createExamplesForMembersWithHttpTraits(
229240
}
230241

231242
if (type == MessageType.ERROR) {
232-
return createErrorExamplesForMembersWithHttpTraits(operationOrError, binding, operation);
243+
return createErrorExamplesForMembersWithHttpTraits(context, operationOrError, binding, operation);
233244
} else {
234245
Map<String, Node> examples = new TreeMap<>();
235246
// unique numbering for unique example names in OpenAPI.
236247
int uniqueNum = 1;
237248

238-
Optional<ExamplesTrait> examplesTrait = operationOrError.getTrait(ExamplesTrait.class);
239-
for (ExamplesTrait.Example example : examplesTrait.map(ExamplesTrait::getExamples)
240-
.orElse(Collections.emptyList())) {
249+
List<ExamplesTrait.Example> modeledExamples = operationOrError.getTrait(ExamplesTrait.class)
250+
.map(ExamplesTrait::getExamples)
251+
.orElse(Collections.emptyList());
252+
253+
for (ExamplesTrait.Example example : modeledExamples) {
241254
ObjectNode inputOrOutput = type == MessageType.REQUEST ? example.getInput()
242255
: example.getOutput().orElse(Node.objectNode());
243256
String name = operationOrError.getId().getName() + "_example" + uniqueNum++;
@@ -251,7 +264,7 @@ private Map<String, Node> createExamplesForMembersWithHttpTraits(
251264
ExampleObject.builder()
252265
.summary(example.getTitle())
253266
.description(example.getDocumentation().orElse(""))
254-
.value(transformSmithyValueToProtocolValue(values))
267+
.value(transformSmithyValueToProtocolValue(context, binding.getMember(), values))
255268
.build()
256269
.toNode());
257270
}
@@ -264,6 +277,7 @@ private Map<String, Node> createExamplesForMembersWithHttpTraits(
264277
* Helper method for createExamples() method.
265278
*/
266279
private Map<String, Node> createErrorExamplesForMembersWithHttpTraits(
280+
Context<T> context,
267281
Shape error,
268282
HttpBinding binding,
269283
OperationShape operation
@@ -290,7 +304,7 @@ private Map<String, Node> createErrorExamplesForMembersWithHttpTraits(
290304
ExampleObject.builder()
291305
.summary(example.getTitle())
292306
.description(example.getDocumentation().orElse(""))
293-
.value(transformSmithyValueToProtocolValue(values))
307+
.value(transformSmithyValueToProtocolValue(context, binding.getMember(), values))
294308
.build()
295309
.toNode());
296310
}
@@ -302,6 +316,7 @@ private Map<String, Node> createErrorExamplesForMembersWithHttpTraits(
302316
* This method is used for converting the Smithy examples to OpenAPI examples for non-payload HTTP message body.
303317
*/
304318
private Map<String, Node> createBodyExamples(
319+
Context<T> context,
305320
Shape operationOrError,
306321
List<HttpBinding> bindings,
307322
MessageType type,
@@ -312,7 +327,7 @@ private Map<String, Node> createBodyExamples(
312327
}
313328

314329
if (type == MessageType.ERROR) {
315-
return createErrorBodyExamples(operationOrError, bindings, operation);
330+
return createErrorBodyExamples(context, operationOrError, bindings, operation);
316331
} else {
317332
Map<String, Node> examples = new TreeMap<>();
318333
// unique numbering for unique example names in OpenAPI.
@@ -321,18 +336,30 @@ private Map<String, Node> createBodyExamples(
321336
Optional<ExamplesTrait> examplesTrait = operationOrError.getTrait(ExamplesTrait.class);
322337
for (ExamplesTrait.Example example : examplesTrait.map(ExamplesTrait::getExamples)
323338
.orElse(Collections.emptyList())) {
339+
340+
Shape structure = operationOrError;
341+
if (operationOrError.isOperationShape()) {
342+
OperationShape op = operationOrError.asOperationShape().get();
343+
if (type == MessageType.REQUEST) {
344+
structure = context.getModel().expectShape(op.getInputShape());
345+
} else {
346+
structure = context.getModel().expectShape(op.getOutputShape());
347+
}
348+
}
349+
324350
// get members included in bindings
325351
ObjectNode values = getMembersWithHttpBindingTrait(bindings,
326352
type == MessageType.REQUEST ? example.getInput()
327353
: example.getOutput().orElse(Node.objectNode()));
328354
String name = operationOrError.getId().getName() + "_example" + uniqueNum++;
355+
329356
// this if condition is needed to avoid errors when converting examples of response.
330357
if (!example.getError().isPresent() || type == MessageType.REQUEST) {
331358
examples.put(name,
332359
ExampleObject.builder()
333360
.summary(example.getTitle())
334361
.description(example.getDocumentation().orElse(""))
335-
.value(transformSmithyValueToProtocolValue(values))
362+
.value(transformSmithyValueToProtocolValue(context, structure, values))
336363
.build()
337364
.toNode());
338365
}
@@ -342,6 +369,7 @@ private Map<String, Node> createBodyExamples(
342369
}
343370

344371
private Map<String, Node> createErrorBodyExamples(
372+
Context<T> context,
345373
Shape error,
346374
List<HttpBinding> bindings,
347375
OperationShape operation
@@ -362,7 +390,7 @@ private Map<String, Node> createErrorBodyExamples(
362390
ExampleObject.builder()
363391
.summary(example.getTitle())
364392
.description(example.getDocumentation().orElse(""))
365-
.value(transformSmithyValueToProtocolValue(values))
393+
.value(transformSmithyValueToProtocolValue(context, error, values))
366394
.build()
367395
.toNode());
368396
}
@@ -456,7 +484,8 @@ private List<ParameterObject> createQueryParameters(Context<T> context, Operatio
456484
}
457485

458486
param.schema(createQuerySchema(context, member, target));
459-
param.examples(createExamplesForMembersWithHttpTraits(operation, binding, MessageType.REQUEST, null));
487+
param.examples(
488+
createExamplesForMembersWithHttpTraits(context, operation, binding, MessageType.REQUEST, null));
460489
result.add(param.build());
461490
}
462491

@@ -496,7 +525,8 @@ private Map<String, ParameterObject> createHeaderParameters(
496525
param.in(null).name(null);
497526
}
498527

499-
param.examples(createExamplesForMembersWithHttpTraits(operationOrError, binding, messageType, operation));
528+
param.examples(
529+
createExamplesForMembersWithHttpTraits(context, operationOrError, binding, messageType, operation));
500530

501531
// Create the appropriate schema based on the shape type.
502532
Shape target = context.getModel().expectShape(member.getTarget());
@@ -566,6 +596,7 @@ private Optional<RequestBodyObject> createRequestPayload(
566596
return shapeName + "InputPayload";
567597
}).toBuilder()
568598
.examples(createExamplesForMembersWithHttpTraits(
599+
context,
569600
operation,
570601
binding,
571602
MessageType.REQUEST,
@@ -598,7 +629,7 @@ private Optional<RequestBodyObject> createRequestDocument(
598629
String pointer = context.putSynthesizedSchema(synthesizedName, schema);
599630
MediaTypeObject mediaTypeObject = MediaTypeObject.builder()
600631
.schema(Schema.builder().ref(pointer).build())
601-
.examples(createBodyExamples(operation, bindings, MessageType.REQUEST, null))
632+
.examples(createBodyExamples(context, operation, bindings, MessageType.REQUEST, null))
602633
.build();
603634

604635
// If any of the top level bindings are required, then the body itself must be required.
@@ -757,6 +788,7 @@ private void createResponsePayload(
757788
: shapeName + "ErrorPayload";
758789
}).toBuilder()
759790
.examples(createExamplesForMembersWithHttpTraits(
791+
context,
760792
operationOrError,
761793
binding,
762794
type,
@@ -840,7 +872,7 @@ private void createResponseDocumentIfNeeded(
840872
String pointer = context.putSynthesizedSchema(synthesizedName, schema);
841873
MediaTypeObject mediaTypeObject = MediaTypeObject.builder()
842874
.schema(Schema.builder().ref(pointer).build())
843-
.examples(createBodyExamples(operationOrError, bindings, messageType, operation))
875+
.examples(createBodyExamples(context, operationOrError, bindings, messageType, operation))
844876
.build();
845877

846878
responseBuilder.putContent(mediaType, mediaTypeObject);

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ private boolean hasSingleUnionMember(StructureShape shape, Model model) {
166166
}
167167

168168
@Override
169-
Node transformSmithyValueToProtocolValue(Node value) {
169+
Node transformSmithyValueToProtocolValue(Context<RestJson1Trait> context, Shape shape, Node value) {
170170
return value;
171171
}
172172
}

0 commit comments

Comments
 (0)