Swagger declaration schema = @Schema(implementation = Map.class) 表示 Schema as String in swagger-ui
Swagger declaration schema = @Schema(implementation = Map.class) represents Schema as String in swagger-ui
我正在尝试创建 springdoc
swagger 文档,我想以一种对客户来说更易读的方式来表示具有数据类型 Map<String, Object>
的请求正文。但是当我声明 @io.swagger.v3.oas.annotations.parameters.RequestBody(content = @Content(schema = @Schema(implementation = Map.class)
时,架构将以 String
的形式出现(附在下面的屏幕截图中)
方法声明
@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引导会根据方法签名自动推断类型,但对于数据类型Map
并不清楚。例如,默认情况下,类型 Map 将被推断如下
但我想以一种更易于理解的方式向引用我的 API 的客户展示架构。我可以看到 Github 中有一张没有正确解决方案的已关闭票证。根据我的要求,请求主体应该是类型不可知的动态键值对,因此除了以 Map<String, Object>
形式接收请求之外别无他法。有没有人用 Map
类型实现了比创建自定义 request/response 模型更好的方法?
这是 springdoc-openapi 库的默认行为,以便忽略 Spring MVC 支持的其他可注入参数。
如果你想改变这个行为,你可以像下面这样排除它:
SpringDocUtils.getConfig().removeRequestWrapperToIgnore(Map.class);
分享我解决该问题的方法,我已经针对 @io.swagger.v3.oas.annotations.parameters.RequestBody(content = @Content(schema = @Schema(implementation = Map.class)
Schema is coming as String 问题做了一个解决方法。
我在 OpenAPI bean 声明中声明了一个名为 Map 的自定义模式,如下所示
new OpenAPI()
.components(new Components()
.addSchemas("Map", new Schema<Map<String, Object>>().addProperties("< * >", new ObjectSchema())
))
.....
.....
并在 Schema 声明中使用上述模式,如下所示
@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
内部使用的任何类型。
我有一个 API 端点,请求主体需要一个 HashMap。关于如何解决“示例值”问题的信息不多。 带我去正确的地方。为了完整起见,我发布了我的解决方案,但所有功劳都归功于他。 (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
}
我创建了一个 HashMap 扩展 class:
@Schema(description = "Response-Object Map<String, EcoBalance).")
public class EcoMap extends HashMap<String, EcoBalance> {
@JsonIgnore
@Override
public boolean isEmpty() {
return super.isEmpty();
}
}
将其用作响应对象
@ApiResponse(responseCode = "200", content = @Content(mediaType = .., schema = @Schema(implementation = EcoMap.class)), headers = ..
注意 OpenAPI 3 生成器不会生成这样的客户端模型,但在 openapi.yml 中被正确引用(甚至验证)。
我想更新 for my situation. I had to combine the answer by rodiri and this answer by Ondřej Černobila to the SO question SpringDoc - How to Add schemas programmatically。我正在使用 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);
};
}
}
对于我的端点,我使用的是 returns 地图,因此它与接受的答案不同。
@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)
我今天 运行 自己解决了这个问题。事实证明,这实际上是 Swagger 的设计问题(@see )。
尽管如此,我也尝试过使用此处和其他线程中的方法。
这是我的 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 = "john.doe@acme-inc.com")
)
)
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...
}
这会产生如下内容:
重要的是要知道在 JSON 对象中,键总是 string
类型。因此不必显式编写类型。考虑到这一点,这是架构:
我正在尝试创建 springdoc
swagger 文档,我想以一种对客户来说更易读的方式来表示具有数据类型 Map<String, Object>
的请求正文。但是当我声明 @io.swagger.v3.oas.annotations.parameters.RequestBody(content = @Content(schema = @Schema(implementation = Map.class)
时,架构将以 String
的形式出现(附在下面的屏幕截图中)
方法声明
@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引导会根据方法签名自动推断类型,但对于数据类型Map
并不清楚。例如,默认情况下,类型 Map
但我想以一种更易于理解的方式向引用我的 API 的客户展示架构。我可以看到 Github 中有一张没有正确解决方案的已关闭票证。根据我的要求,请求主体应该是类型不可知的动态键值对,因此除了以 Map<String, Object>
形式接收请求之外别无他法。有没有人用 Map
类型实现了比创建自定义 request/response 模型更好的方法?
这是 springdoc-openapi 库的默认行为,以便忽略 Spring MVC 支持的其他可注入参数。
如果你想改变这个行为,你可以像下面这样排除它:
SpringDocUtils.getConfig().removeRequestWrapperToIgnore(Map.class);
分享我解决该问题的方法,我已经针对 @io.swagger.v3.oas.annotations.parameters.RequestBody(content = @Content(schema = @Schema(implementation = Map.class)
Schema is coming as String 问题做了一个解决方法。
我在 OpenAPI bean 声明中声明了一个名为 Map 的自定义模式,如下所示
new OpenAPI()
.components(new Components()
.addSchemas("Map", new Schema<Map<String, Object>>().addProperties("< * >", new ObjectSchema())
))
.....
.....
并在 Schema 声明中使用上述模式,如下所示
@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
内部使用的任何类型。
我有一个 API 端点,请求主体需要一个 HashMap。关于如何解决“示例值”问题的信息不多。
配置方面:
@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
}
我创建了一个 HashMap 扩展 class:
@Schema(description = "Response-Object Map<String, EcoBalance).") public class EcoMap extends HashMap<String, EcoBalance> { @JsonIgnore @Override public boolean isEmpty() { return super.isEmpty(); } }
将其用作响应对象
@ApiResponse(responseCode = "200", content = @Content(mediaType = .., schema = @Schema(implementation = EcoMap.class)), headers = ..
注意 OpenAPI 3 生成器不会生成这样的客户端模型,但在 openapi.yml 中被正确引用(甚至验证)。
我想更新
<!-- 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);
};
}
}
对于我的端点,我使用的是 returns 地图,因此它与接受的答案不同。
@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)
我今天 运行 自己解决了这个问题。事实证明,这实际上是 Swagger 的设计问题(@see
尽管如此,我也尝试过使用此处和其他线程中的方法。
这是我的 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 = "john.doe@acme-inc.com")
)
)
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...
}
这会产生如下内容:
重要的是要知道在 JSON 对象中,键总是 string
类型。因此不必显式编写类型。考虑到这一点,这是架构: