I'm having a controller like this one (in Kotlin):
@RestController
@RequestMapping("/")
class CustomerController (private val service: CustomerService) {
@GetMapping("/{id}")
fun findById(@PathVariable id: String,
@RequestHeader(value = IF_NONE_MATCH) versionHeader: String?): Mono<HttpEntity<KundeResource>> =
return service.findById(id)
.switchIfEmpty(Mono.error(NotFoundException()))
.map {
// ETag stuff ...
ok().eTag("...").body(...)
}
}
Im wondering whether there is a better approach than throwing an exception which is annotated with @ResponseStatus(code = NOT_FOUND)
I would like use RouteFunction
instead of @RestController when Spring 5 is stable. Define a HandlerFunction to handle request, and then declare a RouteFunction
to map request to the HandlerFunction:
public Mono<ServerResponse> get(ServerRequest req) {
return this.posts
.findById(req.pathVariable("id"))
.flatMap((post) -> ServerResponse.ok().body(Mono.just(post), Post.class))
.switchIfEmpty(ServerResponse.notFound().build());
}
Check the complete example codes here.
Kotlin version, define a function to handle request, the use RouteFunctionDSL
to map incoming request to HandlerFuncation:
fun get(req: ServerRequest): Mono<ServerResponse> {
return this.posts.findById(req.pathVariable("id"))
.flatMap { post -> ok().body(Mono.just(post), Post::class.java) }
.switchIfEmpty(notFound().build())
}
It is can be an expression, like:
fun get(req: ServerRequest): Mono<ServerResponse> = this.posts.findById(req.pathVariable("id"))
.flatMap { post -> ok().body(Mono.just(post), Post::class.java) }
.switchIfEmpty(notFound().build())
Check the complete example codes of Kotlin DSL here.
If you prefer traditional controllers to expose REST APIs, try this approach.
Firstly define an exception, eg. PostNotFoundException
. Then throw it in controller.
@GetMapping(value = "/{id}")
public Mono<Post> get(@PathVariable(value = "id") Long id) {
return this.posts.findById(id).switchIfEmpty(Mono.error(new PostNotFoundException(id)));
}
Define an ExceptionHandler
to handle the exception, and register it in HttpHandler
.
@Profile("default")
@Bean
public NettyContext nettyContext(ApplicationContext context) {
HttpHandler handler = WebHttpHandlerBuilder.applicationContext(context)
.exceptionHandler(exceptionHandler())
.build();
ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(handler);
HttpServer httpServer = HttpServer.create("localhost", this.port);
return httpServer.newHandler(adapter).block();
}
@Bean
public WebExceptionHandler exceptionHandler() {
return (ServerWebExchange exchange, Throwable ex) -> {
if (ex instanceof PostNotFoundException) {
exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);
return exchange.getResponse().setComplete();
}
return Mono.error(ex);
};
}
Check the complete codes here. For Spring Boot users, check this sample.
Update:In the latest spring 5.2, I found the general @RestControllerAdvice
works for controllers in webflux applications.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With