在我的Spring Boot Rest API中,我为每个端点的每个响应(与方法无关)发送唯一的请求ID标头“ x-request-id”。我可以使用类似以下内容添加此内容:
@ApiResponses(value = {
@ApiResponse(
code = 200,
message = "Successful status response",
responseHeaders = {
@ResponseHeader(
name = "x-request-id",
description = "auto generated unique request id",
response = String.class)})
})
这很好,我可以在Swagger用户界面中看到它。但是,对每个端点执行此操作是一个繁琐的维护问题。我希望在全局范围内执行此操作,但是Springfox documentation仅使用.globalResponseMessage选项显示有关全局响应消息的信息-我找不到全局响应头的任何内容。
最终创建注释来处理此问题:
package com.abc.xyz.api.docs.annotations;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import io.swagger.annotations.ResponseHeader;
import com.abc.xyz.api.constants.ApiConstants;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@ApiResponses(value = {
@ApiResponse(
code = 200,
message = "Successful status response",
responseHeaders = {
@ResponseHeader(
name = ApiConstants.REQUESTIDHEADER,
description = ApiConstants.REQUESTIDDESCRIPTION,
response = String.class)}),
@ApiResponse(
code = 401,
message = "Successful status response",
responseHeaders = {
@ResponseHeader(
name = ApiConstants.REQUESTIDHEADER,
description = ApiConstants.REQUESTIDDESCRIPTION,
response = String.class)}),
@ApiResponse(
code = 403,
message = "Successful status response",
responseHeaders = {
@ResponseHeader(
name = ApiConstants.REQUESTIDHEADER,
description = ApiConstants.REQUESTIDDESCRIPTION,
response = String.class)}),
@ApiResponse(
code = 404,
message = "Successful status response",
responseHeaders = {
@ResponseHeader(
name = ApiConstants.REQUESTIDHEADER,
description = ApiConstants.REQUESTIDDESCRIPTION,
response = String.class)}),
}
)
public @interface RequestIdMethod {};
有了这个,我可以将它添加为方法前面的标记注释:
@RequestMapping(value = "/heartbeat", method = RequestMethod.GET)
@RequestIdMethod
public Heartbeat checkHeartbeat() {
return new Heartbeat(status);
}
这不是很好,因为我需要为每个http返回代码重复整个@ApiResponse批注块(显然可能还有其他返回代码,但我只介绍了Springfox显示的默认代码)。如果有一种方法可以参数化整个@ApiResponse块,那就更好了。
我更新了Docket配置,以在每个API上包含Global标头。希望这会有所帮助。
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(new ApiInfoBuilder()
.contact(new Contact("My Support", null, "My Email"))
.description("My Description")
.licenseUrl("My License")
.title("My Title")
.termsOfServiceUrl("My Terms and Conditions")
.version("My Version")
.build())
.globalOperationParameters(Collections.singletonList(new ParameterBuilder()
.name("x-request-id")
.modelRef(new ModelRef("string"))
.parameterType("header")
.required(false)
.build()))
.select()
.paths(PathSelectors.regex("/user*))
.build()
.directModelSubstitute(LocalDate.class, String.class)
.directModelSubstitute(LocalDateTime.class, String.class);
我知道我来这里参加晚会了,但是我确实找到了一种使用反射在每个响应中全局添加标头的方法(可能不需要,但事实证明这是我获得每个响应的最简单方法。您也可以检查所有ApiResponses
注释,但是其中一些注释是隐式添加的,因此不再使用该方法。)
@Component @Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER + 10) public class RequestIdResponseHeaderPlugin implements OperationBuilderPlugin { @Override public boolean supports(DocumentationType documentationType) { return true; } @Override public void apply(OperationContext operationContext) { try { // we use reflection here since the operationBuilder.build() method would lead to different operation ids // and we only want to access the private field 'responseMessages' to add the request-id header to it Field f = operationContext.operationBuilder().getClass().getDeclaredField("responseMessages"); f.setAccessible(true); Set<ResponseMessage> responseMessages = (Set<ResponseMessage>) f.get(operationContext.operationBuilder()); responseMessages.forEach(message -> { int code = message.getCode(); Map<String, Header> map = new HashMap<>(); map.put("my-header-name", new Header(null, null, new ModelRef("string"))); ResponseMessage responseMessage = new ResponseMessageBuilder().code(code).headersWithDescription(map).build(); operationContext.operationBuilder().responseMessages(Collections.singleton(responseMessage)); }); } catch (NoSuchFieldException | IllegalAccessException e) { e.printStackTrace(); } } }
[在研究了操作构建器的方法
responseMessages()
之后发现了这种方式。它在内部根据状态码合并响应头,逻辑本身将简单地将头添加到现有的响应头中。
希望它可以帮助某人,因为它不需要您注释每个端点。