Swagger 声明 schema = @Schema(implementation = Map.class) 在 swagger-ui 中将 Schema 表示为 String

问题描述 投票:0回答:8

我正在尝试创建

springdoc
swagger 文档,并且我想以客户更容易阅读的方式表示具有数据类型
Map<String, Object>
的请求正文。但是当我声明
@io.swagger.v3.oas.annotations.parameters.RequestBody(content = @Content(schema = @Schema(implementation = Map.class)
时,架构将变为
String
(附有下面的屏幕截图)

enter image description here

方法声明

        @Operation(security = {@SecurityRequirement(name = "bearer-key")}, summary = "Create Data", operationId = "createData", description = "Create createData for the **`type`**. ")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "201", description = "Data created", content = @Content(schema = @Schema(implementation = Map.class),
                    examples = {@ExampleObject(value = "{\n" +
                            "    \"id\": \"927d810c-3ac5-4584-ba58-7c11befabf54\",\n" +
                            "}")})),
            @ApiResponse(responseCode = "400", description = "BAD Request")})
    @PostMapping(value = "/data/type", produces = APPLICATION_JSON_VALUE, consumes = APPLICATION_JSON_VALUE)
    @io.swagger.v3.oas.annotations.parameters.RequestBody(content = @Content(schema = @Schema(implementation = Map.class),
            examples = {@ExampleObject(value = "{\n" +
                    "            \"label\":\"tourism\",\n" +
                    "            \"location\":\"France\"\n" +
                    "         }")}))
    ResponseEntity<Map<String, Object>> createData(@Parameter(name = "type", required = true) @PathVariable("type") String type, @Parameter(name = "request payload") @Valid @RequestBody Map<String, Object> body);

虽然Spring boot会根据方法签名自动推断类型,但对于数据类型

Map
并不清楚。例如,默认情况下,类型 Map 将被推断如下 enter image description here

但我想以更容易理解的方式向引用我的 API 的客户展示 Schema。我可以在 Github 中看到有一张已关闭的票证,但没有正确的解决方案。根据我的要求,请求正文应该是类型不可知的动态键值对,因此除了以

Map<String, Object>
形式接收请求之外没有其他方法。有没有人使用类型
Map
实现了更好的方法,而不是创建自定义请求/响应模型?

spring-boot swagger springdoc springdoc-ui
8个回答
12
投票

分享我针对该问题的工作方法,我已经为

@io.swagger.v3.oas.annotations.parameters.RequestBody(content = @Content(schema = @Schema(implementation = Map.class)
架构作为字符串问题完成了解决方法。

我在 OpenAPI bean 声明中声明了一个名为 Map 的自定义模式,如下所示

new OpenAPI()
                .components(new Components()
                        .addSchemas("Map", new Schema<Map<String, Object>>().addProperties("< * >", new ObjectSchema())
                        ))
                    .....
                    .....

并在架构声明中使用上述架构,如下所示

 @io.swagger.v3.oas.annotations.parameters.RequestBody(
            content = @Content(mediaType = APPLICATION_JSON_VALUE, 
                 schema = @Schema(ref = "#/components/schemas/Map"))

上面的方法可以用来代替

ApiResponse
,如下所示

 @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200",
            content = @Content(mediaType = APPLICATION_JSON_VALUE, 
                 schema = @Schema(ref = "#/components/schemas/Map"))

注意:如果我们使用上述自定义模式方法,我们不需要更改或忽略

SpringDoc
内部使用的任何类型。


9
投票

我有一个 API 端点,请求正文需要一个 HashMap。关于如何解决“示例值”问题的信息并不多。 Prasanth 的回答 引导我到正确的地方。为了完整性,我发布了我的解决方案,但所有功劳都归于他。 (PS:我试图给他的回答点赞,但我没有足够的“分”)

配置方面:

@Configuration
@OpenAPIDefinition
public class DocsConfiguration {
    @Bean
    public OpenAPI customOpenAPI() {
        Schema newUserSchema = new Schema<Map<String, Object>>()
                .addProperties("name",new StringSchema().example("John123"))
                .addProperties("password",new StringSchema().example("P4SSW0RD"))
                .addProperties("image",new StringSchema().example("https://robohash.org/John123.png"));

        return new OpenAPI()
                //.servers(servers)
                .info(new Info()
                        .title("Your app title")
                        .description("App description")
                        .version("1.0")
                        .license(new License().name("GNU/GPL").url("https://www.gnu.org/licenses/gpl-3.0.html"))
                )
                .components(new Components()
                        .addSchemas("NewUserBody" , newUserSchema)
                );
    }
}

控制器端:

    @io.swagger.v3.oas.annotations.parameters.RequestBody(
            content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
                    schema = @Schema(ref = "#/components/schemas/NewUserBody")))
    @PostMapping("/v1/users")
    public Response<User> upsertUser(@RequestBody HashMap<String,Object> user) {
         //Your code here
    }

2
投票

我想根据我的情况更新rodiri的答案。我必须将 rodiri 的答案和 Ondřej Černobila 的答案结合到 SO 问题 SpringDoc - 如何以编程方式添加模式。我正在使用 java 11、spring-boot-starter-parent 2.5.6 和 springdoc-openapi-ui 1.5.12,我相信它正在使用 swagger 3.52.5 <!-- https://mvnrepository.com/artifact/org.springdoc/springdoc-openapi-ui --> <dependency> <groupId>org.springdoc</groupId> <artifactId>springdoc-openapi-ui</artifactId> <version>1.5.12</version> </dependency>

我的配置

import io.swagger.v3.oas.annotations.OpenAPIDefinition; import io.swagger.v3.oas.models.media.ObjectSchema; import io.swagger.v3.oas.models.media.StringSchema; import org.springdoc.core.customizers.OpenApiCustomiser; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration @OpenAPIDefinition public class DocsConfiguration { @Bean public OpenApiCustomiser openApiCustomiser() { return openApi -> { var NewUserBodySchema = new ObjectSchema() .name("NewUserBody") .title("NewUserBody") .description("Object description") .addProperties("name", new StringSchema().example("John123")) .addProperties("password", new StringSchema().example("P4SSW0RD")) .addProperties("image", new StringSchema().example("https://robohash.org/John123.png")); var schemas = openApi.getComponents().getSchemas(); schemas.put(NewUserBodySchema.getName(), NewUserBodySchema); }; } }

对于我的端点,我使用返回 Map 的 get,因此它与接受的答案不同。

@GetMapping(value = "/{userId}") @Operation( summary = "Get Something", description = "Some desciption", responses = { @ApiResponse( responseCode = "200", description = "The Map Response", content = { @Content( mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(ref = "#/components/schemas/NewUserBody") ) }) } ) public ResponseEntity<Map<String, Object>> getMap(@PathVariable String userId)



1
投票

    https://docs.spring.io/spring/docs/5.1.x/spring-framework-reference/web.html#mvc-ann-arguments
  • 如果你想改变这种行为,你可以按如下排除它:

SpringDocUtils.getConfig().removeRequestWrapperToIgnore(Map.class);



1
投票
相关问题

)。 尽管如此,我也尝试使用这里和其他线程中的方法。

这是我的 OpenAPI,其中包含一个用于

Map<Integer,String>

的自定义架构:

@Configuration
@OpenAPIDefinition(
        info = @io.swagger.v3.oas.annotations.info.Info(
                title = "ACME Inc. REST API",
                version = "1.0",
                description = "This is an overview of all REST endpoints of this application",
                contact = @io.swagger.v3.oas.annotations.info.Contact(name = "John Doe", url = "https://acme-inc.com/", email = "[email protected]")
        )
)
public class OpenAPIConfig {
        public static final String ERROR_CODE_MAPPER = "ErrorCode-Mapper";

        @Bean
        public OpenApiCustomiser openApiCustomiser() {
                return openApi -> {
                        Components components = openApi.getComponents();
                        for(Schema<?> schema: buildCustomSchemas()) {
                                components.addSchemas(schema.getName(), schema);
                        }
                };
        }

        private static List<Schema<?>> buildCustomSchemas() {
                ArrayList<Schema<?>> result = new ArrayList<>();

                Schema<?> integerStringMap = new Schema<Map<Integer, String>>()
                        .name(ERROR_CODE_MAPPER)
                        .type("object")
                        .addProperty("error code", new StringSchema().example("Error message belonging to the error code")).example(getErrorCodeExample());
                result.add(integerStringMap);
                // Build more custom schemas...

                return result;
        }

        private static Map<Integer, String> getErrorCodeExample() {
                Map<Integer, String> example = new HashMap<>();
                example.put(666, "Oh no..., the devil himself  showed up and stopped your request");
                return example;
        }
}

注意:

查找您的swagger源代码io.swagger.v3.oas.models.media以获取有用的实用程序类,例如

StringSchema
。您不必从头开始编写所有内容。)
这是我的 REST 端点:

@Operation(summary = "This endpoint returns a list of system error codes, that can occur during processing requests.") @ApiResponses(value = { @ApiResponse( responseCode = "200", description = "Map of all system error codes mapping to their messages", content = {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(ref = "#/components/schemas/"+ ERROR_CODE_MAPPER))} ) }) @GetMapping("/error-codes") public Map<Integer, String> listErrorCodes() { // return your map here... }

这会产生这样的结果:

enter image description here 重要的是要知道,在 JSON 对象中,键始终为

string

类型。因此类型不必显式编写。考虑到这一点,这就是架构:

enter image description here


0
投票
    我创建了一个HashMap扩展类:
  1. @Schema(description = "Response-Object Map<String, EcoBalance).") public class EcoMap extends HashMap<String, EcoBalance> { @JsonIgnore @Override public boolean isEmpty() { return super.isEmpty(); } }

  2. 将其用作响应对象
  3. @ApiResponse(responseCode = "200", content = @Content(mediaType = .., schema = @Schema(implementation = EcoMap.class)), headers = ..

  4. 请注意,OpenAPI 3 生成器不会生成这样的客户端模型,但在 openapi.yml 中正确引用(甚至验证)。

0
投票

@ApiResponses( @ApiResponse( responseCode = "200", **useReturnTypeSchema = true** ) ResponseEntity<Map<String, String>> xxx

这使得将端点记录为返回additionalProperties 架构,这是我所期待的


0
投票
字典、哈希图和关联数组

。 OpenAPI 允许您定义键为字符串的字典。 下面的示例产生与已接受问题相同的结果: import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.StringToClassMapItem; @ApiResponse( responseCode = "200", content = @Content( mediaType = "application/json", schema = @Schema( type = "object", properties = {@StringToClassMapItem(key = "<*>", value = Object.class)} ) )) Map<String, Object> createData(..) {...}

要定义字典,请在内容模式中使用 
type = object

。然后,在

properties
内定义固定键/值,如上例所示。
    

© www.soinside.com 2019 - 2024. All rights reserved.