Karthik Prasad
Karthik Prasad

Reputation: 10004

Map Error using onErrorMap in WebFlux for Mono<Void>

I've two microservices, let us say a FrontEnd and BackEnd, for FrontEnd I'm using WebFlux and calling backend service using feign client as shown in below code excample, though the below code example works, but I wanted to have a generic exception handler using Function and feed onto onErrorMap

@RestController
@Slf4j
public class MyFrentEndService {

    @Autowired
    private MyBackEndService client;

    @PostMapping(value="/hello", consumes="application/json")
    public Mono<Void> sayHello(@Valid String msg) {
        log.info("Message is {}", msg);
        return Mono.create(sink-> {
            try {
                client.hello(msg);
            }catch (FeignException e) {
                System.out.println(e.status());
                HttpStatus status = e.status() ==0 ? HttpStatus.SERVICE_UNAVAILABLE : HttpStatus.valueOf(e.status());
                String message = e.getMessage();
                sink.error(new ResponseStatusException(status, message));
            }
            sink.success();
        });

    }

}

Tried to use onErrorMap, but getting compilation error stating, use Mono instead of Mono<Void>

@RestController
@Slf4j
public class MyFrentEndService {

    @Autowired
    private MyBackEndService client;

    @PostMapping(value="/hello", consumes="application/json")
    public Mono<Void> sayHello(@Valid String msg) {
        log.info("Message is {}", msg);
        return Mono.fromSupplier(() -> {
                  client.hello(msg);
                  return null;
               }).onErrorMap(e->{
                     HttpStatus status = e.status() ==0 } HttpStatus.SERVICE_UNAVAILABLE : HttpStatus.valueOf(e.status());
                     String message = e.getMessage();
                     return new ResponseStatusException(status, message);
                });

    }

}

How to use onErrorMap?

Upvotes: 2

Views: 17859

Answers (1)

Felipe Moraes
Felipe Moraes

Reputation: 218

This error is unrelated to the operator onErrorMap. This code dont compile because the compiler can not infer the generic type returned by the method Mono.fromSupplier to be Void - you are returning null on the supplied function. This should be corrected by doing the following:

    @PostMapping(value="/hello", consumes="application/json")
    public Mono<Void> sayHello(@Valid String msg) {
        log.info("Message is {}", msg);
        return Mono.<Void>fromSupplier(() -> {
                  client.hello(msg);
                  return null;
               }).onErrorMap(e->{
                     HttpStatus status = e.status() ==0 ? HttpStatus.SERVICE_UNAVAILABLE : HttpStatus.valueOf(e.status());
                     String message = e.getMessage();
                     return new ResponseStatusException(status, message);
                });

    }

I think that it is more idiomatic to do the following:

    @PostMapping(value="/hello", consumes="application/json")
    public Mono<Void> sayHello(@Valid String msg) {
        log.info("Message is {}", msg);
        return Mono.fromRunnable(() -> {
                  client.hello(msg);
               })
               .then()
               .onErrorMap(e->{
                     HttpStatus status = e.status() ==0 ? HttpStatus.SERVICE_UNAVAILABLE : HttpStatus.valueOf(e.status());
                     String message = e.getMessage();
                     return new ResponseStatusException(status, message);
                });

    }

Finally, I would advise against using blocking calls inside the reactive pipeline unless you really have to. (prefer WebClient or other nonblocking HTTP client over blocking clients as feign).

Upvotes: 2

Related Questions