OpenAPI 抛出无法解析引用:无法解析指针:@ExampleObject 文件

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

我正在开发一个基于 Quarkus 服务的应用程序,我正在为其添加基于 open API 的注释,例如 @ExampleObject。为此,我想添加资源文件内容作为可以出现在 SwaggerUI.

中的示例

当我从资源文件夹中添加对文件的引用时,出现以下错误:

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

以下是我的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"
        }))

注意: 我可以将 String 添加为 value,但是这些示例的内容非常大,所以我只想从文件中读取,所以尝试这种方法。

有什么方法可以访问资源文件并将其作为 ref 添加到我的 @ExampleObject

下面的工作示例:


创建一个实现 OASFilter:

的 OASModelFilter class
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;
    }

}

控制器使用createExample作为其@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";
    }
}

在您的 application.properties 中指定以下内容:请注意,它引用了过滤器的完整包路径。

mp.openapi.filter=org.acme.OASModelFilter

user.json 文件的内容:

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

使用的JSON文件直接位于资源下。当然,您可以更改该路径,但您需要更新您的 InputStream。


mvn clean install

mvn quarkus:dev

转到 http://localhost:8080/q/swagger-ui/,您现在将看到显示的 user.json 文件内容

希望对您有所帮助,

我的调查参考资料:

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

编辑:这在 spring-boot

中运行良好

上面的答案可能有效,但要放入太多代码才能使其有效。

Instead, you can use externalValue field to pass on the JSON file.

例如,

@ExampleObject(
  summary = "temp",
  name =
      "A 500 error",
  externalValue = "/response.json"
)

现在您可以在 /resources/static 下创建 json 文件,如下所示,

Swagger 文档截图

这就是您所需要的。您无需在此处编写任何手动代码。

希望这能帮助您解决问题。

以下有效,但如您所见,我正在创建 PATHS,您仍然需要知道 (path/address/is) 是什么才能创建路径。

它可以帮助您思考以不同的方式处理它。

如果您正在考虑直接修改 @ApiResponses/@ApiResponse 注释,那将行不通。

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.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.Map;

import org.eclipse.microprofile.openapi.models.examples.Example;

import io.quarkus.logging.Log;

public class CustomOASFilter 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);


        openAPI.setPaths(OASFactory.createPaths()
                                   .addPathItem(
                                           "/hello/customer", OASFactory.createPathItem()
                                                                        .GET(
                                                                                OASFactory.createOperation()
                                                                                          .operationId("hello-customer-get")
                                                                                          .summary("A simple get call")
                                                                                          .description("Getting customer information")
                                                                                          .responses(
                                                                                                  OASFactory.createAPIResponses()
                                                                                                            .addAPIResponse(
                                                                                                                    "200", OASFactory.createAPIResponse()
                                                                                                                                     .content(OASFactory.createContent()
                                                                                                                                                        .addMediaType("application/json", OASFactory.createMediaType()
                                                                                                                                                                                                    .examples(generateExamples()))))))));

    }

    Map<String, Example> generateExamples() {

        Map<String, Example> examples = new LinkedHashMap<>();

        try {

            ClassLoader loader = Thread.currentThread().getContextClassLoader();

            String userJSON = new String(loader.getResourceAsStream("user.json").readAllBytes(), StandardCharsets.UTF_8);
            String customerJson = new String(loader.getResourceAsStream("customer.json").readAllBytes(), StandardCharsets.UTF_8);

            Example userExample = OASFactory.createExample()
                                            .description("User JSON Example Description")
                                            .value(objectMapper.readValue(userJSON, ObjectNode.class));

            Example customerExample = OASFactory.createExample()
                                                .description("Customer JSON Example Description")
                                                .value(objectMapper.readValue(customerJson, ObjectNode.class));

            examples.put("userExample", userExample);
            examples.put("customerExample", customerExample);

        } catch (IOException ioException) {
            Log.error(ioException);
        }
        return examples;
    }

}