yahoo / elide

Elide is a Java library that lets you stand up a GraphQL/JSON-API web service with minimal effort.
https://elide.io
Other
1k stars 228 forks source link

Add support for extension property of OpenAPI 3_0 #3301

Open AleCamerini opened 3 days ago

AleCamerini commented 3 days ago

Currently, OpenAPI swagger documentation supports the definition of extension properties in the @Schema annotation, it is built like a Map<String, Object> and generally allows the OpenAPI user to define customs properties on the documentation.

Expected Behavior

We could use this feature to address which of our attributes is a localized attribute by simply defining this annotation:

@Schema(extensions = {
            @Extension(properties = {
                    @ExtensionProperty(name = "localized", value = true)
            })
    })

Multiple extentionProperties can be defined in the same Schema. allowing us to enhance the OpenAPI doc further. It could also be useful to define the types of relationships in the OpenAPI documentation with something like this:

@Schema(extensions = {
            @Extension(properties = {
                    @ExtensionProperty(name = "relationType", value = "oneToOne")
            })
    })

the output of the schema above for a normal attribute will be something like this:

"properties": {
    "name": {
        "type": "string",
         "readOnly": false,
         "writeOnly": false,
         "localized": true,
         "example": null
    },
   ...
}

Current Behavior

Currently this feature is not supported on Elide meaning that the openAPI doc ignores this property inside the schema annotation

Possible Solution

A possible solution that can be done is to add inside the JsonApiModelResolver.class a method like this:

    private Map<String, Object> getExtensions(Type<?> clazz, String fieldName) {
        io.swagger.v3.oas.annotations.media.Schema property = getSchema(clazz, fieldName);
        return property == null ? Map.of()
                : Arrays.stream(property.extensions())
                        .flatMap(extension -> Arrays.stream(extension.properties()))
                        .collect(Collectors.toMap(ExtensionProperty::name, ExtensionProperty::value));
}

Then call it inside the processAttribute and processRelationship method by calling the Schema<?>.setExtensions method like this:

attribute.setExtensions(getExtensions(clazzType, attributeName));

Context

The reason I'm opening this feature is that I need to send more information to the FrontEnd point of my applications through OpenAPI to handle various situations, such as localized properties and others. By adding the extension property we are able to send all the necessary information and many more, leading to a more customizable experience for OpenAPI definition.

aklish commented 1 day ago

This makes sense and the approach seems reasonable. If you push a PR for this change, happy to review and merge it.