java Sping Boot Open API 3.0 -如何显示自定义示例而无需手动编写JSON

jtoj6r0c  于 2023-03-06  发布在  Java
关注(0)|答案(1)|浏览(85)

我正在处理一个Sping Boot 2.5.2 + Java 8项目,该项目具有Open API 3.0:

<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-ui</artifactId>
    <version>1.6.14</version>
</dependency>

我需要向用户显示一些特定的错误主体,如下所示:
此示例来自另一个Sping Boot 项目,其中swagger与yaml文件进行了Map。

我需要展示一个类似的主体但使用注解的例子(因为如果添加了一个新的端点,它会自动Map到Swagger UI。我们面临着一个问题,开发人员忘记Mapyaml文件中的端点,这个操作试图避免这种情况)。
以下是我的Map:

@ApiResponse(responseCode = "401",
                    description = "Something is required.",
                    content = {
                            @Content(mediaType = "application/json",

                                    examples = {

                                        //The problem lays here!!
                                    }

                            )

                    })
    })
    public abstract ResponseEntity<Mono<Object>> queryLegacy(String query);

我的错误类是ErpResponseBodyDTO.class

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ErpResponseBodyDTO{
  private Long code;
  private String message;
}

如何创建这个类的示例(如new ErpResponseBodyDTO(123, "Error Message");)并将其用作示例?
我是说,就像:

...
@Content(mediaType = "application/json",

examples = {

    new ErpResponseBodyDTO(123, "Error Message"),
    new ErpResponseBodyDTO(456, "Error Message 2"),
    new ErpResponseBodyDTO(789, "Error Message 3")
}
)
...

我不想手动编写Json示例,因为我的API有很多可能的错误,并且在@ExampleObject(value=" {"A":"BIG", "JSON":"HERE"} ")中编写它会污染代码。

dwbf0jvd

dwbf0jvd1#

    • 已解决**
  • 解决方案:以编程方式记录API。*

Spring有一个库,您可以在其中操作整个OpenAPI项目。
这是我的配置类,它是解决方案:

package br.orchestratorapi.config;

import br.com.dto.ErpResponseBodyDTO;
import br.com.exception.MessageError;
import br.com.exception.MyExceptionWrapperClassException;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.examples.Example;
import io.swagger.v3.oas.models.media.Content;
import io.swagger.v3.oas.models.media.MediaType;
import io.swagger.v3.oas.models.responses.ApiResponse;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.springdoc.core.customizers.OpenApiCustomiser;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.util.FileCopyUtils;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UncheckedIOException;
import java.util.List;
import java.util.ArrayList;
import java.util.Optional;

@Configuration
public class OpenAPIExamples {

@Value("classpath:/swagger_examples.json")
    private Resource swaggerExamples;

    @Bean
    public OpenApiCustomiser openApiCustomiser() {
        return openAPI -> buildExamplesFromJson().forEach(exampleValue -> setExamplesOnEndpoints(openAPI, exampleValue, "application/json"));
    }

    private void setExamplesOnEndpoints(OpenAPI api, ExampleValue exampleValue, String bodyType) {
        Optional.ofNullable(api.getPaths())
                .map(paths -> paths.get(exampleValue.getPath()))
                .map(paths -> getOperationForHttpMethod(exampleValue.getHttpMethod(), paths))
                .ifPresent(operation -> setExamplesOnEndpoints(exampleValue, bodyType, operation));
    }

    private void setExamplesOnEndpoints(ExampleValue exampleValue, String bodyType, Operation operation) {
        ApiResponse response = operation.getResponses().get(String.valueOf(exampleValue.getHttpStatus()));
        if(response == null)
             response = new ApiResponse();

        Content content = response.getContent();
        if(content == null)
             content = new Content();

        MediaType mediaType = content.get(bodyType);

        if(mediaType == null)
            mediaType = new MediaType();

        mediaType.addExamples(exampleValue.getExampleName(), exampleValue.getExample());

        content.put(bodyType, mediaType);
        response.setContent(content);

        operation.getResponses().put(String.valueOf(exampleValue.getHttpStatus()), response);
    }

    private Operation getOperationForHttpMethod(String httpMethod, PathItem paths) {
        switch (httpMethod) {
            case "POST":
                return paths.getPost();
            case "PATCH":
                return paths.getPatch();
            case "PUT":
                return paths.getPut();
            case "DELETE":
                return paths.getDelete();
            case "GET":
                return paths.getGet();
            case "OPTIONS":
                return paths.getOptions();
            case "HEAD":
                return paths.getHead();
            case "TRACE":
                return paths.getTrace();
            default:
                return null;
        }
    }

    public List<ExampleValue> buildExamplesFromJson() {
        List<ExampleValue> result = new ArrayList<>();

        JsonObject jsonObject = new Gson().fromJson(asString(swaggerExamples), JsonObject.class);
        JsonArray endpoints = jsonObject.getAsJsonArray("endpoints");

        endpoints.forEach(element -> {
            JsonObject path = element.getAsJsonObject();

            String endpointPath = path.get("path").getAsString();
            String method = path.get("method").getAsString();

            path.get("responses").getAsJsonArray().forEach(response -> {
                JsonObject resp = response.getAsJsonObject();

                int status = resp.get("status").getAsInt();

                resp.getAsJsonArray("errors").forEach(error -> {

                    JsonObject errorObj = error.getAsJsonObject();
                    String enumName = errorObj.get("enum").getAsString();

                    Example example = new Example();
                    example.description(errorObj.get("description").getAsString());
                    example.value(ErpResponseBodyDTO.builder().error(new MyExceptionWrapperClassException(MessageError.valueOf(enumName)).getResponse().getError()).build());

                    ExampleValue exampleValue = new ExampleValue(errorObj.get("exampleName").getAsString(), example, status, method, endpointPath);

                    result.add(exampleValue);

                });

            });

        });

        return result;

    }

    public static String asString(Resource resource) {
        try (Reader reader = new InputStreamReader(resource.getInputStream())) {
            return FileCopyUtils.copyToString(reader);
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    @Data
    @AllArgsConstructor
    private class ExampleValue {
        private String exampleName;
        private Example example;
        private int httpStatus;
        private String httpMethod;
        private String path;
    }

 }

如您所见,我从参考资料中读取了一个Json文件:

{
  "endpoints": [

    {
      "path":  "/endpoint/that/{already}/{exists-in-swagger}",
      "method": "POST",
      "responses": [

        {
          "status":  401,
          "errors":[
            {"description":"A description","enum": "ENUM_THAT_I_HAVE_SO_PAY_ATTENTION", "exampleName":  "You have thrown an error"}
          ]
        }

      ]
    }

  ]
}

相关问题