Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing error messages from SSE (Webflux) Spring Boot app to Angular 7 frontend

My application is a Spring Boot app with several end points. We are trying to add an SSE enabled endpoint, using Webflux.

Use case :

Step 1: Front-end submits a request to a POST endpoint and gets a unique ID.

Step 2: Front end fetches processed result using a GET endpoint (SSE enabled - Flux)

Angular uses EventSource object to consume the SSE endpoint. It requires the end point to produce text/event-stream. It works very well for positive test cases. But when runtime exceptions are thrown from the service, Angular frontend cannot get the HTTP status codes and exception details. It just errors with no data.

Thrown exceptions:

@ResponseStatus(code = HttpStatus.NOT_FOUND)
public class RequestNotFoundException extends RuntimeException {

    private static final long serialVersionUID = 1L;

    public RequestNotFoundException(String message) {
        super(message);
    }
}

As mentioned in this, returning a Flux<ServerSentEvent> and terminating the flux with a custom event:

Java endpoint

 @GetMapping(path= "{id}/async", produces=MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ServerSentEvent<Optional<ProcessedResult>>> getProcessedResultStream(
        @PathVariable("id") @ApiParam(value = "The unique identifier of the request", required = true) String id)
        throws InterruptedException {
    // Combining data and adding a disconnect event to handle at the frontend.
    return Flux.concat(
            Flux.just(ServerSentEvent.<Optional<ProcessedResult>>builder(service.getProcessedResult(id))
                    .build()),
            Flux.just(ServerSentEvent.<Optional<ProcessedResult>>builder().event("disconnect").build()));
}

This helps to close the connection at the UI end by disconnecting it. But my main issue remains open. How should I go about propagating error messages back to the frontend ? All other (normal) endpoints throw custom runtime exceptions with proper HTTP codes as given above.

Should I change my ProcessedResult class to take exception details also ?

like image 218
Jay Avatar asked Mar 19 '19 14:03

Jay


1 Answers

Server side events use an open HTTP connection to stream content from the server. According to W3C spec of Eventsource HTTP 200 OK responses with a proper Content-Type header is required to establish the connection, HTTP 500, 502, 503, 504 or any other network errors will cause the browser to reestablish the connection. If none of the above cases is satisfied an error event is triggered with readyState = 'CLOSED'. In short, the onError callback is only for handling network timeouts or access control issues.

It is not possible to send a different HTTP status code based on runtime exception since you already send 200 Ok when you establish the connection. The only way to handle runtime error is to catch the exception and send a custom named event from the server and close the EvetSource based on that.

like image 115
Nemoy Avatar answered Nov 13 '22 00:11

Nemoy