It's frequent for HTTP (JSON) APIs to wrap response data into some kind of envelope structure. When using HTTP interface clients to integrate with such APIs, it would be nice to have a mechanism that allows simple unwrapping of response data from these envelopes so that HTTP interface client (and calling code) could focus on the domain of the API rather than having to also deal with its protocol details.
The API I recently integrated with using HTTP interface clients has the following response structure for successful responses:
{
"success": true,
"result": {
"k1": "v1",
"k2": "v2"
}
}
And the following for error responses:
{
"success": false,
"code": 1,
"message": "problem"
}
Error responses also use HTTP response status 200
which makes it difficult to use existing ResponseErrorHandler
for any custom error handling.
Currently I'm addressing these challenges using something along these lines:
record ApiResult<T>(Boolean success, T result, Integer code, String message) implements Supplier<T> {
@Override
public T get() {
if (Boolean.TRUE.equals(success())) {
return result();
}
else {
throw new ApiException(code(), message());
}
}
}
class MyMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {
@Override
public Object read(Type type, Class<?> contextClass, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
JavaType javaType = getJavaType(type, contextClass);
Object result;
if (javaType.hasRawClass(ApiResult.class)) {
result = super.read(type, contextClass, inputMessage);
}
else {
ResolvableType resolvableType = ResolvableType.forClassWithGenerics(ApiResult.class, javaType.getRawClass());
ApiResult<?> apiResult = (ApiResult<?>) super.read(resolvableType.getType(), contextClass, inputMessage);
result = apiResult.get();
}
return result;
}
}
This works, but it would be nice if Framework provided a simpler and more obvious way to unwrap relevant data from these kind of API responses.
Finally, there are also examples of similar API response envelopes in Spring ecosystem such as Spring Data's PagedModel
or any of the representation models provided by Spring HATEOAS. Any improvements requested here would also likely benefit when working with APIs that produce those models.
Comment From: quaff
It seems related to #28576