Skip to content

Latest commit

 

History

History
219 lines (176 loc) · 5.41 KB

File metadata and controls

219 lines (176 loc) · 5.41 KB

Error Handler

Jooby catches application exception using the javadoc:ErrorHandler[] class. The javadoc:DefaultErrorHandler[] error handler produces simple HTML page or JSON based on the value of the ACCEPT header and log the exception.

HTML:
Not Found
message: Page not found
status code: 404
JSON:
{
  "message": "Page not found",
  "status": 404,
  "reason": "Not Found"
}
Log:
GET /xx 404 Not Found
io.jooby.StatusCodeException: Not found
	at ...
	at ...
	at ...
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)

The javadoc:exception.StatusCodeException[] works as generic exception that let you specify an status code.

throw new StatusCodeException(StatusCode.FORBIDDEN);

throw new StatusCodeException(StatusCode.NOT_FOUND);

...

These exception types have a default status code:

  • IllegalArgumentException: BAD_REQUEST(400) (or sub-classes of it)

  • NoSuchElementException: BAD_REQUEST(400) (or sub-classes of it)

  • FileNotFound: NOT_FOUND(404) (or sub-classes of it)

  • Exception: SERVER_ERROR(500) (or sub-classes of it)

To set a custom status code, an entry should be added it to the error code map:

{
  errorCode(MyException.class, StatusCode.XXX);
}

Custom Error Handler

You can provide your own error handler using the javadoc:Router[error, io.jooby.ErrorHandler] method:

Error Handler
{
  error((ctx, cause, statusCode) -> {                                      (1)
    Router router = ctx.getRouter();
    router.getLog().error("found `{}` error", statusCode.value(), cause);  (2)
    ctx.setResponseCode(statusCode);
    ctx.send("found `" + statusCode.value() + "` error");                  (3)
  });
}
Kotlin
{
  error { ctx, cause, statusCode ->                                        (1)
    val router = ctx.router
    router.log.error("found `{}` error", statusCode.value(), cause)        (2)
    ctx.responseCode = statusCode
    ctx.send("found `${statusCode.value()}` error")                        (3)
  }
}
  1. Add a global/catch-all exception handler

  2. Log the error to logging system

  3. Send an error response to the client

You can use the javadoc:Context[render, java.lang.Object] object which looks for a registered javadoc:MessageEncoder[] or javadoc:TemplateEngine[].

The next example produces a HTML or JSON response based on the value of the Accept header.

Error with content negotiation
import static io.jooby.MediaType.json;
import static io.jooby.MediaType.html;

{
  install(new MyTemplateEngineModule());                      (1)

  install(new MyJsonModule());                                (2)

  error((ctx, cause, statusCode) -> {
    Router router = ctx.getRouter();
    router.getLog().error("found `{}` error", statusCode.value(), cause);

    if (ctx.accept(json)) {                                   (3)
      Map error = ...;
      ctx.render(error);                                      (4)
    } else {
      // fallback to html
      Map error = ...;
      ctx.render(new ModelAndView("error.template", error));  (5)
    }
  });
}
Kotlin
import io.jooby.MediaType.json
import io.jooby.MediaType.html

{
  install(MyTemplateEngineModule())                           (1)

  install(MyJsonModule())                                     (2)

  error {ctx, cause, statusCode ->
    val router = ctx.router
    router.log.error("found `{}` error", statusCode.value(), cause)

    if (ctx.accept(json)) {                                   (3)
      val error = mapOf(...)
      ctx.render(error)                                       (4)
    } else {
        // fallback to html
        val error = mapOf(...)
        ctx.render(ModelAndView("error.template", error))     (5)
    }
  }
}
  1. Install one of the available template engines

  2. Install one of the available json modules

  3. Test if the accept header matches the application/json content type

  4. Render json if matches

  5. Render html as fallback

Catch by Code

In addition to the generic/global error handler you can catch specific status code:

Status Code Error Handler
import static io.jooby.StatusCode.NOT_FOUND;
{
  error(NOT_FOUND, (ctx, cause, statusCode) -> {
    ctx.send(statusCode);   (1)
  });
}
Kotlin
import io.jooby.StatusCode.NOT_FOUND
{
  error (NOT_FOUND) { ctx, cause, statusCode ->
    ctx.send(statusCode)    (1)
  }
}
  1. Send 404 response to the client

Here we kind of silence all the 404 response due we don’t log anything and send an empty response.

Tip

The javadoc:Context[send, io.jooby.StatusCode] method send an empty response to the client

Catch by Exception

In addition to the generic/global error handler you can catch specific exception type:

Exception Handler
{
  error(MyException.class, (ctx, cause, statusCode) -> {
    // log and process MyException
  });
}
Kotlin
{
  error (MyException::class) { ctx, cause, statusCode ->
    // log and process MyException
  }
}