How to return 404 with Spring WebFlux
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)
spring spring-boot project-reactor spring-webflux
add a comment |
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)
spring spring-boot project-reactor spring-webflux
add a comment |
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)
spring spring-boot project-reactor spring-webflux
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)
spring spring-boot project-reactor spring-webflux
spring spring-boot project-reactor spring-webflux
asked Aug 18 '17 at 8:31
Juergen ZimmermannJuergen Zimmermann
5411230
5411230
add a comment |
add a comment |
3 Answers
3
active
oldest
votes
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.
add a comment |
Instead of throwing an exception the method's implementation can be changed to
fun findById(@PathVariable id: String,
@RequestHeader(value = IF_NONE_MATCH) versionHeader: String?): Mono<ResponseEntity<KundeResource>> =
return service.findById(id)
.map {
// ETag stuff ...
ok().eTag("...").body(...)
}
.defaultIfEmpty(notFound().build())
add a comment |
You can use ResponseStatusException, just extend your exception:
public class YourLogicException extends ResponseStatusException {
public YourLogicException(String message) {
super(HttpStatus.BAD_REQUEST, message);
}
public YourLogicException(String message, Throwable cause) {
super(HttpStatus.BAD_REQUEST, message, cause);
}
And in service:
public Mono<String> doLogic(Mono<YourContext> ctx) {
return ctx.map(ctx -> doSomething(ctx));
}
private String doSomething(YourContext ctx) {
try {
// some logic
} catch (Exception e) {
throw new YourLogicException("Exception message", e);
}
}
And after that, you could have a pretty message:
{ "timestamp": 00000000, "path": "/endpoint", "status": 400, "error": "Bad Request", "message": "Exception message" }
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f45752104%2fhow-to-return-404-with-spring-webflux%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
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.
add a comment |
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.
add a comment |
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.
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.
edited May 17 '18 at 10:17
answered Aug 19 '17 at 8:13
HantsyHantsy
9531830
9531830
add a comment |
add a comment |
Instead of throwing an exception the method's implementation can be changed to
fun findById(@PathVariable id: String,
@RequestHeader(value = IF_NONE_MATCH) versionHeader: String?): Mono<ResponseEntity<KundeResource>> =
return service.findById(id)
.map {
// ETag stuff ...
ok().eTag("...").body(...)
}
.defaultIfEmpty(notFound().build())
add a comment |
Instead of throwing an exception the method's implementation can be changed to
fun findById(@PathVariable id: String,
@RequestHeader(value = IF_NONE_MATCH) versionHeader: String?): Mono<ResponseEntity<KundeResource>> =
return service.findById(id)
.map {
// ETag stuff ...
ok().eTag("...").body(...)
}
.defaultIfEmpty(notFound().build())
add a comment |
Instead of throwing an exception the method's implementation can be changed to
fun findById(@PathVariable id: String,
@RequestHeader(value = IF_NONE_MATCH) versionHeader: String?): Mono<ResponseEntity<KundeResource>> =
return service.findById(id)
.map {
// ETag stuff ...
ok().eTag("...").body(...)
}
.defaultIfEmpty(notFound().build())
Instead of throwing an exception the method's implementation can be changed to
fun findById(@PathVariable id: String,
@RequestHeader(value = IF_NONE_MATCH) versionHeader: String?): Mono<ResponseEntity<KundeResource>> =
return service.findById(id)
.map {
// ETag stuff ...
ok().eTag("...").body(...)
}
.defaultIfEmpty(notFound().build())
answered Aug 18 '17 at 14:39
Juergen ZimmermannJuergen Zimmermann
5411230
5411230
add a comment |
add a comment |
You can use ResponseStatusException, just extend your exception:
public class YourLogicException extends ResponseStatusException {
public YourLogicException(String message) {
super(HttpStatus.BAD_REQUEST, message);
}
public YourLogicException(String message, Throwable cause) {
super(HttpStatus.BAD_REQUEST, message, cause);
}
And in service:
public Mono<String> doLogic(Mono<YourContext> ctx) {
return ctx.map(ctx -> doSomething(ctx));
}
private String doSomething(YourContext ctx) {
try {
// some logic
} catch (Exception e) {
throw new YourLogicException("Exception message", e);
}
}
And after that, you could have a pretty message:
{ "timestamp": 00000000, "path": "/endpoint", "status": 400, "error": "Bad Request", "message": "Exception message" }
add a comment |
You can use ResponseStatusException, just extend your exception:
public class YourLogicException extends ResponseStatusException {
public YourLogicException(String message) {
super(HttpStatus.BAD_REQUEST, message);
}
public YourLogicException(String message, Throwable cause) {
super(HttpStatus.BAD_REQUEST, message, cause);
}
And in service:
public Mono<String> doLogic(Mono<YourContext> ctx) {
return ctx.map(ctx -> doSomething(ctx));
}
private String doSomething(YourContext ctx) {
try {
// some logic
} catch (Exception e) {
throw new YourLogicException("Exception message", e);
}
}
And after that, you could have a pretty message:
{ "timestamp": 00000000, "path": "/endpoint", "status": 400, "error": "Bad Request", "message": "Exception message" }
add a comment |
You can use ResponseStatusException, just extend your exception:
public class YourLogicException extends ResponseStatusException {
public YourLogicException(String message) {
super(HttpStatus.BAD_REQUEST, message);
}
public YourLogicException(String message, Throwable cause) {
super(HttpStatus.BAD_REQUEST, message, cause);
}
And in service:
public Mono<String> doLogic(Mono<YourContext> ctx) {
return ctx.map(ctx -> doSomething(ctx));
}
private String doSomething(YourContext ctx) {
try {
// some logic
} catch (Exception e) {
throw new YourLogicException("Exception message", e);
}
}
And after that, you could have a pretty message:
{ "timestamp": 00000000, "path": "/endpoint", "status": 400, "error": "Bad Request", "message": "Exception message" }
You can use ResponseStatusException, just extend your exception:
public class YourLogicException extends ResponseStatusException {
public YourLogicException(String message) {
super(HttpStatus.BAD_REQUEST, message);
}
public YourLogicException(String message, Throwable cause) {
super(HttpStatus.BAD_REQUEST, message, cause);
}
And in service:
public Mono<String> doLogic(Mono<YourContext> ctx) {
return ctx.map(ctx -> doSomething(ctx));
}
private String doSomething(YourContext ctx) {
try {
// some logic
} catch (Exception e) {
throw new YourLogicException("Exception message", e);
}
}
And after that, you could have a pretty message:
{ "timestamp": 00000000, "path": "/endpoint", "status": 400, "error": "Bad Request", "message": "Exception message" }
edited Nov 27 '18 at 8:39
answered Nov 19 '18 at 11:21
mchernyakovmchernyakov
3616
3616
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f45752104%2fhow-to-return-404-with-spring-webflux%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown