在用例中处理来自网关实现的错误 - Clean Architecture
Handling errors coming from gateway implementation in the use case - Clean Architecture
当我们使用洋葱架构构建软件时,如何处理来自网关实现的异常?
为了澄清,我使用 Java 和 SpringBoot 创建了一个示例:
@Component
@AllArgsConstructor
public class SaveAddressUseCase{
private final GetCustomerGateway getCustomerGateway;
public void execute(AddressDomain address, Long customerId){
try{
//validates the customerId supplied and returns the customer from an external service.
CustomerDomain customer = getCustomerGateway.execute(customerId);
address.setCustomer(customer);
//saves the address
}catch(CustomerNotFoundException ex) {
AddressErrorDomain addressErrorDomain = new AddressErrorDomain();
//saves the address in a error table with httpStatus 404
} catch (InternalErrorException ex) {
AddressErrorDomain addressErrorDomain = new AddressErrorDomain();
//save the address in a error table with httpStatus 500
}
}
}
这是一个保存地址的简单用例,但首先需要从外部服务获取该地址的客户。如果找不到客户,我需要将地址保存在错误table中,以便稍后处理。如果此外部服务已关闭,情况也是如此,但区分这两个错误很重要,我可以使用从我的 API 调用返回的 HttpStatus 来处理这个问题。
public interface GetCustomerGateway {
CustomerDomain execute(Long customerId);
}
@Component
@AllArgsConstructor
public class GetCustomerGatewayImpl implements GetCustomerGateway {
private final CustomerApi customerApi; //Feign interface to call an external service
public CustomerDomain execute(Long customerId){
try{
return customerApi.getCustomerById(customerId);
}catch(FeignException ex){
if (ex.status() == HttpStatus.NOT_FOUND.value()) {
throw new CustomerNotFoundException();
} else {
throw new InternalErrorException();
}
}
}
}
最后,这是我的网关实现,它使用简单的 Feign 接口调用此外部服务并抛出两个我从 RuntimeException 扩展的自定义异常。
问题:在用例中捕获这两个异常我不是在处理只有网关必须知道的细节?或者更糟的是,我没有使用异常来控制我的应用程序的流程?我如何才能以比示例中更好的方式处理来自网关实现的错误?
Obs: 在这个例子中,重要的是保存错误的地址table,以免破坏客户端的用户体验,我还需要区分这些错误。
提前致谢!
考虑为此使用@ControllerAdvice 以保持控制器清洁和专注
@ControllerAdvice
@Slf4j
public class RestExceptionHandler {
//Magic happens here
}
在 RestExceptionHandler 内部,您可以像这样捕获所有假异常并根据需要处理它们
@ResponseBody
@ExceptionHandler(Throwable.class)
public final ResponseEntity<?> handleFeignExceptions(Exception ex, WebRequest request) {
if (ex instanceof FeignException) {
return handle((FeignException) ex);// define your custom handle method
}
}
当我们使用洋葱架构构建软件时,如何处理来自网关实现的异常?
为了澄清,我使用 Java 和 SpringBoot 创建了一个示例:
@Component
@AllArgsConstructor
public class SaveAddressUseCase{
private final GetCustomerGateway getCustomerGateway;
public void execute(AddressDomain address, Long customerId){
try{
//validates the customerId supplied and returns the customer from an external service.
CustomerDomain customer = getCustomerGateway.execute(customerId);
address.setCustomer(customer);
//saves the address
}catch(CustomerNotFoundException ex) {
AddressErrorDomain addressErrorDomain = new AddressErrorDomain();
//saves the address in a error table with httpStatus 404
} catch (InternalErrorException ex) {
AddressErrorDomain addressErrorDomain = new AddressErrorDomain();
//save the address in a error table with httpStatus 500
}
}
}
这是一个保存地址的简单用例,但首先需要从外部服务获取该地址的客户。如果找不到客户,我需要将地址保存在错误table中,以便稍后处理。如果此外部服务已关闭,情况也是如此,但区分这两个错误很重要,我可以使用从我的 API 调用返回的 HttpStatus 来处理这个问题。
public interface GetCustomerGateway {
CustomerDomain execute(Long customerId);
}
@Component
@AllArgsConstructor
public class GetCustomerGatewayImpl implements GetCustomerGateway {
private final CustomerApi customerApi; //Feign interface to call an external service
public CustomerDomain execute(Long customerId){
try{
return customerApi.getCustomerById(customerId);
}catch(FeignException ex){
if (ex.status() == HttpStatus.NOT_FOUND.value()) {
throw new CustomerNotFoundException();
} else {
throw new InternalErrorException();
}
}
}
}
最后,这是我的网关实现,它使用简单的 Feign 接口调用此外部服务并抛出两个我从 RuntimeException 扩展的自定义异常。
问题:在用例中捕获这两个异常我不是在处理只有网关必须知道的细节?或者更糟的是,我没有使用异常来控制我的应用程序的流程?我如何才能以比示例中更好的方式处理来自网关实现的错误?
Obs: 在这个例子中,重要的是保存错误的地址table,以免破坏客户端的用户体验,我还需要区分这些错误。
提前致谢!
考虑为此使用@ControllerAdvice 以保持控制器清洁和专注
@ControllerAdvice
@Slf4j
public class RestExceptionHandler {
//Magic happens here
}
在 RestExceptionHandler 内部,您可以像这样捕获所有假异常并根据需要处理它们
@ResponseBody
@ExceptionHandler(Throwable.class)
public final ResponseEntity<?> handleFeignExceptions(Exception ex, WebRequest request) {
if (ex instanceof FeignException) {
return handle((FeignException) ex);// define your custom handle method
}
}