-1

I have something like this:

@RestController
public class MyController {

    @GetMapping("/myAddress")
    public Response generateReportAsync(...) {
         ...
    }

}

This web service generates a report file according to the Accept header requested (pdf, xls, csv...). Since the generation is performed asynchronously, the response returned is actually a JSON at first and the report is made accessible later.

My problem is that when I invoke this passing an Accept header like application/pdf I receive a 406 back since the WS replies with a JSON. Is there any way I can force a JSON reply with any Accept header I receive only for this specific mapping?

I've tried playing around with the produces and consumes properties on the GetMapping annotations without luck. Other answers I've found use a global configuration or mess with the HttpResponse. If possible I'd like to use a more declarative approach with annotations.

Thanks!

Aurasphere
  • 3,841
  • 12
  • 44
  • 71
  • Why would you request a PDF response when you **know** the REST end point will return a JSON? It is the followup REST request for the actual PDF that should specify `Accept: application/pdf`, not the REST request to *start* generating the PDF. If that first request needs to specify which format you want the result in, then that should be a query parameter. – Andreas Apr 21 '20 at 08:29
  • @Andreas the reason is making the API uniform with the synchronous counterpart – Aurasphere Apr 21 '20 at 08:34
  • I don't understand the downvote. The question follows the guidelines, contains code, is specific and says what I've done. Care to explain? – Aurasphere Apr 21 '20 at 08:35
  • But the asynchronous version should be expecting JSON on the first call, and whatever format was requested on the second call. Why would the client say "give me a PDF as answer to this request", if it knows darn well that the answer will be JSON? And it knows, because it has to parse and read that JSON. The REST API you're proposing is not making any sense. – Andreas Apr 21 '20 at 09:20
  • 1
    If it's the same REST End Point for both the first request getting JSON back and the followup request getting PDF back, then the client should specify that, with e.g. `Accept: application/pdf, application/json;q=0.5`, i.e. saying "I'd prefer a PDF with the report, but will accept a JSON if the report is not ready yet". Then your request handler method can do it's own content negotiation, and return a rendered report in a format acceptable to the client, or starting generating that and return a JSON saying "will be done soon". – Andreas Apr 21 '20 at 09:26
  • @Andreas this is a good solution. If you want to write an answer I'll accept it – Aurasphere Apr 21 '20 at 11:40
  • just return http status 204 on first call e.g. request accepted, response pending – Marc Stroebel Apr 21 '20 at 13:09

1 Answers1

2

Sounds like you need to implement a single REST End Point working as follows:

  • On first request, a background job is started to generate the report.
    A JSON response is returned indicating that report generation has been requested.

  • If background job not yet completed, a subsequent request will return a JSON response indicating report generation in progress. If possible, a progress indicator (e.g. 25%) may be included in the response.

  • If background job fails, subsequent requests will return a JSON response indicating caused of failure.

  • Otherwise, subsequent requests will return the generated report, with appropriate Content-Type.

Now for the important part: All requests must include Accept header listing both application/json and one or more supported report formats (e.g. application/pdf, text/csv), otherwise a 406 Not Acceptable is returned.

Quality values (;q=) can be used to indicate preference of report format.


Since different clients might want the same report in different formats, the server should support generation of multiple report files.

E.g. if a request is received with Accept: application/pdf, application/json;q=0.1, the system will start generating a PDF. If another request is received with Accept: text/csv, application/json;q=0.1, the system will start generating a CSV file, in parallel or queued.

Subsequent requests will ignore pending/completed reports that are not acceptable. e.g. if a third request is received with Accept: text/csv;q=0.5, application/pdf, application/json;q=0.1, the system will start generating a CSV file, the system will return status response of PDF generation, or download the PDF if completed.

Andreas
  • 154,647
  • 11
  • 152
  • 247