Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wrap refs with defaults in an allOf #1887

Merged
merged 1 commit into from
Jul 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 86 additions & 1 deletion docs/source-2.0/guides/converting-to-openapi.rst
Original file line number Diff line number Diff line change
Expand Up @@ -790,6 +790,89 @@ supportNonNumericFloats (``boolean``)
}


.. _generate-openapi-setting-disableDefaultValues:

disableDefaultValues (``boolean``)
Set to true to disable adding default values.

.. code-block:: json

{
"version": "2.0",
"plugins": {
"openapi": {
"service": "example.weather#Weather",
"disableDefaultValues": true
}
}
}

With this disabled, default values will not appear in the output:

.. code-block:: json

{
"Foo": {
"type": "object",
"properties": {
"bam": {
"type": "array",
"items": {
"type": "string"
}
},
"bar": {
"type": "number"
},
"bat": {
"$ref": "#/definitions/MyEnum"
},
"baz": {
"type": "string"
}
}
}
}

With this enabled (the default), default values will be added, with ``$ref``
pointers wrapped in an ``allOf``:

.. code-block:: json

{
"Foo": {
"type": "object",
"properties": {
"bam": {
"type": "array",
"items": {
"type": "string"
},
"default": []
},
"bar": {
"type": "number",
"default": 0
},
"bat": {
"allOf": [
{
"$ref": "#/definitions/MyEnum"
},
{
"default": "FOO"
}
]
},
"baz": {
"type": "string",
"default": ""
}
}
}
}


----------------
Security schemes
----------------
Expand Down Expand Up @@ -1438,7 +1521,9 @@ Amazon API Gateway limitations

The ``default`` property in OpenAPI is not currently supported by Amazon
API Gateway. The ``default`` property is automatically removed from OpenAPI
models when they are generated for Amazon API Gateway.
models when they are generated for Amazon API Gateway. Additionally, ``default``
values will not be set on ``$ref`` pointers or wrapped in an ``allOf`` as
described in :ref:`disableDefaultValues <generate-openapi-setting-disableDefaultValues>`.


-------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,6 @@ public List<ApiGatewayConfig.ApiType> getApiTypes() {
public void updateDefaultSettings(Model model, OpenApiConfig config) {
config.setAlphanumericOnlyRefs(true);
config.getDisableFeatures().add("default");
config.setDisableDefaultValues(true);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@
},
"components": {
"schemas": {
"DefaultEnum": {
"type": "string",
"enum": [
"FOO",
"BAR"
]
},
"HasDefaultRequestContent": {
"type": "object",
"properties": {
Expand All @@ -59,6 +66,9 @@
"items": {
"type": "string"
}
},
"baz": {
"$ref": "#/components/schemas/DefaultEnum"
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ $version: "2.0"

namespace example.smithy

use aws.protocols#httpChecksum
use aws.protocols#restJson1

@restJson1
Expand All @@ -20,9 +19,15 @@ operation HasDefault {
output := {
foo: String = ""
bar: StringList = []
baz: DefaultEnum = "FOO"
}
}

list StringList {
member: String
}

enum DefaultEnum {
FOO
BAR
}
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ public String toString() {
private boolean supportNonNumericFloats = false;
private boolean enableOutOfServiceReferences = false;
private boolean useIntegerType;
private boolean disableDefaultValues = false;

public JsonSchemaConfig() {
nodeMapper.setWhenMissingSetter(NodeMapper.WhenMissing.IGNORE);
Expand Down Expand Up @@ -406,6 +407,20 @@ public void setUseIntegerType(boolean useIntegerType) {
}


public boolean getDisableDefaultValues() {
return disableDefaultValues;
}

/**
* Set to true to disable default values on schemas, including wrapping $ref pointers in an `allOf`.
*
* @param disableDefaultValues True to disable setting default values.
*/
public void setDisableDefaultValues(boolean disableDefaultValues) {
this.disableDefaultValues = disableDefaultValues;
}


/**
* JSON schema version to use when converting Smithy shapes into Json Schema.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,13 @@ private Schema createRef(MemberShape member) {
if (converter.isInlined(member)) {
return member.accept(this);
} else {
Schema.Builder builder = Schema.builder().ref(converter.toPointer(member.getTarget()));
member.getTrait(DefaultTrait.class).ifPresent(trait -> builder.defaultValue(trait.toNode()));
return builder.build();
// Wrap the ref and default in an allOf if disableDefaultValues has been not been disabled on config.
if (member.hasTrait(DefaultTrait.class) && !converter.getConfig().getDisableDefaultValues()) {
Schema ref = Schema.builder().ref(converter.toPointer(member.getTarget())).build();
Schema def = Schema.builder().defaultValue(member.expectTrait(DefaultTrait.class).toNode()).build();
return Schema.builder().allOf(ListUtils.of(ref, def)).build();
}
return Schema.builder().ref(converter.toPointer(member.getTarget())).build();
}
}

Expand Down Expand Up @@ -317,8 +321,9 @@ private Schema.Builder updateBuilder(Shape shape, Schema.Builder builder) {
.map(EnumTrait::getEnumDefinitionValues)
.ifPresent(builder::enumValues);

shape.getTrait(DefaultTrait.class)
.ifPresent(trait -> builder.defaultValue(trait.toNode()));
if (shape.hasTrait(DefaultTrait.class) && !converter.getConfig().getDisableDefaultValues()) {
builder.defaultValue(shape.expectTrait(DefaultTrait.class).toNode());
}

return builder;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -689,7 +689,7 @@ public void removesMixins() {
}

@Test
public void appliesDefaults() {
public void appliesDefaultsByDefault() {
Model model = Model.assembler()
.addImport(getClass().getResource("default-values.smithy"))
.assemble()
Expand All @@ -703,4 +703,23 @@ public void appliesDefaults() {
IoUtils.toUtf8String(getClass().getResourceAsStream("default-values.jsonschema.v07.json")));
Node.assertEquals(document.toNode(), expected);
}

@Test
public void defaultsCanBeDisabled() {
Model model = Model.assembler()
.addImport(getClass().getResource("default-values.smithy"))
.assemble()
.unwrap();
JsonSchemaConfig config = new JsonSchemaConfig();
config.setDisableDefaultValues(true);
SchemaDocument document = JsonSchemaConverter.builder()
.config(config)
.model(model)
.build()
.convert();

Node expected = Node.parse(
IoUtils.toUtf8String(getClass().getResourceAsStream("default-values-disabled.jsonschema.v07.json")));
Node.assertEquals(document.toNode(), expected);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"definitions": {
"Foo": {
"type": "object",
"properties": {
"bam": {
"type": "array",
"items": {
"type": "string"
}
},
"bar": {
"type": "number"
},
"bat": {
"$ref": "#/definitions/TestEnum"
},
"baz": {
"type": "string"
}
}
},
"TestEnum": {
"type": "string",
"enum": [
"FOO",
"BAR"
]
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,28 @@
"type": "number",
"default": 0
},
"bat": {
"allOf": [
{
"$ref": "#/definitions/TestEnum"
},
{
"default": "FOO"
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this is a better way to do member documentation traits too

]
},
"baz": {
"type": "string",
"default": ""
}
}
},
"TestEnum": {
"type": "string",
"enum": [
"FOO",
"BAR"
]
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,15 @@ namespace smithy.example
structure Foo {
bar: Integer = 0
baz: String = ""
bam: StringList = []
bam: StringList = [],
bat: TestEnum = "FOO"
}

list StringList {
member: String
}

enum TestEnum {
FOO
BAR
}