Ktor — Backend made simple

Akshay Shah
3 min readJan 16, 2021

Your first API in less than 20 minutes

This would be a 2 part series. First, we would set up a Ktor server in less than 20 minutes, and then we would deep dive into how Ktor really works, what is going on under the hood.

Part 2 : Ktor — Deep Dive

What is Ktor ?

From the official docs here , Ktor is a framework to easily build connected applications — web applications, HTTP services, mobile and browser applications. Modern connected applications need to be asynchronous to provide the best experience to users, and Kotlin coroutines provide awesome facilities to do it in an easy and straightforward way.

Let's dive into the code !!

Project Setup

Ktor has a few ways of setting up a preconfigured Gradle project: start.ktor.io and the Ktor IntelliJ IDEA plugin. Or you can clone it from here

You would find a resources folder already available to you which has a file called application.conf which configures the entry point for our application. It should look something like this

ktor {
deployment {
port = 8080
port = ${?PORT}
}
application {
modules = [ com.akshay.sampleKtor.ApplicationKt.module ]
}
}

This corresponds to the Application.module() function in Application.kt, which currently doesn't do anything and looks like this.

fun main(args: Array<String>): Unit = io.ktor.server.netty.EngineMain.main(args)fun Application.module() {}

Defining models

Create a folder under src->main called models and add a file called Movies.kt and add the following code to it.

import kotlinx.serialization.Serializable@Serializable
data class Movie(val id: String, val movieName: String, val movieGenre: String, val releaseDate: String)

To not complicate the code, for this tutorial we’ll be using in-memory storage (i.e. a mutable list of. Movies) – in a real application, we would be storing this information in a database so that it doesn't get lost after restarting our application. We can simply add this line to the top level of the Movie.kt file:

val movieStorage = mutableListOf<Movie>(
Movie(id = "101",movieName = "Dark",movieGenre = "thriller",releaseDate = "2017"),
Movie(id = "102",movieName = "Inception",movieGenre = "sci-fi",releaseDate = "2015")
)

Defining routes

We want to respond to GET, POST, and DELETE requests on the /movie endpoint. As such, let's define our routes with the corresponding HTTP methods.Create a folder routes under src->main and add a file MovieRoutes.kt which will contain the following code.

import io.ktor.application.*
import io.ktor.http.*
import io.ktor.request.*
import io.ktor.response.*
import io.ktor.routing.*
import models.Movie
import models.movieStorage

/**
* Routing for movies
*/
fun Route.movieRouting() {
/**
* this is an all in one route for movies
*/
route("/movie") {
/**
* this would get all movies in our temporary database
*/
get {
if (movieStorage.isNotEmpty()) {
call.respond(movieStorage)
} else {
call.respondText("No movies found", status = HttpStatusCode.NotFound)
}
}
/**
* this would get movies with provided id
*/
get("{id}") {
val id = call.parameters["id"] ?: return@get call.respondText(
"Missing or malformed id",
status = HttpStatusCode.BadRequest
)
val movie =
movieStorage.find { it.id == id } ?: return@get call.respondText(
"No movie with id $id",
status = HttpStatusCode.NotFound
)
call.respond(movie)
}
/**
* this would add a movie to our temporary database
*/
post {
val movie = call.receive<Movie>()
movieStorage.add(movie)
call.respondText("Movie stored correctly", status = HttpStatusCode.Accepted)
}
/**
* this would delete a movie from our temporary database
*/
delete("{id}") {
val id = call.parameters["id"] ?: return@delete call.respond(HttpStatusCode.BadRequest)
if (movieStorage.removeIf { it.id == id }) {
call.respondText("Movie removed correctly", status = HttpStatusCode.Accepted)
} else {
call.respondText("Not Found", status = HttpStatusCode.NotFound)
}
}
}
}

/**
* registering a movie route
*/
fun Application.registerMovieRoutes() {
routing {
movieRouting()
}
}

In order for this to work, we need to enable content negotiation in Ktor. Add the below line to your Application.kt file. When a client makes a request, content negotiation allows the server to examine the Accept header, see if it can serve this specific type of content, and if so, return the result.

fun Application.module() {
install(ContentNegotiation) {
json()
}
}

And finally, we would like all this to come in place by registering our movie route in our Application.module

fun Application.module() {
install(ContentNegotiation) {
json()
}
registerMovieRoutes()
}

Run application from the menu. Hoila !! our API server is up and running.
Test your API with Postman collection uploaded here. If you face any difficulties while running this app check out my GitHub repo

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Akshay Shah
Akshay Shah

Written by Akshay Shah

Lead Software Engineer @ EPAM Systems |Android | Kotlin | KMM

No responses yet

Write a response