Ktor: Crafting a Stock Portfolio Endpoint – Part 1

Ktor: Crafting a Stock Portfolio Endpoint – Part 1
Generated by ChatGPT

Let's build a simple server for an investment portfolio tracker using Ktor - a lightweight Kotlin framework. The server built in this series of posts only features a single endpoint. This endpoint returns a response containing the latest price and volume information for a stock ticker symbol tailored from the Alpha Vantage Quote Endpoint. If you're wondering why someone would bother wrapping an external endpoint instead of calling it directly, you may want to take a look at my other post The Advantages of Calling an External API from the Server. Part 1 only shows how to set up a Ktor project and return a type-safe response.

Setup

To set things up, you can follow Ktor's official documentation to build a simple server application that prints "Hello World!" on a browser. For ease of following along, let's choose Netty as the main engine and YAML as the configuration file format.

Setup in start.ktor.io

Now, you officially have a working server but it can only print a string instead of a tailored type-safe response. The entry point of the server lives in Application.kt with the main logic in Routing.kt which was installed as a plugin.

//...
fun main(args: Array<String>) {
    io.ktor.server.netty.EngineMain.main(args)
}

fun Application.module() {
    configureRouting()
}

Application.kt

//...
fun Application.configureRouting() {
    routing {
        get("/") {
            call.respondText("Hello World!")
        }
    }
}

Routing.kt

Type-Safe Response

Let's create a simple type-safe response in a new file and return that instead of the string "Hello World!" to see how the server responds.

data class Response(val status: String)

Response.kt

With that, you can update the logic in Routing.kt to return the new type instead.

//...
fun Application.configureRouting() {
    routing {
        get("/") {
            call.respond(Response(status = "OK"))
        }
    }
}

Routing.kt

The server throws an error Failed to load resource: the server responded with a status of 500 (). Chrome also displays a generic error message that doesn't add any value to help us determine the underlying cause.

Chrome's Generic Error Message

Luckily, Ktor has Status Pages, a useful plugin to respond appropriately to any failure state based on a thrown exception or status code. Let's start by adding the dependency in build.gradle.kts if you haven't already.

dependencies {
  //...
  implementation("io.ktor:ktor-server-status-pages:$ktor_version")
}

build.gradle.kts

Next, you can configure Status Pages similar to how the Routing plugin was configured. That means putting the main configuration logic function in a separate file StatusPages.kt which is called in Application.kt. Then, let's run the application again.

//...
fun Application.module() {
    //...
    configureStatusPages()
}

Application.kt

//...
fun Application.configureStatusPages() {
    install(StatusPages) {
        exception<Throwable> { call, error ->
            call.respondText(
                text = error.localizedMessage,
                contentType = ContentType.Text.Plain,
                status = HttpStatusCode.InternalServerError,
            )
        }
    }
}

StatusPages.kt

Error Message in Chrome

The browser is now able to catch the exception and print a useful message. Turns out that the Response type needs serializing before returning it to the browser. Following the instructions from the error message, you can install the serialization compiler plugin and mark the Response class @Serializable.

dependencies {
  //...
  implementation("io.ktor:ktor-server-content-negotiation:$ktor_version")
  implementation("io.ktor:ktor-serialization-kotlinx-json:$ktor_version")
}

build.gradle.kts

@Serializable
data class Response(val status: String)

Response.kt

//...
fun Application.module() {
    //...
    configureSerialization()
}

Application.kt

//...
fun Application.configureSerialization() {
    install(ContentNegotiation) {
        json()
    }
}

Serialization.kt

Chrome

Finally, the application can now display a type-safe response on a desired port. If you encounter any issues, you can leave a comment below for assistance. Check out Part 2 here.

Ktor: Crafting a Stock Portfolio Endpoint – Part 2
This is the second post in the series of posts that aim to build a single endpoint with Ktor by wrapping the AlphaVantage Quote Endpoint.

GitHub Repo

GitHub - trinhan-nguyen/ktor-ferreter
Contribute to trinhan-nguyen/ktor-ferreter development by creating an account on GitHub.

Reference

API Documentation | Alpha Vantage
API Documentation for Alpha Vantage. Alpha Vantage offers free JSON APIs for realtime and historical stock market data with over 50 technical indicators. Supports intraday, daily, weekly, and monthly stock quotes and technical analysis with charting-ready time series.
Welcome | Ktor