-
Notifications
You must be signed in to change notification settings - Fork 47
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Exception Handling Section #137
base: staging
Are you sure you want to change the base?
Changes from 6 commits
7ccde39
17cb996
2cea4f1
4ef5b9c
f1ba9ff
f50926b
dfe2460
d3c23b4
774dcc9
8142f90
6eb52be
2875ad2
9c46dc4
281bdae
a0bf96d
5d55c19
a0b98f1
4f64414
91d1901
f6ad019
8703afb
64c991f
f622c39
bd43aa4
ed6c2ae
2cf7c12
ab34acb
1eeb4fc
a1e13a1
e79e851
594b666
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -203,6 +203,68 @@ include::{common-includes}/devmode-build.adoc[] | |||||
Check out the service that you created at the | ||||||
http://localhost:9080/LibertyProject/System/properties[^] URL. | ||||||
|
||||||
// ================================================================================================= | ||||||
// Exception Handling | ||||||
// ================================================================================================= | ||||||
|
||||||
== Exception Handling | ||||||
|
||||||
If a resource doesn't exist or the service experiences an exception, the client will receive either an empty response or an HTML error page respectively. | ||||||
A client should not receive either of these. | ||||||
Clients should receive JSON responses. | ||||||
|
||||||
This will be handled using an `ExceptionMapper` which maps exceptions to responses and builds appropriate JSON payloads. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
[role="code_command hotspot", subs="quotes"] | ||||||
---- | ||||||
#Create the `ErrorResponse` class.# | ||||||
`src/main/java/io/openliberty/guides/rest/exceptions/ErrorResponse.java` | ||||||
---- | ||||||
|
||||||
ErrorResponse.java | ||||||
[source, Java, linenums, role="code_column hide_tags=comment"] | ||||||
---- | ||||||
include::finish/src/main/java/io/openliberty/guides/rest/exceptions/ErrorResponse.java[] | ||||||
---- | ||||||
|
||||||
The [hotspot file=0]`ErrorResponse` class will define the JSON contents of our response. | ||||||
It contains fields for the error code and error message. | ||||||
|
||||||
[role="code_command hotspot", subs="quotes"] | ||||||
---- | ||||||
#Create the `GenericExceptionMapper` class.# | ||||||
`src/main/java/io/openliberty/guides/rest/exceptions/GenericExceptionMapper.java` | ||||||
---- | ||||||
|
||||||
GenericExceptionMapper.java | ||||||
[source, Java, linenums, role="code_column hide_tags=comment"] | ||||||
---- | ||||||
include::finish/src/main/java/io/openliberty/guides/rest/exceptions/GenericExceptionMapper.java[] | ||||||
---- | ||||||
|
||||||
When JAX-RS sees any `Throwable`, it will search for a matching `ExceptionMapper` interface that has been marked with the [hotspot=provider file=1]`@Provider` annotation. | ||||||
It will pass the `Throwable` to the [hotpost=toResponse file=1]`toResponse()` method to construct a response using the `ErrorResponse` class. | ||||||
|
||||||
The [hotspot file=1]`GenericExceptionMapper` class will be used for any `Throwable` that does not have a more specific `ExceptionMapper` interface implemented. | ||||||
|
||||||
[role="code_command hotspot", subs="quotes"] | ||||||
---- | ||||||
#Create the `NotFoundExceptionMapper` class.# | ||||||
`src/main/java/io/openliberty/guides/rest/exceptions/NotFoundExceptionMapper.java` | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
---- | ||||||
|
||||||
NotFoundExceptionMapper.java | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We discussed in slack that it might be better to use a different exception type here - ideally an application-specific, business exception (like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
[source, Java, linenums, role="code_column hide_tags=comment"] | ||||||
---- | ||||||
include::finish/src/main/java/io/openliberty/guides/rest/exceptions/NotFoundExceptionMapper.java[] | ||||||
---- | ||||||
|
||||||
The [hotspot file=2]`NotFoundExceptionMapper` class is a more specific implementation of the `ExceptionMapper` interface. | ||||||
The type of the generic inside is now [hotspot=generic file=2]`NotFoundException` instead of `Throwable`. | ||||||
It will only map to instances of `NotFoundException` that the application throws. | ||||||
|
||||||
See this error by visiting a URL for a resource that doesn't exist such as http://localhost:9080/LibertyProject/System/DoesNotExist[^]. | ||||||
|
||||||
// ================================================================================================= | ||||||
// Testing the service | ||||||
// ================================================================================================= | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package io.openliberty.guides.rest.exceptions; | ||
|
||
public class ErrorResponse { | ||
int errorCode; | ||
String errorMessage; | ||
|
||
public ErrorResponse(int errorCode, String errorMessage) { | ||
super(); | ||
this.errorCode = errorCode; | ||
this.errorMessage = errorMessage; | ||
} | ||
|
||
public int getErrorCode() { | ||
return this.errorCode; | ||
} | ||
|
||
public String getErrorMessage() { | ||
return this.errorMessage; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package io.openliberty.guides.rest.exceptions; | ||
|
||
import javax.ws.rs.core.MediaType; | ||
import javax.ws.rs.core.Response; | ||
import javax.ws.rs.ext.ExceptionMapper; | ||
import javax.ws.rs.ext.Provider; | ||
|
||
// tag::provider[] | ||
@Provider | ||
// end::provider[] | ||
public class GenericExceptionMapper implements ExceptionMapper<Throwable> { | ||
|
||
// tag::toResponse[] | ||
@Override | ||
public Response toResponse(Throwable t) { | ||
ErrorResponse response = new ErrorResponse(500, t.getMessage()); | ||
return Response.serverError() | ||
.entity(response) | ||
.type(MediaType.APPLICATION_JSON) | ||
.build(); | ||
} | ||
//end::toResponse[] | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package io.openliberty.guides.rest.exceptions; | ||
|
||
import javax.ws.rs.NotFoundException; | ||
import javax.ws.rs.core.MediaType; | ||
import javax.ws.rs.core.Response; | ||
import javax.ws.rs.ext.ExceptionMapper; | ||
import javax.ws.rs.ext.Provider; | ||
|
||
@Provider | ||
// tag::generic[] | ||
public class NotFoundExceptionMapper implements ExceptionMapper<NotFoundException> { | ||
// end::generic[] | ||
|
||
@Override | ||
public Response toResponse(NotFoundException ex) { | ||
ErrorResponse response = new ErrorResponse(404, ex.getMessage()); | ||
return Response.status(Response.Status.NOT_FOUND) | ||
.entity(response) | ||
.type(MediaType.APPLICATION_JSON) | ||
.build(); | ||
} | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would rephrase this section. I'm not sure that the client will always receive an empty response or an HTML error page. And ideally, the client would receive the error response in the same MediaType (MIME type) that they would receive a normal response in (i.e. it could be text, xml, etc.).
Maybe something like this:
Most application developers will want to ensure that when an exception occurs in the application (such as the client requesting a resource that does not exist or posting an invalid resource, etc.) that it is handled consistently and in a way that allows the client to fully understand the failure (i.e. bad input, server outage, etc.). This can be accomplished using the exception handling mechanisms in JAX-RS such as sending a
Response
via aWebApplicationException
(or subclass) or by usingExceptionMapper
providers.