Search code examples
javaswaggerswagger-uiopenapiquarkus

OpenAPI throws Could not resolve reference: Could not resolve pointer: for @ExampleObject files


I am developing a Quarkus service-based application for which I am adding open API based annotations such as @ExampleObject. For this, I would like to add the resources file contents as an example that can appear in the SwaggerUI.

I am getting the following error when I add the reference to the files from the resources folder:

Errors
 
Resolver error at paths./api/generateTestData.post.requestBody.content.application/json.examples.Example1 Schema.$ref
Could not resolve reference: Could not resolve pointer: /Example1.json does not exist in document

Resolver error at paths./api/generateTestData.post.requestBody.content.application/json.examples.Example2 Schema.$ref
Could not resolve reference: Could not resolve pointer: /Example2.json does not exist in document

Following is my Quarkus based Java code:

@RequestBody(description = "InputTemplate body",
        content = @Content(schema = @Schema(implementation = InputTemplate.class), examples = {
                @ExampleObject(name = "Example-1",
                        description = "Example-1 for InputTemplate.",
                        ref = "#/resources/Example1.json"), externalValue = "#/resources/Example2.json"
                @ExampleObject(name = "Example-2",
                        description = "Example-2 for InputTemplate.",
                        ref = "#/resources/Example1.json") //externalValue = "#/resources/Example1.json"
        }))

Note: I am able to add the String as value but the content for these examples is very large so I would like to read from the files only so trying this approach.

Is there any way I can access the resources file and add it as a ref within my @ExampleObject


Solution

  • A working example below:


    Create an OASModelFilter class which implements OASFilter:

    package org.acme;
    
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.node.ObjectNode;
    import org.eclipse.microprofile.openapi.OASFactory;
    import org.eclipse.microprofile.openapi.OASFilter;
    import org.eclipse.microprofile.openapi.models.Components;
    import org.eclipse.microprofile.openapi.models.OpenAPI;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.nio.charset.StandardCharsets;
    import java.util.LinkedHashMap;
    import java.util.Map;
    
    import org.eclipse.microprofile.openapi.models.examples.Example;
    
    public class OASModelFilter implements OASFilter {
    
        ObjectMapper objectMapper = new ObjectMapper();
    
        @Override
        public void filterOpenAPI(OpenAPI openAPI) {
    
            //openApi.getComponents() will result in NULL as we don't have any openapi.yaml file.
            Components defaultComponents = OASFactory.createComponents();
            if(openAPI.getComponents() == null){
                openAPI.setComponents(defaultComponents);
            }
    
            generateExamples().forEach(openAPI.getComponents()::addExample);
        }
    
        Map<String, Example> generateExamples() {
    
    
            Map<String, Example> examples = new LinkedHashMap<>();
    
            try {
    
                //loop over your Example JSON Files,..
                //In this case, the example is only for 1 file.
                ClassLoader loader = Thread.currentThread().getContextClassLoader();
                InputStream userJsonFileInputStream = loader.getResourceAsStream("user.json");
    
                String fileJSONContents = new String(userJsonFileInputStream.readAllBytes(), StandardCharsets.UTF_8);
    
    
    
                //Create a unique example for each File/JSON
                Example createExample = OASFactory.createExample()
                                                  .description("User JSON Description")
                                                  .value(objectMapper.readValue(fileJSONContents, ObjectNode.class));
    
                // Save your Example with a Unique Map Key.
                examples.put("createExample", createExample);
    
            } catch (IOException ioException) {
                System.out.println("An error occured" + ioException);
            }
            return examples;
        }
    
    }
    

    The controller using createExample as its @ExampleObject.

    @Path("/hello")
    public class GreetingResource {
    
        @GET
        @Produces(MediaType.TEXT_PLAIN)
        @APIResponses(
                value = {
                        @APIResponse(responseCode = "200", content =  @Content(
                                mediaType = "*/*",
                                examples = {
                                        @ExampleObject(name = "boo",
                                                summary = "example of boo",
                                                ref = "createExample")
                                }
    
                        ))
                }
        )
        public String hello() {
            return "Hello RESTEasy";
        }
    }
    

    In your application.properties, specify the following: Take note that it references the full package path of the Filter.

    mp.openapi.filter=org.acme.OASModelFilter
    

    Contents of user.json file:

    {
      "hello": "world",
      "my": "json",
      "testing": "manually adding resource JSONs as examples"
    }
    

    The JSON file used is located directly under resources. Of course you can change that path, but you need to update your InputStream.

    enter image description here


    mvn clean install
    

    mvn quarkus:dev
    

    Go to http://localhost:8080/q/swagger-ui/ and you will now see your user.json file contents displayed

    enter image description here

    Hopes this helps you,

    References for my investigation:

    https://github.com/labcabrera/rolemaster-core/blob/c68331c10ef358f6288518350c79d4868ff60d2c/src/main/java/org/labcabrera/rolemaster/core/config/OpenapiExamplesConfig.java

    https://github.com/bf2fc6cc711aee1a0c2a/kafka-admin-api/blob/54496dd67edc39a81fa7c6da4c966560060c7e3e/kafka-admin/src/main/java/org/bf2/admin/kafka/admin/handlers/OASModelFilter.java