Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Return application/json response to WebClient request as a Flux #25472

Closed
fransflippo opened this issue Jul 24, 2020 · 4 comments
Closed

Return application/json response to WebClient request as a Flux #25472

fransflippo opened this issue Jul 24, 2020 · 4 comments
Labels
status: duplicate A duplicate of another issue

Comments

@fransflippo
Copy link

Affects:
Spring Webflux 5.2.7.RELEASE

This relates to how WebClient handles traditional application/json responses. From what I've seen, the entire response is always parsed into a Java object in memory and exposed as a Mono.

A very common case in web APIs is that the JSON response consists of a few basic fields followed by a list of "records". Consider for example the following Elasticsearch response to a search request:

{
  "took" : 796,
  "timed_out" : false,
  "_shards" : {
    "total" : 335,
    "successful" : 335,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 176806640,
    "max_score" : 1.0,
    "hits" : [
      {
          ...
      },
      {
          ...
      },
      ....
    ]
  }
}

It would be very useful to be able to get the "hits" elements as a Flux<> as this would enable streaming processing of that list instead of having the entire response loaded in memory at once.

The following StackOverflow questions seem to be looking for something like this:

Sort of related:

I recall (but am struggling to find it now, it's been a while) that Spring Batch had an item reader for reading XML where you could pass it the name of an element that contained a list of records and it would read those records as items. That's kind of what I'm looking for here, but obviously in a web instead of a batch context and for JSON, not XML.

Obviously, if you're in control of the server side, you can amend it to be able to return application/stream+json responses, but the reality is that there are thousands of APIs out there that can't do that yet (but still can return sizeable responses at times).

This is less about the truly reactive concerns like back pressure and more about handling data as a stream instead of as an in-memory list, to facilitate scalability.

It seems technically possible. Jackson has a low-level API that can do streaming deserialization and it couldn't be that hard to wrap a Flux layer around that that retrieves items on demand. I would be happy to look into writing something like that, but in case something like that already exists, I don't want to reinvent the wheel (and then maybe this becomes a documentation issue instead of an enhancement suggestion).

If this is not the right platform, let me know. Between StackOverflow and GitHub issues, this seemed the more appropriate.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Jul 24, 2020
@kiran-italiya
Copy link

kiran-italiya commented Oct 4, 2020

Hey, I am having similar problem as you described. I want to deliver the same response to frontend which I've recieved from API response. Problem is that Json is dynamic and I cannot make a common pojo. Did you find any solution or have any idea what can I do?

@rstoyanchev
Copy link
Contributor

@fransflippo thanks for raising the issue. First to confirm that streaming JSON to a Flux today is only possible if the server returns a JSON array or JSON stream.

We could explore allowing more flexibility. For example there is a related proposal in #24951 to extract a JSON array located under a JSON pointer. That seems relatively straight forward but in your case I imagine you also want to have access the rest of the content? It's less obvious how to provide a general solution for that, e.g. typically decode to Mono or Flux, not both. I also tend to to think that a server should not return a very large response as a single object, so I wonder if Elasticsearch provides an alternative to obtain just an array of hits?

@kiran1901 because it is difficult to think of a general solution for the problem, I think it is important to discuss each use case individually with is own details. It sounds like in your case you want to read from a remote service and then write that down to the server response? If you don't need to decode the content, you could simply obtain it as Flux<DataBuffer> and write it as such to the response.

@kiran-italiya
Copy link

kiran-italiya commented Oct 5, 2020

@rstoyanchev Thnank you very much for your response. As json has become the de facto standard it is necessary that web client should have such mechanism. Eagerly waiting for that feature to be meterialized. I hacked my way with String.class and because json data was rather simple it worked but I know that it is not reliable. However, you've suggested the best solution for me. Thank you very much.

@fransflippo
Copy link
Author

Thanks for taking the time to respond, @rstoyanchev . Actually #24951 looks like exactly what I'm talking about. I guess I wasn't using the right search terms when looking for an existing issue.

Like you say, returning both the array as well as other fields in the JSON response as a Flux makes things a lot more complicated, and I don't think there's a clean way to make that a very generic solution. From my personal experience and what I saw on StackOverflow it's also not what people are looking for: just the simple case of returning a JSON array as a Flux seems like it would solve the bulk of these cases.

I'll close this as a duplicate of #24951 . Thanks!

@rstoyanchev rstoyanchev added status: duplicate A duplicate of another issue and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Oct 6, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: duplicate A duplicate of another issue
Projects
None yet
Development

No branches or pull requests

4 participants