kotlin-ktor-patterns — ai-agents kotlin-ktor-patterns, everything-claude-code, official, ai-agents, ide skills, anthropic, claude-code, developer-tools, Claude Code, Cursor, Windsurf

Verified
v1.0.0
GitHub

About this Skill

Perfect for Kotlin-based Web Development Agents needing advanced HTTP server patterns and robust REST API implementation. Ktor server patterns including routing DSL, plugins, authentication, Koin DI, kotlinx.serialization, WebSockets, and testApplication testing.

# Core Topics

affaan-m affaan-m
[116.8k]
[15188]
Updated: 3/30/2026

Agent Capability Analysis

The kotlin-ktor-patterns skill by affaan-m is an open-source official AI agent skill for Claude Code and other IDE workflows, helping agents execute tasks with better context, repeatability, and domain-specific guidance. Optimized for ai-agents, anthropic, claude-code.

Ideal Agent Persona

Perfect for Kotlin-based Web Development Agents needing advanced HTTP server patterns and robust REST API implementation.

Core Value

Empowers agents to build scalable and maintainable Ktor servers with Kotlin coroutines, leveraging plugins like authentication, CORS, and ContentNegotiation, while utilizing dependency injection with Koin and efficient testing with testApplication.

Capabilities Granted for kotlin-ktor-patterns

Implementing RESTful APIs with Ktor routing DSL
Configuring Ktor plugins for authentication and authorization
Setting up WebSockets for real-time communication in Ktor applications
Writing comprehensive integration tests with testApplication
Optimizing Ktor server performance with kotlinx.serialization

! Prerequisites & Limits

  • Requires Kotlin programming language
  • Ktor server and plugins configuration needed
  • Dependency on Koin for dependency injection
  • Netty or other supported embedded servers required
Labs Demo

Browser Sandbox Environment

⚡️ Ready to unleash?

Experience this Agent in a zero-setup browser environment powered by WebContainers. No installation required.

Boot Container Sandbox

kotlin-ktor-patterns

Install kotlin-ktor-patterns, an AI agent skill for AI agent workflows and automation. Works with Claude Code, Cursor, and Windsurf with one-command setup.

SKILL.md
Readonly

Ktor Server Patterns

Comprehensive Ktor patterns for building robust, maintainable HTTP servers with Kotlin coroutines.

When to Activate

  • Building Ktor HTTP servers
  • Configuring Ktor plugins (Auth, CORS, ContentNegotiation, StatusPages)
  • Implementing REST APIs with Ktor
  • Setting up dependency injection with Koin
  • Writing Ktor integration tests with testApplication
  • Working with WebSockets in Ktor

Application Structure

Standard Ktor Project Layout

text
1src/main/kotlin/ 2├── com/example/ 3│ ├── Application.kt # Entry point, module configuration 4│ ├── plugins/ 5│ │ ├── Routing.kt # Route definitions 6│ │ ├── Serialization.kt # Content negotiation setup 7│ │ ├── Authentication.kt # Auth configuration 8│ │ ├── StatusPages.kt # Error handling 9│ │ └── CORS.kt # CORS configuration 10│ ├── routes/ 11│ │ ├── UserRoutes.kt # /users endpoints 12│ │ ├── AuthRoutes.kt # /auth endpoints 13│ │ └── HealthRoutes.kt # /health endpoints 14│ ├── models/ 15│ │ ├── User.kt # Domain models 16│ │ └── ApiResponse.kt # Response envelopes 17│ ├── services/ 18│ │ ├── UserService.kt # Business logic 19│ │ └── AuthService.kt # Auth logic 20│ ├── repositories/ 21│ │ ├── UserRepository.kt # Data access interface 22│ │ └── ExposedUserRepository.kt 23│ └── di/ 24│ └── AppModule.kt # Koin modules 25src/test/kotlin/ 26├── com/example/ 27│ ├── routes/ 28│ │ └── UserRoutesTest.kt 29│ └── services/ 30│ └── UserServiceTest.kt

Application Entry Point

kotlin
1// Application.kt 2fun main() { 3 embeddedServer(Netty, port = 8080, module = Application::module).start(wait = true) 4} 5 6fun Application.module() { 7 configureSerialization() 8 configureAuthentication() 9 configureStatusPages() 10 configureCORS() 11 configureDI() 12 configureRouting() 13}

Routing DSL

Basic Routes

kotlin
1// plugins/Routing.kt 2fun Application.configureRouting() { 3 routing { 4 userRoutes() 5 authRoutes() 6 healthRoutes() 7 } 8} 9 10// routes/UserRoutes.kt 11fun Route.userRoutes() { 12 val userService by inject<UserService>() 13 14 route("/users") { 15 get { 16 val users = userService.getAll() 17 call.respond(users) 18 } 19 20 get("/{id}") { 21 val id = call.parameters["id"] 22 ?: return@get call.respond(HttpStatusCode.BadRequest, "Missing id") 23 val user = userService.getById(id) 24 ?: return@get call.respond(HttpStatusCode.NotFound) 25 call.respond(user) 26 } 27 28 post { 29 val request = call.receive<CreateUserRequest>() 30 val user = userService.create(request) 31 call.respond(HttpStatusCode.Created, user) 32 } 33 34 put("/{id}") { 35 val id = call.parameters["id"] 36 ?: return@put call.respond(HttpStatusCode.BadRequest, "Missing id") 37 val request = call.receive<UpdateUserRequest>() 38 val user = userService.update(id, request) 39 ?: return@put call.respond(HttpStatusCode.NotFound) 40 call.respond(user) 41 } 42 43 delete("/{id}") { 44 val id = call.parameters["id"] 45 ?: return@delete call.respond(HttpStatusCode.BadRequest, "Missing id") 46 val deleted = userService.delete(id) 47 if (deleted) call.respond(HttpStatusCode.NoContent) 48 else call.respond(HttpStatusCode.NotFound) 49 } 50 } 51}

Route Organization with Authenticated Routes

kotlin
1fun Route.userRoutes() { 2 route("/users") { 3 // Public routes 4 get { /* list users */ } 5 get("/{id}") { /* get user */ } 6 7 // Protected routes 8 authenticate("jwt") { 9 post { /* create user - requires auth */ } 10 put("/{id}") { /* update user - requires auth */ } 11 delete("/{id}") { /* delete user - requires auth */ } 12 } 13 } 14}

Content Negotiation & Serialization

kotlinx.serialization Setup

kotlin
1// plugins/Serialization.kt 2fun Application.configureSerialization() { 3 install(ContentNegotiation) { 4 json(Json { 5 prettyPrint = true 6 isLenient = false 7 ignoreUnknownKeys = true 8 encodeDefaults = true 9 explicitNulls = false 10 }) 11 } 12}

Serializable Models

kotlin
1@Serializable 2data class UserResponse( 3 val id: String, 4 val name: String, 5 val email: String, 6 val role: Role, 7 @Serializable(with = InstantSerializer::class) 8 val createdAt: Instant, 9) 10 11@Serializable 12data class CreateUserRequest( 13 val name: String, 14 val email: String, 15 val role: Role = Role.USER, 16) 17 18@Serializable 19data class ApiResponse<T>( 20 val success: Boolean, 21 val data: T? = null, 22 val error: String? = null, 23) { 24 companion object { 25 fun <T> ok(data: T): ApiResponse<T> = ApiResponse(success = true, data = data) 26 fun <T> error(message: String): ApiResponse<T> = ApiResponse(success = false, error = message) 27 } 28} 29 30@Serializable 31data class PaginatedResponse<T>( 32 val data: List<T>, 33 val total: Long, 34 val page: Int, 35 val limit: Int, 36)

Custom Serializers

kotlin
1object InstantSerializer : KSerializer<Instant> { 2 override val descriptor = PrimitiveSerialDescriptor("Instant", PrimitiveKind.STRING) 3 override fun serialize(encoder: Encoder, value: Instant) = 4 encoder.encodeString(value.toString()) 5 override fun deserialize(decoder: Decoder): Instant = 6 Instant.parse(decoder.decodeString()) 7}

Authentication

JWT Authentication

kotlin
1// plugins/Authentication.kt 2fun Application.configureAuthentication() { 3 val jwtSecret = environment.config.property("jwt.secret").getString() 4 val jwtIssuer = environment.config.property("jwt.issuer").getString() 5 val jwtAudience = environment.config.property("jwt.audience").getString() 6 val jwtRealm = environment.config.property("jwt.realm").getString() 7 8 install(Authentication) { 9 jwt("jwt") { 10 realm = jwtRealm 11 verifier( 12 JWT.require(Algorithm.HMAC256(jwtSecret)) 13 .withAudience(jwtAudience) 14 .withIssuer(jwtIssuer) 15 .build() 16 ) 17 validate { credential -> 18 if (credential.payload.audience.contains(jwtAudience)) { 19 JWTPrincipal(credential.payload) 20 } else { 21 null 22 } 23 } 24 challenge { _, _ -> 25 call.respond(HttpStatusCode.Unauthorized, ApiResponse.error<Unit>("Invalid or expired token")) 26 } 27 } 28 } 29} 30 31// Extracting user from JWT 32fun ApplicationCall.userId(): String = 33 principal<JWTPrincipal>() 34 ?.payload 35 ?.getClaim("userId") 36 ?.asString() 37 ?: throw AuthenticationException("No userId in token")

Auth Routes

kotlin
1fun Route.authRoutes() { 2 val authService by inject<AuthService>() 3 4 route("/auth") { 5 post("/login") { 6 val request = call.receive<LoginRequest>() 7 val token = authService.login(request.email, request.password) 8 ?: return@post call.respond( 9 HttpStatusCode.Unauthorized, 10 ApiResponse.error<Unit>("Invalid credentials"), 11 ) 12 call.respond(ApiResponse.ok(TokenResponse(token))) 13 } 14 15 post("/register") { 16 val request = call.receive<RegisterRequest>() 17 val user = authService.register(request) 18 call.respond(HttpStatusCode.Created, ApiResponse.ok(user)) 19 } 20 21 authenticate("jwt") { 22 get("/me") { 23 val userId = call.userId() 24 val user = authService.getProfile(userId) 25 call.respond(ApiResponse.ok(user)) 26 } 27 } 28 } 29}

Status Pages (Error Handling)

kotlin
1// plugins/StatusPages.kt 2fun Application.configureStatusPages() { 3 install(StatusPages) { 4 exception<ContentTransformationException> { call, cause -> 5 call.respond( 6 HttpStatusCode.BadRequest, 7 ApiResponse.error<Unit>("Invalid request body: ${cause.message}"), 8 ) 9 } 10 11 exception<IllegalArgumentException> { call, cause -> 12 call.respond( 13 HttpStatusCode.BadRequest, 14 ApiResponse.error<Unit>(cause.message ?: "Bad request"), 15 ) 16 } 17 18 exception<AuthenticationException> { call, _ -> 19 call.respond( 20 HttpStatusCode.Unauthorized, 21 ApiResponse.error<Unit>("Authentication required"), 22 ) 23 } 24 25 exception<AuthorizationException> { call, _ -> 26 call.respond( 27 HttpStatusCode.Forbidden, 28 ApiResponse.error<Unit>("Access denied"), 29 ) 30 } 31 32 exception<NotFoundException> { call, cause -> 33 call.respond( 34 HttpStatusCode.NotFound, 35 ApiResponse.error<Unit>(cause.message ?: "Resource not found"), 36 ) 37 } 38 39 exception<Throwable> { call, cause -> 40 call.application.log.error("Unhandled exception", cause) 41 call.respond( 42 HttpStatusCode.InternalServerError, 43 ApiResponse.error<Unit>("Internal server error"), 44 ) 45 } 46 47 status(HttpStatusCode.NotFound) { call, status -> 48 call.respond(status, ApiResponse.error<Unit>("Route not found")) 49 } 50 } 51}

CORS Configuration

kotlin
1// plugins/CORS.kt 2fun Application.configureCORS() { 3 install(CORS) { 4 allowHost("localhost:3000") 5 allowHost("example.com", schemes = listOf("https")) 6 allowHeader(HttpHeaders.ContentType) 7 allowHeader(HttpHeaders.Authorization) 8 allowMethod(HttpMethod.Put) 9 allowMethod(HttpMethod.Delete) 10 allowMethod(HttpMethod.Patch) 11 allowCredentials = true 12 maxAgeInSeconds = 3600 13 } 14}

Koin Dependency Injection

Module Definition

kotlin
1// di/AppModule.kt 2val appModule = module { 3 // Database 4 single<Database> { DatabaseFactory.create(get()) } 5 6 // Repositories 7 single<UserRepository> { ExposedUserRepository(get()) } 8 single<OrderRepository> { ExposedOrderRepository(get()) } 9 10 // Services 11 single { UserService(get()) } 12 single { OrderService(get(), get()) } 13 single { AuthService(get(), get()) } 14} 15 16// Application setup 17fun Application.configureDI() { 18 install(Koin) { 19 modules(appModule) 20 } 21}

Using Koin in Routes

kotlin
1fun Route.userRoutes() { 2 val userService by inject<UserService>() 3 4 route("/users") { 5 get { 6 val users = userService.getAll() 7 call.respond(ApiResponse.ok(users)) 8 } 9 } 10}

Koin for Testing

kotlin
1class UserServiceTest : FunSpec(), KoinTest { 2 override fun extensions() = listOf(KoinExtension(testModule)) 3 4 private val testModule = module { 5 single<UserRepository> { mockk() } 6 single { UserService(get()) } 7 } 8 9 private val repository by inject<UserRepository>() 10 private val service by inject<UserService>() 11 12 init { 13 test("getUser returns user") { 14 coEvery { repository.findById("1") } returns testUser 15 service.getById("1") shouldBe testUser 16 } 17 } 18}

Request Validation

kotlin
1// Validate request data in routes 2fun Route.userRoutes() { 3 val userService by inject<UserService>() 4 5 post("/users") { 6 val request = call.receive<CreateUserRequest>() 7 8 // Validate 9 require(request.name.isNotBlank()) { "Name is required" } 10 require(request.name.length <= 100) { "Name must be 100 characters or less" } 11 require(request.email.matches(Regex(".+@.+\\..+"))) { "Invalid email format" } 12 13 val user = userService.create(request) 14 call.respond(HttpStatusCode.Created, ApiResponse.ok(user)) 15 } 16} 17 18// Or use a validation extension 19fun CreateUserRequest.validate() { 20 require(name.isNotBlank()) { "Name is required" } 21 require(name.length <= 100) { "Name must be 100 characters or less" } 22 require(email.matches(Regex(".+@.+\\..+"))) { "Invalid email format" } 23}

WebSockets

kotlin
1fun Application.configureWebSockets() { 2 install(WebSockets) { 3 pingPeriod = 15.seconds 4 timeout = 15.seconds 5 maxFrameSize = 64 * 1024 // 64 KiB — increase only if your protocol requires larger frames 6 masking = false // Server-to-client frames are unmasked per RFC 6455; client-to-server are always masked by Ktor 7 } 8} 9 10fun Route.chatRoutes() { 11 val connections = Collections.synchronizedSet<Connection>(LinkedHashSet()) 12 13 webSocket("/chat") { 14 val thisConnection = Connection(this) 15 connections += thisConnection 16 17 try { 18 send("Connected! Users online: ${connections.size}") 19 20 for (frame in incoming) { 21 frame as? Frame.Text ?: continue 22 val text = frame.readText() 23 val message = ChatMessage(thisConnection.name, text) 24 25 // Snapshot under lock to avoid ConcurrentModificationException 26 val snapshot = synchronized(connections) { connections.toList() } 27 snapshot.forEach { conn -> 28 conn.session.send(Json.encodeToString(message)) 29 } 30 } 31 } catch (e: Exception) { 32 logger.error("WebSocket error", e) 33 } finally { 34 connections -= thisConnection 35 } 36 } 37} 38 39data class Connection(val session: DefaultWebSocketSession) { 40 val name: String = "User-${counter.getAndIncrement()}" 41 42 companion object { 43 private val counter = AtomicInteger(0) 44 } 45}

testApplication Testing

Basic Route Testing

kotlin
1class UserRoutesTest : FunSpec({ 2 test("GET /users returns list of users") { 3 testApplication { 4 application { 5 install(Koin) { modules(testModule) } 6 configureSerialization() 7 configureRouting() 8 } 9 10 val response = client.get("/users") 11 12 response.status shouldBe HttpStatusCode.OK 13 val body = response.body<ApiResponse<List<UserResponse>>>() 14 body.success shouldBe true 15 body.data.shouldNotBeNull().shouldNotBeEmpty() 16 } 17 } 18 19 test("POST /users creates a user") { 20 testApplication { 21 application { 22 install(Koin) { modules(testModule) } 23 configureSerialization() 24 configureStatusPages() 25 configureRouting() 26 } 27 28 val client = createClient { 29 install(io.ktor.client.plugins.contentnegotiation.ContentNegotiation) { 30 json() 31 } 32 } 33 34 val response = client.post("/users") { 35 contentType(ContentType.Application.Json) 36 setBody(CreateUserRequest("Alice", "alice@example.com")) 37 } 38 39 response.status shouldBe HttpStatusCode.Created 40 } 41 } 42 43 test("GET /users/{id} returns 404 for unknown id") { 44 testApplication { 45 application { 46 install(Koin) { modules(testModule) } 47 configureSerialization() 48 configureStatusPages() 49 configureRouting() 50 } 51 52 val response = client.get("/users/unknown-id") 53 54 response.status shouldBe HttpStatusCode.NotFound 55 } 56 } 57})

Testing Authenticated Routes

kotlin
1class AuthenticatedRoutesTest : FunSpec({ 2 test("protected route requires JWT") { 3 testApplication { 4 application { 5 install(Koin) { modules(testModule) } 6 configureSerialization() 7 configureAuthentication() 8 configureRouting() 9 } 10 11 val response = client.post("/users") { 12 contentType(ContentType.Application.Json) 13 setBody(CreateUserRequest("Alice", "alice@example.com")) 14 } 15 16 response.status shouldBe HttpStatusCode.Unauthorized 17 } 18 } 19 20 test("protected route succeeds with valid JWT") { 21 testApplication { 22 application { 23 install(Koin) { modules(testModule) } 24 configureSerialization() 25 configureAuthentication() 26 configureRouting() 27 } 28 29 val token = generateTestJWT(userId = "test-user") 30 31 val client = createClient { 32 install(io.ktor.client.plugins.contentnegotiation.ContentNegotiation) { json() } 33 } 34 35 val response = client.post("/users") { 36 contentType(ContentType.Application.Json) 37 bearerAuth(token) 38 setBody(CreateUserRequest("Alice", "alice@example.com")) 39 } 40 41 response.status shouldBe HttpStatusCode.Created 42 } 43 } 44})

Configuration

application.yaml

yaml
1ktor: 2 application: 3 modules: 4 - com.example.ApplicationKt.module 5 deployment: 6 port: 8080 7 8jwt: 9 secret: ${JWT_SECRET} 10 issuer: "https://example.com" 11 audience: "https://example.com/api" 12 realm: "example" 13 14database: 15 url: ${DATABASE_URL} 16 driver: "org.postgresql.Driver" 17 maxPoolSize: 10

Reading Config

kotlin
1fun Application.configureDI() { 2 val dbUrl = environment.config.property("database.url").getString() 3 val dbDriver = environment.config.property("database.driver").getString() 4 val maxPoolSize = environment.config.property("database.maxPoolSize").getString().toInt() 5 6 install(Koin) { 7 modules(module { 8 single { DatabaseConfig(dbUrl, dbDriver, maxPoolSize) } 9 single { DatabaseFactory.create(get()) } 10 }) 11 } 12}

Quick Reference: Ktor Patterns

PatternDescription
route("/path") { get { } }Route grouping with DSL
call.receive<T>()Deserialize request body
call.respond(status, body)Send response with status
call.parameters["id"]Read path parameters
call.request.queryParameters["q"]Read query parameters
install(Plugin) { }Install and configure plugin
authenticate("name") { }Protect routes with auth
by inject<T>()Koin dependency injection
testApplication { }Integration testing

Remember: Ktor is designed around Kotlin coroutines and DSLs. Keep routes thin, push logic to services, and use Koin for dependency injection. Test with testApplication for full integration coverage.

FAQ & Installation Steps

These questions and steps mirror the structured data on this page for better search understanding.

? Frequently Asked Questions

What is kotlin-ktor-patterns?

Perfect for Kotlin-based Web Development Agents needing advanced HTTP server patterns and robust REST API implementation. Ktor server patterns including routing DSL, plugins, authentication, Koin DI, kotlinx.serialization, WebSockets, and testApplication testing.

How do I install kotlin-ktor-patterns?

Run the command: npx killer-skills add affaan-m/everything-claude-code/kotlin-ktor-patterns. It works with Cursor, Windsurf, VS Code, Claude Code, and 19+ other IDEs.

What are the use cases for kotlin-ktor-patterns?

Key use cases include: Implementing RESTful APIs with Ktor routing DSL, Configuring Ktor plugins for authentication and authorization, Setting up WebSockets for real-time communication in Ktor applications, Writing comprehensive integration tests with testApplication, Optimizing Ktor server performance with kotlinx.serialization.

Which IDEs are compatible with kotlin-ktor-patterns?

This skill is compatible with Cursor, Windsurf, VS Code, Trae, Claude Code, OpenClaw, Aider, Codex, OpenCode, Goose, Cline, Roo Code, Kiro, Augment Code, Continue, GitHub Copilot, Sourcegraph Cody, and Amazon Q Developer. Use the Killer-Skills CLI for universal one-command installation.

Are there any limitations for kotlin-ktor-patterns?

Requires Kotlin programming language. Ktor server and plugins configuration needed. Dependency on Koin for dependency injection. Netty or other supported embedded servers required.

How To Install

  1. 1. Open your terminal

    Open the terminal or command line in your project directory.

  2. 2. Run the install command

    Run: npx killer-skills add affaan-m/everything-claude-code/kotlin-ktor-patterns. The CLI will automatically detect your IDE or AI agent and configure the skill.

  3. 3. Start using the skill

    The skill is now active. Your AI agent can use kotlin-ktor-patterns immediately in the current project.

Related Skills

Looking for an alternative to kotlin-ktor-patterns or another official skill for your workflow? Explore these related open-source skills.

View All

flags

Logo of facebook
facebook

Use when you need to check feature flag states, compare channels, or debug why a feature behaves differently across release channels.

243.6k
0
Developer

extract-errors

Logo of facebook
facebook

Use when adding new error messages to React, or seeing unknown error code warnings.

243.6k
0
Developer

fix

Logo of facebook
facebook

Use when you have lint errors, formatting issues, or before committing code to ensure it passes CI.

243.6k
0
Developer

flow

Logo of facebook
facebook

Use when you need to run Flow type checking, or when seeing Flow type errors in React code.

243.6k
0
Developer