简体   繁体   English

如何使用 microprofile 记录内部错误

[英]How to document internal error with microprofile

Assume following code written with Quarkus.假设以下代码是用 Quarkus 编写的。 But can as well be with micronaut.但也可以与 micronaut 一起使用。

@POST
@Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    @APIResponses(
            value = {
                    @APIResponse(
                            responseCode = "201",
                            description = "Customer Created"),
                    @APIResponse(
                            responseCode = "400",
                            description = "Customer already exists for customerId")
            }
    )
    public Response post(@Valid Customer customer) {
        final Customer saved = customerService.save(customer);
        return Response.status(Response.Status.CREATED).entity(saved).build();
    }

The Customer definition includes a field pictureUrl.客户定义包括一个字段 pictureUrl。 CustomerService is responsible to validate the the URL is a valid URL and that the image really exists. CustomerService 负责验证 URL 是有效的 URL 并且图像确实存在。

This means that following exception will be processed by the service: MalformedURLException and IOException.这意味着服务将处理以下异常:MalformedURLException 和 IOException。 The CustomerService catches these errors and throws an application specific exception to report that the image does not exist or the path is not correct: ApplicationException. CustomerService 捕获这些错误并抛出应用程序特定异常以报告图像不存在或路径不正确:ApplicationException。

How do you document this error case with microprofile?您如何使用 microprofile 记录此错误案例?

My research suggests that I have to implement an exception mapper of the form:我的研究表明我必须实施以下形式的异常映射器:

public class ApplicationExceptionMapper implements ExceptionMapper<NotFoundException> {

    @Override
    @APIResponse(responseCode = "404", description = "Image not Found",
        content = @Content(
            schema = @Schema(implementation = Customer.class)
        )
    )
    public Response toResponse(NotFoundException t) {
        return Response.status(404, t.getMessage()).build();
    }

}

And once I have a such mapper, the framework would know how to convert my exception into Response.一旦我有了这样的映射器,框架就会知道如何将我的异常转换为 Response。 Is my analysis correct?我的分析正确吗? What is the best practice?最佳做法是什么?

You are more or less pointed in the right direction, your question can be divided in two, let me answer separately both:您或多或少指向了正确的方向,您的问题可以分为两个,让我分别回答两个:

  1. How to document an error using microprofile openapi: Using the api responses and the operation description is the correct way as you are doing, you can include a extended description of your errors and the specific Http error code associated with each if you want.如何使用 microprofile openapi 记录错误:使用 api 响应和操作描述是正确的方法,如果需要,您可以包含错误的扩展描述以及与每个相关的特定 Http 错误代码。 This annotations should be present in the Rest Resource not in the ExceptionMapper.此注释应存在于 Rest 资源中,而不是 ExceptionMapper 中。
  2. Handling custom errors with micro profile or just the Jax-RS way of dealing with exceptions: A endpoint implemented with Jax-RS Apis knows how to hande WebApplicationExceptions automatically, By launching a custom exception which has this one us parent, the Jax-RS implementation automatically will know how to map your Exception to a Response.使用微配置文件处理自定义错误或仅使用 Jax-RS 处理异常的方式:使用 Jax-RS API 实现的端点知道如何自动处理WebApplicationExceptions ,通过启动具有这个我们父级的自定义异常,即 Jax-RS 实现自动将知道如何 map 您的异常响应。
  3. Dealing with Unexpected exceptions or customizing responses for certain exceptions: By implementing the interface ExceptionMapper, you can further customize the response generation for specific exceptions if you want but this is not generally required.处理意外异常或为某些异常自定义响应:通过实现接口 ExceptionMapper,您可以根据需要进一步自定义特定异常的响应生成,但这通常不是必需的。

A common good strategy for dealing with the scenario you have explained is to have a family of custom exceptions that extend the WebApplicationException where you can specify the response code and message, Or just using the ones provided by jax-rs .处理您所解释的场景的一个常见的好策略是拥有一系列扩展 WebApplicationException 的自定义异常,您可以在其中指定响应代码和消息,或者仅使用jax-rs提供的那些。 And if you need further customization with i18n support or its important to provide a response entity with details associated to the error, then implement the ExceptionMapper.如果您需要进一步定制 i18n 支持,或者提供一个包含与错误相关的详细信息的响应实体很重要,那么请实现 ExceptionMapper。

For the actual error handling and conversion of exceptions to corresponding HTTP responses you would use the JaxRS exception mapper as you already started.对于实际的错误处理和将异常转换为相应的 HTTP 响应,您将使用已经开始的 JaxRS 异常映射器。 But the exception mapper itself, is not considered at all during the creation of the OpenAPI schema, as the OpenAPI extension has no way of obtaining the information about the actual error responses produced by your exception mapper.但是异常映射器本身在创建 OpenAPI 模式期间根本不被考虑,因为 OpenAPI 扩展无法获取有关异常映射器产生的实际错误响应的信息。 So you need to declare the possible error cases on the actual endpoint methods -which can be a bit tedious, especially if your endpoint methods can result in multiple error responses (400, 500, 409..).因此,您需要在实际端点方法上声明可能的错误情况——这可能有点乏味,尤其是当您的端点方法可能导致多个错误响应(400、500、409..)时。 But you can reduce the amount of duplicated code by creating a shared error response definitions.但是您可以通过创建共享的错误响应定义来减少重复代码的数量。

A common pattern for error handling on API layer is to explicitly define the models for your error responses eg I want all my endpoints to return error responses in a form of json document that looks sth like this: API 层错误处理的常见模式是明确定义错误响应的模型,例如我希望我所有的端点以 json 文档的形式返回错误响应,看起来像这样:

{
  "errorCode" : "MY_API_123",
  "errorDescription" : "This operation is not allowed"
  //anything else, details, links etc
}

So I create a POJO model for the response:所以我为响应创建了一个 POJO model:

@Data
@AllArgsConstructor
public class ErrorResponse {
   private String errorCode;
   private String errorDescription;
}

And in my exception mapper I can convert my exception to the error response above:在我的异常映射器中,我可以将我的异常转换为上面的错误响应:

public Response toResponse(Exception e) {
  // you can define a mapper for a more general type of exception and then create specific error responses based on actual type, or you could define your own application level exception with custom error info, keys, maybe even i18n, that you catch here, you get the idea
  if (e instanceOf NotFoundException) {
     return Response.status(404,  new ErrorResponse("MY_API_400", "Object not found")).build();
  }
  if (e instanceOf IllegalArgumentException) {
    return Response.status(400, new ErrorResponse("MY_API_400", "Invalid request")).build();
  }
  
  // fallback if we dont have any better error info
  return Response.status(500,  new ErrorResponse("MY_API_100", "Internal server error")).build();
}


You can then document the possible error responses using the OpenAPi annotations:然后,您可以使用 OpenAPI 注释记录可能的错误响应:

@APIResponses({
  @APIResponse(responseCode = "201", description = "Customer Created"),
  @APIResponse(responseCode = "400", description = "Other object exists for customerId", content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
  @APIResponse(responseCode = "500", description = "Internal error", content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
public Response yourMethod()

Or if you have some responses that are repeated often (such as generic internal server error, unathorized/unathenticated) you can document them on your class extending JaxRS Application and then reference them in your endpoints like this:或者,如果您有一些经常重复的响应(例如一般的内部服务器错误、未经授权/未经授权),您可以将它们记录在您的 class 扩展 JaxRS 应用程序中,然后在您的端点中引用它们,如下所示:

@Authenticated
@APIResponses({
   @APIResponse(responseCode = "200", description = "Ok"),
   @APIResponse(responseCode = "401", ref = "#/components/responses/Unauthorized"),
   @APIResponse(responseCode = "500", ref = "#/components/responses/ServerError")
})
public Response someAPIMethod() {

Example JaxRS application class(useful for other common top level openapi schema attributes) JaxRS 应用程序类示例(对其他常见的顶级 openapi 模式属性很有用)

@OpenAPIDefinition(
   info = @Info(title = "My cool API", version = "1.0.0"),
   components = @Components(
       schemas = {@Schema(name = "ErrorResponse", implementation = ErrorResponse.class)},
       responses = {
          @APIResponse(name = "ServerError", description = "Server side error", content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(ref = "#/components/schemas/ErrorResponse")), responseCode = "500"),
          @APIResponse(name = "NotFound", description = "Requested object not found", content = @Content(schema = @Schema(ref = "#/components/schemas/ErrorResponse")), responseCode = "404"),
          @APIResponse(name = "Forbidden", description = "Authorization error", responseCode = "403"),
          @APIResponse(name = "BadRequest", description = "Bad Request", responseCode = "400"),
          @APIResponse(name = "Unauthorized", description = "Authorization error", responseCode = "401")})
)
public class RESTApplication extends Application {

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM