我正在尝试找出一种管理REST端点验证的简洁方法,这样我就可以在出现错误(HTTP状态代码和一些错误消息)的同时为用户提供有意义的反馈,同时避免验证方法中的副作用也在进行工作。
例如,我需要解析一个json对象,首先我需要验证它是否解析并获取代表它的对象。如果我在解析过程中遇到异常,那么我想告诉用户,但是如果它正确解析,我还想从验证方法中取回对象。
这里有两个问题,验证并将json字符串转换为POJO。如果我将它们放在相同的方法中,那么如果解析失败而没有副作用,如何返回错误字符串?
超级伪代码显示一种可能性,但有副作用:
public Pet parsePet(HTTPResponse httpResponse, String petStr) {
Pet pet = null;
try {
Parser parser = new Parser();
pet = parser.parse(petStr, Pet.class);
} catch(Exception e) {
httpResponse.setStatus(400);
}
return pet;
}
显然在这种情况下,我可以使用空响应来确定它没有解析并避免副作用,但是在一个更复杂的例子中,不同的错误会产生不同的错误状态'我怎样才能避免副作用?
对于这类事情,是否有一些标准的最佳实践或架构概念?
我能想到的“最干净”选项是抛出一些新的异常,例如ValidationException(int statusCode)
,当业务规则被破坏时可能抛出。但随后整个“特殊事物的例外”开始发挥作用。鉴于我最终向用户返回了一个错误,但似乎异常在某种程度上是可以接受的。
答案 0 :(得分:0)
如果我将它们放在同一个方法中,那么如果解析失败而没有副作用,如何返回错误字符串?
发生错误时抛出异常。更高的东西会解释它并将其转换为http错误响应。
你可以做的其他来自Haskell世界的东西就是让这个方法返回Either<Pet, Error>
。将填写这两个中的一个(Pet
或Error
)。调用者需要确定哪一个。我只是在这里给你一个选项,这不是我在惯用的Java代码中看到的。
我能想到的“最干净”选项是抛出一些新的异常,例如
ValidationException(int statusCode)
我认为抛出一个PetParsingException
是一个smidgen清洁器,更高的东西解释异常并判定它是400.你的验证不 知道它是宁静的api的一部分。
答案 1 :(得分:0)
创建一个用于存储错误的新界面:
interface ValidationErrors
{
public void addError(String message);
public List<String> getErrors();
}
更改parsePet方法以接受ValidationErrors的对象而不是HTTPResponse。
public Pet parsePet(String petStr, ValidationErrors errors) {
try {
Parser parser = new Parser();
pet = parser.parse(petStr, Pet.class);
} catch(Exception e) {
errors.addError("Parsing pet failed: " + e.getMessage());
return null;
}
return pet;
}
然后,您可以实现一种方法,将ValidationErrors对象转换为适当的HTTPResponse配置。
ValidationErrors可以随着您的需求而增长 - i。即也许你想在那里存储异常,提供遇到的错误的摘要,或使用自动记录。
PS:Spring验证器使用类似的方法。
答案 2 :(得分:0)
将异常抛出业务方法(可能包含在一些ValidationException中并附带其他详细信息),并让它在方法调用堆栈的更高级别处理。
“更高级别”实际上是一些Web框架错误处理实用程序。在那里,您可以决定如何处理错误 - 返回具有适当HTTP状态的消息,重试该操作或其他内容。
这将使代码更清晰(为此目的已经发明了异常),它实际上将帮助您避免不良副作用(通过回滚事务和类似事件)。