Introduction
Kotlin est un langage de programmation moderne qui gagne rapidement en popularité dans le développement backend. Grâce à sa syntaxe concise, sa compatibilité totale avec Java et ses outils puissants comme le framework Ktor, écrire une API REST en Kotlin prend littéralement 30 minutes. Dans cet article, nous allons créer une API REST complète pour gérer une liste de tâches (Todo API). Vous apprendrez à configurer le projet, créer des endpoints, connecter une base de données et tester l'API. Pas de théorie superflue — seulement de la pratique.
Étape 1 : Configuration du projet et dépendances
Pour démarrer rapidement, utilisons IntelliJ IDEA (Community Edition) ou tout autre éditeur. Créons un nouveau projet Gradle avec Kotlin DSL.
Création de la structure du projet
Ajoutez les dépendances suivantes dans le fichier build.gradle.kts :
plugins { kotlin("jvm") version "1.9.22" application}
repositories { mavenCentral()}
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("com.h2database:h2:2.2.224") implementation("ch.qos.logback:logback-classic:1.4.14")}
application { mainClass.set("ApplicationKt")}Nous utilisons :
- Ktor — un framework asynchrone léger pour les serveurs HTTP.
- Exposed — un ORM pour travailler avec les bases de données.
- H2 — une base de données intégrée pour le développement.
- Kotlinx.serialization — pour travailler avec JSON.
Étape 2 : Création du modèle de données et connexion à la base de données
Définissons la structure de la table des tâches. Créez le fichier Database.kt :
import org.jetbrains.exposed.sql.Tableimport org.jetbrains.exposed.sql.insertimport org.jetbrains.exposed.sql.selectAllimport org.jetbrains.exposed.sql.transactions.transaction
object Tasks : Table() { val id = integer("id").autoIncrement() val title = varchar("title", 255) val completed = bool("completed").default(false)
override val primaryKey = PrimaryKey(id)}
data class Task(val id: Int, val title: String, val completed: Boolean)
fun initDatabase() { Database.connect("jdbc:h2:mem:test", driver = "org.h2.Driver") transaction { SchemaUtils.create(Tasks) }}Ce code crée une table Tasks avec trois champs : id, title et completed. La fonction initDatabase() initialise la base de données en mémoire.
Étape 3 : Écriture des contrôleurs REST API
Créons maintenant le fichier principal de l'application Application.kt. Nous y définirons tous les endpoints.
Configuration de base du serveur
import io.ktor.server.application.*import io.ktor.server.engine.*import io.ktor.server.netty.*import io.ktor.server.routing.*import io.ktor.server.response.*import io.ktor.server.request.*import io.ktor.serialization.kotlinx.json.*import io.ktor.server.plugins.contentnegotiation.*
fun main() { embeddedServer(Netty, port = 8080) { install(ContentNegotiation) { json() } initDatabase() configureRouting() }.start(wait = true)}Implémentation des endpoints CRUD
fun Application.configureRouting() { routing { // Obtenir toutes les tâches get("/tasks") { val tasks = transaction { Tasks.selectAll().map { row -> Task( id = row[Tasks.id], title = row[Tasks.title], completed = row[Tasks.completed] ) } } call.respond(tasks) }
// Obtenir une tâche par ID get("/tasks/{id}") { val id = call.parameters["id"]?.toIntOrNull() if (id == null) { call.respondText(\"ID invalide\", status = io.ktor.http.HttpStatusCode.BadRequest) return@get } val task = transaction { Tasks.selectAll().where { Tasks.id eq id }.singleOrNull() } if (task == null) { call.respondText(\"Tâche non trouvée\", status = io.ktor.http.HttpStatusCode.NotFound) } else { call.respond(Task(task[Tasks.id], task[Tasks.title], task[Tasks.completed])) } }
// Créer une nouvelle tâche post("/tasks") { val task = call.receive() val id = transaction { Tasks.insert { it[title] = task.title it[completed] = task.completed } get Tasks.id } call.respond(Task(id, task.title, task.completed), status = io.ktor.http.HttpStatusCode.Created) }
// Mettre à jour une tâche put("/tasks/{id}") { val id = call.parameters["id"]?.toIntOrNull() if (id == null) { call.respondText(\"ID invalide\", status = io.ktor.http.HttpStatusCode.BadRequest) return@put } val updatedTask = call.receive() transaction { Tasks.update({ Tasks.id eq id }) { it[title] = updatedTask.title it[completed] = updatedTask.completed } } call.respond(updatedTask) }
// Supprimer une tâche delete("/tasks/{id}") { val id = call.parameters["id"]?.toIntOrNull() if (id == null) { call.respondText(\"ID invalide\", status = io.ktor.http.HttpStatusCode.BadRequest) return@delete } transaction { Tasks.deleteWhere { Tasks.id eq id } } call.respondText(\"Tâche supprimée\", status = io.ktor.http.HttpStatusCode.OK) } }} Étape 4 : Test de l'API
Démarrez l'application et testez les endpoints à l'aide de Postman, cURL ou tout autre outil. Voici quelques exemples de requêtes :
Créer une tâche
curl -X POST http://localhost:8080/tasks \ -H \"Content-Type: application/json\" \ -d '{\"title\":\"Apprendre Kotlin\",\"completed\":false}'Obtenir toutes les tâches
curl http://localhost:8080/tasksMettre à jour une tâche
curl -X PUT http://localhost:8080/tasks/1 \ -H \"Content-Type: application/json\" \ -d '{\"title\":\"Apprendre Kotlin avancé\",\"completed\":true}'Supprimer une tâche
curl -X DELETE http://localhost:8080/tasks/1Conclusion
Félicitations ! Vous avez créé une API REST fonctionnelle en Kotlin en utilisant Ktor et Exposed. Ce projet de base peut être étendu avec l'authentification, la validation des données, la journalisation et d'autres fonctionnalités. Kotlin continue de gagner en popularité dans le développement backend, et sa maîtrise ouvre de nombreuses opportunités. Continuez à expérimenter et à construire des projets plus complexes !