Ktor REST Apis — Part 2 (Create Routes)

Saurabh Pant
ProAndroidDev
Published in
3 min readOct 31, 2021

--

Image by istockphoto.com

If you haven’t set the Ktor project yet and need help, checkout

This tutorial is the second part of the series. It’ll be focussed on developing the simple static REST APIs for our dog project.

Here are the following APIs that we’ll be building

POST : Add a dog : http://127.0.0.1:8080/dogs

GET : Get all dogs : http://127.0.0.1:8080/dogs

GET : Get dog by id: http://127.0.0.1:8080/dogs/{id}

DELETE : Delete dog by id: http://127.0.0.1:8080/dogs/{id}

As we know, we need to define Routes for our application and we define them inside our modules. So let’s create a new class named as DogsRoute.kt.

Because our apis are static which means we’ll be saving our dogs into a list inside our application. So let’s create a list of dogs.

val dogs = mutableListOf<Dog>()

For our demo purposes, this will serve as a storage.

Now let’s create a Dog class as

@Serializable
data class Dog(val name: String, val color: String = "Unknown", val id: Int = 0)

As you can see we marked the class as Serializable which makes it eligible for being serialized during transactions.

Alright, it’s time to add our Routes inside our DogsRoute.kt:

POST — Add Dog

fun Route.addDogRoute() {
post {
val dog = call.receive<Dog>()
dogs.add(dog)
call.respond(HttpStatusCode.Created, "Dog saved")
}
}

It is an extension function operated on Route object. Under the Route, we create a post request by keyword post. As this is a post request, there will be a body that we’ll receive. So we can extract the body by call.receive<Dog>().

Then we save our dog in the list and responds with a http code and a message with call.respond function.

GET — Dog by id

fun Route.getDogRoute() {
get("{id}") {
val id = call.parameters["id"]?.toInt()
val dog = dogs.find { it.id == id }
dog?.let {
call.respond(HttpStatusCode.Found, it)
} ?: call.respond(HttpStatusCode.NotFound, "No dog found with id $id")

}
}

Similar to our add dog route, we simply created a GET request by using the keyword get and passing the dog id as path parameter. We check if there is any dog present with the given id and respond accordingly. This also shows how can we extract path parameters in a GET request.

GET — All Dogs

fun Route.getDogsRoute() {
get {
if (dogs.isNotEmpty())
call.respond(HttpStatusCode.OK, dogs)
else
call.respond(HttpStatusCode.NotFound, "No dog found")
}
}

Similar to our GET by id route, here we checks if the list of dogs is empty or not and respond accodingly.

DELETE — Dog by id

fun Route.deleteDogRoute() {
delete("{id}") {
val id = call.parameters["id"]?.toInt() ?: return@delete call.respond(
HttpStatusCode.BadRequest,
"Dog id required"
)
if (dogs.removeIf { it.id == id })
call.respond(HttpStatusCode.Accepted, "Dog removed successfully")
else
call.respond(HttpStatusCode.NotFound, "No dog found with id $id")
}
}

In this route, we again extracts the dog id and remove it from the list and respond back to user.

Now we’ve defined all our routes, it is time to add them inside a module that we can then pass on to our application module. We can do that by adding all the routes inside the routing tag as follows

fun Application.registerDogsRoute() {
routing {
addDogRoute()
getDogRoute()
getDogsRoute()
deleteDogRoute()
}
}

Boom! Our routes are added to the dog module. One thing to note here is the we need a specific url path for all our dog specific routes i.e. all dog routes should start with /dogs and we can achieve it easily by modifying our registerDogsRoute module as

fun Application.registerDogsRoute() {
routing {
route("/dogs") {
addDogRoute()
getDogRoute()
getDogsRoute()
deleteDogRoute()
}
}
}

The only thing remains here is to add this module to our application module as follows

@Suppress("unused") // application.conf references the main function. This annotation prevents the IDE from marking it as unused.
fun Application.module() {
configureSerialization()
configureMonitoring()
registerDogsRoute()
}

Whoa! We’ve just finished developing our APIs using Ktor and ready to test them. Let’s do it in the following tutorial and see them in action.

Full code can be found on github : here under static-apis branch.

Hope this would be helpful in some way.

Cheers! 🍺

--

--

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