spring-projects / spring-projects/spring-framework

Provide HTTP message conversion support for response envelopes

Open
#35,586 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

in: web status: waiting-for-triage
Dominant language
Java
Stars
60.2k
Forks
38.8k
Avg merge
5d 2h
Merged PRs (30d)
27

Description

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.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with HTTP interface clients and MappingJackson2HttpMessageConverter, especially its read method, and review how ResponseErrorHandler currently handles responses. Compare the requested successful and error envelopes with the existing message-conversion flow; done should be a documented framework mechanism that unwraps supported envelopes and handles their errors consistently.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, spring
Domain
api, backend
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.