Exploring Ktor for APIs
Ktor is a powerful Kotlin framework for building asynchronous servers and clients.
Basic Server Setup
Simple Server
// build.gradle.kts
plugins {
kotlin("jvm") version "1.8.0"
application
}
dependencies {
implementation("io.ktor:ktor-server-core:2.0.0")
implementation("io.ktor:ktor-server-netty:2.0.0")
}
// Application.kt
fun main() {
embeddedServer(Netty, port = 8080) {
routing {
get("/") {
call.respondText("Hello, World!")
}
}
}.start(wait = true)
}
REST API
data class User(val id: Int, val name: String)
fun main() {
embeddedServer(Netty, port = 8080) {
routing {
route("/api/users") {
get {
val users = listOf(
User(1, "John"),
User(2, "Jane")
)
call.respond(users)
}
get("/{id}") {
val id = call.parameters["id"]?.toIntOrNull()
if (id != null) {
val user = User(id, "User $id")
call.respond(user)
} else {
call.respond(HttpStatusCode.BadRequest)
}
}
post {
val user = call.receive<User>()
call.respond(HttpStatusCode.Created, user)
}
}
}
}.start(wait = true)
}
Advanced Features
Authentication
fun main() {
embeddedServer(Netty, port = 8080) {
install(Authentication) {
basic("auth-basic") {
validate { credentials ->
if (credentials.name == "admin" && credentials.password == "password") {
UserIdPrincipal(credentials.name)
} else {
null
}
}
}
}
routing {
authenticate("auth-basic") {
get("/secure") {
val principal = call.principal<UserIdPrincipal>()
call.respondText("Hello, ${principal?.name}!")
}
}
}
}.start(wait = true)
}
Content Negotiation
fun main() {
embeddedServer(Netty, port = 8080) {
install(ContentNegotiation) {
json(Json {
prettyPrint = true
isLenient = true
})
}
routing {
route("/api") {
get("/data") {
val data = mapOf(
"message" to "Hello",
"timestamp" to System.currentTimeMillis()
)
call.respond(data)
}
post("/data") {
val received = call.receive<Map<String, Any>>()
call.respond(received)
}
}
}
}.start(wait = true)
}
Best Practices
- Use proper routing
- Implement error handling
- Add logging
- Use dependency injection
- Follow REST principles
Common Patterns
Error Handling
fun main() {
embeddedServer(Netty, port = 8080) {
install(StatusPages) {
exception<Throwable> { call, cause ->
call.respondText(
"500: ${cause.message}",
status = HttpStatusCode.InternalServerError
)
}
status(HttpStatusCode.NotFound) { call, status ->
call.respondText(
"404: Not Found",
status = status
)
}
}
routing {
get("/error") {
throw RuntimeException("Something went wrong")
}
}
}.start(wait = true)
}
Database Integration
fun main() {
embeddedServer(Netty, port = 8080) {
install(ContentNegotiation) {
json()
}
routing {
route("/api/users") {
get {
val users = database.getAllUsers()
call.respond(users)
}
post {
val user = call.receive<User>()
val saved = database.saveUser(user)
call.respond(HttpStatusCode.Created, saved)
}
}
}
}.start(wait = true)
}
Performance Considerations
- Connection pooling
- Caching strategies
- Async operations
- Resource management
- Monitoring
Common Mistakes
- Not handling errors
- Missing security
- Poor routing
- No logging
- Resource leaks
Conclusion
Ktor is a powerful and flexible framework for building Kotlin applications. Use it to create efficient and maintainable APIs.