Introduction : pourquoi Kotlin est le langage idéal pour les microservices
Le développement backend moderne s'éloigne de plus en plus des solutions monolithiques au profit d'une architecture microservices. Kotlin, en tant que langage statiquement typé fonctionnant sur la JVM, offre aux développeurs une combinaison unique de concision, de sécurité et de performance. Contrairement à Java, Kotlin permet d'écrire un code plus expressif et plus sûr sans code passe-partout, ce qui est crucial lors de la construction de systèmes distribués complexes.
Dans cet article, nous aborderons le cycle complet de création d'un microservice en Kotlin : du choix du framework au déploiement dans un conteneur. Vous apprendrez à utiliser Ktor pour le serveur HTTP, Koin pour l'injection de dépendances et Exposed pour travailler avec la base de données. Tous les exemples de code sont prêts à être utilisés dans des projets réels.
1. Conception de l'architecture du microservice
La première étape consiste à définir les limites du service. Contrairement au monolithe, chaque microservice est responsable d'une capacité métier. Prenons l'exemple d'un service de gestion des utilisateurs (User Service).
Structure du projet
Structure recommandée pour un microservice Kotlin :
user-service/├── src/│ ├── main/kotlin/com/example/userservice/│ │ ├── application/ # Couche application (cas d'utilisation)│ │ ├── domain/ # Modèles de domaine│ │ ├── infrastructure/ # Référentiels, BDD, API externes│ │ └── presentation/ # Contrôleurs (routes Ktor)│ └── resources/│ └── application.conf└── build.gradle.ktsCette architecture suit les principes de la Clean Architecture et du Domain-Driven Design, ce qui facilite les tests et la maintenance.
Choix de la pile technologique
- Framework HTTP : Ktor (léger, asynchrone, coroutines)
- DI : Koin (simple, sans réflexion)
- ORM : Exposed (DSL natif Kotlin pour SQL)
- Base de données : PostgreSQL
- Conteneurisation : Docker + Docker Compose
2. Implémentation du microservice en Kotlin avec Ktor et Koin
Configuration de build.gradle.kts
Ajout des dépendances nécessaires :
plugins { kotlin("jvm") version "1.9.22" id("io.ktor.plugin") version "2.3.7" kotlin("plugin.serialization") version "1.9.22"}
dependencies { implementation("io.ktor:ktor-server-core:2.3.7") implementation("io.ktor:ktor-server-netty:2.3.7") implementation("io.ktor:ktor-server-content-negotiation:2.3.7") implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.7") implementation("org.jetbrains.exposed:exposed-core:0.44.1") implementation("org.jetbrains.exposed:exposed-dao:0.44.1") implementation("org.jetbrains.exposed:exposed-jdbc:0.44.1") implementation("org.postgresql:postgresql:42.6.0") implementation("io.insert-koin:koin-ktor:3.5.0")}Création du modèle de domaine et du référentiel
// domain/User.ktdata class User( val id: Long, val name: String, val email: String)
// infrastructure/UserRepository.ktinterface UserRepository { suspend fun getAll(): List<User> suspend fun getById(id: Long): User? suspend fun create(user: User): User}Implémentation du référentiel avec Exposed
// infrastructure/UserRepositoryImpl.ktimport org.jetbrains.exposed.sql.*import org.jetbrains.exposed.sql.transactions.transaction
object UsersTable : Table("users") { val id = long("id").autoIncrement() val name = varchar("name", 255) val email = varchar("email", 255) override val primaryKey = PrimaryKey(id)}
class UserRepositoryImpl(private val database: Database) : UserRepository { override suspend fun getAll(): List<User> =