Backend Tutorial

Ktor REST Apis — Exception handling

Catch it if you can!

Saurabh Pant
Dev Genius
Published in
4 min readSep 5, 2022

--

Source: Test Automation Blog

In this Rest Api series using Ktor, we earlier explored how can we create rest apis. But exceptions are unsaid reality of any code base. It’s very important that our code is ready for any such unexpected scenarios. So in this article, we’ll be exploring how can we handle exceptions in our rest apis.

In case you want to start from the beginning, please read the following and you won’t be disappointed.

Ktor REST Apis - Part 1 (Project Set up)
Ktor REST Apis - Part 2 (Create Routes)
Ktor REST Apis - Part 3 (Testing Routes)
Ktor REST Apis - Integrating SQL Database using Ktorm

StatusPages

In Ktor, exception handling is done using StatusPages. This is a plugin which gracefully handles any failure state based on a thrown exception or a status code. It means that we can provide implementations for

  • any uncaught exception or throwable i.e exception raised from anywhere during the execution.
  • any number of specific status codes

Set up

To use this plugin we need to add its dependency as follows.

// status pages for exception handling
implementation("io.ktor:ktor-server-status-pages:$ktor_version")

Then we need to install this plugin like we do with any other plugin as follows

fun Application.configureExceptions() {
install(StatusPages)
}

Then we can call this configuration from our application’s main module and we’re ready to use the plugin.

StatusPages using Exception based handling

Once we install the plugin, right there itself, we can provide the implementation for returning content based on exceptions raised.

Now, to define the exception handling we simply create an exception block and passes a <Throwable> type. It now indicates that any throwable, if not handled, should come here and response is returned as per the definition inside this block.

We create two custom exceptions that we assume, are thrown from different apis at runtime. These are simply throwable classes as follows.

class ValidationException(override val message: String): Throwable()
class ParsingException(override val message: String): Throwable()

We override the message field so that we can pass custom messages and now the complete handling looks like as follows.

Content based on Exception raised

We simply checks what kind of unhandled exception have we received and returns a response accordingly. Here ExceptionResponse is a data class used to provide json response format.

@Serializable
data class ExceptionResponse(
val message: String,
val code: Int
)

We’ll see the apis in action later in the Action section of the article.

StatusPages using Status code based handling

Similar to exception based handling under the exception block, we can define status code based handling under status block as follows.

Content based on Status codes

In this case, the control comes to StatusPages if the api will be returning any http status which is defined under this status block. For instance, we’ve mentioned Internal Server and Bad Gateway errors. So whenever our apis will return with these codes, the execution control will come here and we’ll be able to respond with defined responses.

Alright! Enough of set up! Now it’s time to see all of the above in action.

Action

We’ll create 4 api end points, all of which will throw four different types of exception. Two of them will be uncaught exception and rest two will be based on status code.

exception/validation      // exception based
exception/parsing // exception based
exception/internal-error // status based
exception/bad-gateway // status based

For these apis, we’ll set up a route as follows.

fun Application.configureExceptionRoutes() {
routing {
route("/exception") {
exceptionRoutes()
statusRoutes()
}
}
}

exceptionRoutes will contain the exception based routes namely validation and parsing.

statusRoutes will contain the status based routes namely internal-error and bad-gateway.

API: exception/validation

We simply define an end point and throws a Validation exception.

get("/validation") {
throw ValidationException("this is a validation exception")
}

On hitting this endpoint, we get the result as follows.

{
"message": "this is a validation exception",
"code": 400
}

Whoo! On to the point. Let’s test others too.

API: exception/parsing

We simply define an end point and throws a Parsing exception.

get("/parsing") {
throw ParsingException("this is a parsing exception")
}

On hitting this endpoint, we get the result as follows.

{
"message": "this is a parsing exception",
"code": 417
}

API: exception/internal-error

We simply define an end point and returns internal server error status.

get("/internal-error") {
call.respond(
HttpStatusCode.InternalServerError
)
}

On hitting this endpoint, we get the result as follows.

{
"message": "Oops! internal server error at our end",
"code": 500
}

API: exception/bad-gateway

We simply define an end point and returns internal server error status.

get("/bad-gateway") {
call.respond(
HttpStatusCode.BadGateway
)
}

On hitting this endpoint, we get the result as follows.

{
"message": "Oops! We got a bad gateway. Fixing it. Hold on!",
"code": 502
}

Advantages

Using StatusPages provides us with some advantages which are:

  • We can provide a consistent implementation for our uncaught exception. This is also beneficial from code maintenance point of view.
  • We can provide specific implementation for specific exception while still being consistent with rest of the exceptions.
  • We can treat different status codes to provide consistent response to users.

This would be enough to get started with handling exceptions in our apis. Play around with different scenario and experience them in real. For reference you can checkout the complete code at the following. Hope it would be useful.

That is all for now! Stay tuned!

Connect with me (if the content is helpful to you ) on

Subscribe to email to be in sync for further interesting topics on Android/IOS/Backend/Web.

Until next time…

Cheers!

--

--

App Developer (Native & Flutter) | Mentor | Writer | Youtuber @_zaqua | Traveller | Content Author & Course Instructor @Droidcon | Frontend Lead @MahilaMoney