Blog ENI : Toute la veille numérique !
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
💥 Les 22 & 23 novembre : Accès 100% GRATUIT
à la Bibliothèque Numérique ENI. Je m'inscris !
  1. Livres et vidéos
  2. Kotlin
  3. Développement d’API avec Ktor
Extrait - Kotlin Développement backend d’applications web avec Ktor et Exposed
Extraits du livre
Kotlin Développement backend d’applications web avec Ktor et Exposed Revenir à la page d'achat du livre

Développement d’API avec Ktor

Introduction

1. Qu’est-ce que Ktor ?

Ktor est un framework de développement écrit entièrement en Kotlin. Il est utilisé pour développer des applications web ou clientes. Par exemple, il peut être employé tant pour le développement de la composante « backend » d’une application que pour l’établissement de la connectivité avec le serveur depuis une application mobile écrite en Kotlin.

L’objectif du framework Ktor est de fournir un cadre unique pour le développement de l’ensemble des composantes d’une application, qu’il s’agisse du côté client ou serveur.

Pour optimiser ses performances lors de l’exécution de multiples requêtes HTTP concurrentes, Ktor a recours au modèle de programmation asynchrone qui repose sur les coroutines. Ce modèle lui permet d’exécuter les opérations de manière non bloquante et de pouvoir gérer de nombreuses connexions avec un nombre réduit de threads système.

2. Comparaison avec le framework Spring

Spring est un framework de développement extrêmement populaire, écrit en Java. Il s’agit d’un framework complet, fondé sur les principes d’injection de dépendances et d’inversion de contrôle. Il est souvent employé conjointement avec le framework SpringBoot afin d’accélérer le développement d’applications web.

Il est parfaitement possible d’utiliser Spring et/ou SpringBoot en Kotlin. Comme évoqué dans les premiers chapitres, Kotlin est un langage de programmation compatible à 100 % avec Java et tous les langages compilés en ByteCode de la JVM. Toutefois, l’emploi de Spring et/ou SpringBoot en Kotlin ne permet pas de tirer pleinement parti de tous les avantages et de toute la puissance du langage.

a. Le temps de démarrage

Le framework Spring embarque un conteneur d’injection de dépendances. La plupart des bibliothèques et des fonctionnalités de ce framework reposent ainsi sur deux principes :

  • La découverte automatique des objets représentant les dépendances. Il est par exemple possible d’identifier une classe permettant la connexion à une base de données.

  • L’injection desdites dépendances au lancement de l’application dans les divers objets métier. L’instance de la classe utilisée pour accéder à la base de données pourrait être injectée dans une autre classe destinée à répondre aux requêtes REST.

Au démarrage, Spring parcourt l’ensemble des classes de l’application ainsi que celles des bibliothèques utilisées. Ensuite, Spring crée les objets de dépendances et les injecte aux différents endroits où ils sont requis.

Ce mécanisme a un impact sur le temps de démarrage de l’application. Plus la taille de l’application et des bibliothèques utilisées est grande, plus le temps de démarrage sera important.

Ktor n’utilise aucun système d’injection de dépendances. Il est de plus découpé en plusieurs modules. L’application embarque uniquement les modules nécessaires, ce qui accélère considérablement son temps de démarrage par rapport à une application similaire développée en utilisant le framework SpringBoot.

Dans le développement de microservices où le temps de démarrage revêt une importance capitale, Ktor présente un avantage significatif par rapport à Spring.

b. L’écosystème

La popularité du framework SpringBoot en fait le standard de facto pour le développement d’applications web utilisant le langage Java ou d’autres langages basés sur la JVM. Cette notoriété a fait qu’un écosystème très riche a été créé autour de ce framework. Il est facile de trouver de nombreuses bibliothèques pour répondre aux divers besoins d’une application. De plus...

Les bases de Ktor

1. Écrire une API REST

a. Définir l’API

Tout au long de ce chapitre, nous allons utiliser le framework Ktor afin de créer une application web permettant la gestion d’équipes sportives.

Pour les besoins de cette application, nous allons exposer les routes suivantes :

  • GET /teams : elle permet de récupérer la liste des équipes.

  • GET /teams/:team_id : elle permet de récupérer les informations d’une équipe grâce à son identifiant unique team_id.

  • POST /teams : elle permet de créer une nouvelle équipe.

  • PUT /teams/:team_id : elle permet de mettre à jour les données d’une équipe en utilisant son identifiant unique team_id.

  • DELETE /teams/:team_id : elle permet de supprimer une équipe en utilisant son identifiant unique team_id.

  • GET /teams/:team_id/players : elle permet de récupérer la liste des joueurs d’une équipe en utilisant son identifiant unique team_id.

  • GET /teams/:team_id/players/:player_id : elle permet de récupérer les informations sur un joueur d’une équipe grâce à son identifiant player_id et celui de son équipe team_id.

  • POST /teams/:team_id/players : elle permet d’ajouter un nouveau joueur à l’équipe identifié par le team_id.

  • PUT /teams/:team_id/players/:player_id : elle permet de mettre à jour les informations relatives à un joueur d’une équipe.

  • DELETE /teams/:team_id/players/:player_id : elle permet de supprimer le joueur dont l’identifiant est player_id de l’équipe dont l’identifiant est team_id.

Pour définir cette API dans l’application Ktor, nous devons utiliser la méthode routing de la classe io.ktor.server.application.Application.

import io.ktor.server.application.Application 
import io.ktor.server.routing.delete 
import io.ktor.server.routing.get 
import io.ktor.server.routing.post 
import io.ktor.server.routing.put 
import io.ktor.server.routing.routing 
 
fun Application.module() { 
    routing { 
        get("/teams") { 
        } 
 
        get("/teams/{team_id}") { 
        } 
 
        post("/teams") { 
        } 
 
        put("/teams/{team_id}") { 
        } 
 
        delete("/teams/{team_id}") { 
        } 
 
        get("/teams/{team_id}/players") { 
        } 
 
        post("/teams/{team_id}/players") { 
        } 
 
        put("/teams/{team_id}/players/{player_id}") { 
        } 
 
        delete("/teams/{team_id}/players/{player_id}") { 
        } 
    } 
} 

Grâce à Kotlin, la syntaxe pour définir ces routes est similaire au format d’un DSL (Domain Specific Language). Ceci facilite la lecture du code et rend intuitive la définition des routes HTTP.

Si nous lançons le code précédent, l’application renverra toujours le code HTTP 404, même pour les routes configurées. Ceci est dû au fait que nous n’avons pas encore spécifié la réponse à envoyer pour chacune des requêtes de l’API....

Sécuriser son API

1. Authentification basique

L’authentification (AuthN) est la première brique à mettre en place pour sécuriser son API. Elle permet de valider l’identité de l’utilisateur de l’API. Il est important de ne pas confondre Authn avec l’autorisation (AuthZ) qui permet de déterminer les actions qu’un utilisateur déjà authentifié pourra réaliser dans l’application.

Le moyen le plus simple pour implémenter l’authentification est de transmettre les informations d’identification (par exemple, le nom d’utilisateur et son mot de passe) à chaque requête HTTP. Cette procédure est réalisée grâce à la structure d’authentification du protocole HTTP appelée « l’authentification basique » (basic authentication). Cette authentification se base sur l’en-tête Authorization du protocole HTTP.

Pour authentifier l’utilisateur, le client HTTP génère une chaîne de caractères contenant les informations d’identification de l’utilisateur. Le format de cette chaîne doit être connu par le client et le serveur. Généralement, le format suivant est utilisé :

username:password 

L’en-tête Authorization est créé en encodant la chaîne de caractères avec l’algorithme « Base64 ». Ensuite, pour chaque requête nécessitant une authentification, la valeur encodée est placée dans l’en-tête Authorization comme suit :

Authorization : Basic dXNlcm5hbWU6cGFzc3dvcmQ= 

Une fois la requête reçue par le serveur, ce dernier décode la valeur contenant les informations d’identification en utilisant le même algorithme « Base64 ». Il procède ensuite à la validation de l’identité de l’utilisateur avant de répondre à la requête. Si les informations d’identification ne sont pas correctes, une réponse HTTP avec le statut 401 est généralement renvoyée.

Il convient de noter que Base64 n’est pas un algorithme de cryptage, mais plutôt un système de codage. Les données encodées en Base64 ne sont pas chiffrées et peuvent être facilement décodées. Par conséquent, lors de l’envoi d’informations sensibles telles que des identifiants ou des mots de passe, il est impératif d’utiliser le protocole HTTPS pour sécuriser les données transmises. HTTPS chiffre l’intégralité de la requête HTTP, y compris les en-têtes.

Pour intégrer l’authentification basique à une application Ktor, il est nécessaire d’ajouter en premier lieu le plugin Authentication et sa dépendance io.ktor:ktor-server-auth :

  • Gradle

implementation("io.ktor:ktor-server-auth:2.3.5") 
  • Maven

<dependency> 
    <groupId>io.ktor</groupId> 
    <artifactId>ktor-server-auth</artifactId> 
    <version>2.3.5</version> 
</dependency> 

Une fois la dépendance ajoutée, il est nécessaire d’installer et de configurer le plugin :

install(Authentication) { 
        basic { 
            validate { credentials -> 
            } 
        } 
    } 

La méthode validate est appelée par le plugin Ktor à chaque requête HTTP à authentifier. Son argument est une lambda prenant un paramètre de type UserPasswordCredential et renvoyant un objet nullable de type Principal. Le paramètre UserPasswordCredential contient le nom de l’utilisateur ainsi que son mot de passe, tous deux décodés. Il est important de noter que Ktor utilise, par défaut, le format username:password pour transmettre...

Ktor : documenter son API

1. Documentation OpenAPI

OpenAPI est un standard utilisé pour documenter les API d’une application. Il définit des règles et des formats de documentation indépendants des frameworks utilisés pour développer l’application. Cette norme permet de définir clairement le contrat de l’API et de développer le serveur et le client de manière indépendante. De plus, il existe des outils permettant de générer du code pour le client et le serveur à partir d’une spécification utilisant le standard OpenAPI.

Le framework Ktor ne permet pas de générer automatiquement une spécification OpenAPI depuis la définition des routes. Les développeurs sont donc contraints à respecter la recommandation qui conseille de définir la spécification OpenAPI de leurs API avant de commencer le développement de ces derniers. 

Une spécification OpenAPI peut être rédigée en format YAML ou en format JSON. Elle spécifie la version de l’API, la méthode d’authentification et les différentes routes exposées par l’API.

La première section de la documentation définit la version du standard OpenAPI et les informations générales sur l’application :

openapi: 3.0.0 
info: 
  version: 1.0.0 
  title: Teams application API 
  description: An API to manage teams and players 

L’exemple utilise la dernière version du standard disponible 3.0.0. Chaque nouvelle version du standard peut impacter le format du fichier de la documentation. L’exemple définit aussi une version 1.0.0. Cette version représente la version de l’API de l’application. Cette dernière peut être différente de la version de l’application. Généralement, cette version est incrémentée lors de l’ajout ou la suppression de routes. Il est recommandé de passer à une nouvelle version majeure lorsque des changements impactant la compatibilité avec la version antérieure sont introduits.

La deuxième section documente les informations globales sur l’API ainsi que des éléments réutilisables par les différentes routes. Parmi ces éléments figure la méthode d’authentification de l’API. L’exemple suivant illustre une spécification d’une API utilisant JWT comme méthode d’authentification :

 components: 
  securitySchemes: 
    BasicAuth: 
      type:...

Tester son API REST

L’écriture des tests est toujours une étape très importante lors du développement d’une application. Les tests assurent le bon fonctionnement de l’application dans les différents scénarios possibles. Dans le cadre du développement d’une application web, l’écriture des tests pour les API REST permet de garantir leur fiabilité et de valider leur compatibilité avec les cas d’utilisation prévus.

Le framework Ktor propose un module de test dédié qui permet de simuler les requêtes HTTP reçues par l’application sans avoir besoin pour autant de lancer un véritable serveur HTTP. Cela évite la gestion de connexions réseau et accélère l’exécution des tests. Le module de test de Ktor exécute directement le code de l’application responsable de traiter la requête HTTP à tester. Comparée aux frameworks de test de bout en bout traditionnels, qui exigent le démarrage de l’application et de son serveur web embarqué, cette approche de simulation offre un gain significatif de temps d’exécution des tests.

1. Configuration de l’environnement de test

Le module de test de Ktor facilite l’écriture de tests unitaires pour les requêtes HTTP de l’application. Afin de l’utiliser, il est nécessaire d’avoir une configuration de projet comprenant un moteur d’exécution de tests unitaires : la bibliothèque JUnit de l’écosystème Java par exemple, ou la bibliothèque Kotest présentée dans la section sur l’écriture des tests en Kotlin du chapitre Présentation du langage Kotlin de cet ouvrage.

Une fois un moteur d’exécution de test unitaire intégré à la configuration du projet, le module de test des requêtes peut être ajouté grâce à la dépendance suivante :

  • Gradle

testImplementation("io.ktor:ktor-server-test-host:2.3.5") 
  • Maven

<dependency> 
    <groupId>io.ktor</groupId> 
    <artifactId>ktor-server-test-host</artifactId> 
    <version>2.3.5</version> 
    <scope>test</scope> 
</dependency> 

Cette dépendance est bien sûr uniquement ajoutée pour le code des tests de l’application. Elle n’est pas visible par le code de production. Ceci est dû à l’utilisation de « testImplementation » en Gradle et à l’ajout du tag « scope » avec la valeur « test » en Maven.

2. Écriture du test

Pour la suite de cette section, nous allons écrire un test unitaire pour l’API REST suivante :

fun Application.teamManagementModule() { 
    val teams: MutableMap<Int, Team> = mutableMapOf() 
 
    routing { 
        post("/teams") { 
            val team = call.receive<Team>() 
            if (teams.containsKey(team.id)) { 
                call.respond(HttpStatusCode.Conflict) 
            } else { 
                teams[team.id] = team 
                call.respond(HttpStatusCode.OK, team.id) 
            } 
        } 
    } 
} 

L’API comprend une seule route HTTP de type « POST ». Cette route permet de récupérer un objet de type Team et de l’ajouter dans la « Map »...

Se connecter à une API REST avec le client HTTP

Le framework Ktor ne se limite pas au développement d’applications web. Il peut aussi être utilisé pour le développement de clients HTTP.

Afin de développer un client HTTP, Ktor utilise la même architecture basée sur les plugins pour l’émission et la gestion des requêtes HTTP sortantes. De plus, il prend en charge plusieurs implémentations de clients HTTP, également appelés moteurs (engines) HTTP. Le choix du moteur à utiliser dépend de la plate-forme cible de l’application. Parmi les moteurs supportés par défaut :

  • Apache : il se base sur la librairie Java HttpClient.

  • Java : il se base sur le client HTTP embarqué dans la JVM.

  • Jetty : il utilise la librairie Java du framework Jetty.

  • Android : il se base sur le client HTTP du SDK d’Android. Ce moteur est spécifique aux applications mobiles ciblant la plate-forme Android.

  • Darwin : il se base sur le client HTTP du SDK d’iOS. Ce moteur est spécifique aux applications mobiles ciblant la plate-forme iOS.

  • CIO : il se base sur un client HTTP entièrement écrit en Kotlin. Ce client utilise le paradigme de programmation asynchrone basé sur les coroutines de Kotlin.

  • JS : il se base sur l’API JavaScript « fetch ». Ce moteur est destiné aux applications clientes web où le code Kotlin est compilé en JavaScript.

Le choix du moteur du client HTTP n’impacte pas le code de l’application, car l’API de Ktor fournit une couche d’abstraction qui masque tous les détails spécifiques à chaque moteur pris en charge par Ktor. Ainsi, les développeurs peuvent choisir le moteur qui convient le mieux à leur environnement, sans avoir à modifier le code de leur application.

Une application web peut aussi avoir besoin d’appeler des services REST externes. Il est tout à fait possible d’utiliser Ktor à la fois pour exposer des API REST et pour se connecter aux API REST externes.

1. Installation et configuration

Pour cette section, le choix du moteur utilisé se portera sur le moteur CIO, entièrement écrit en Kotlin. Il est nécessaire d’ajouter les deux dépendances suivantes :

  • Gradle

implementation("io.ktor:ktor-client-core:2.3.5") 
implementation("io.ktor:ktor-client-cio:2.3.5") 
  • Maven

<dependency> 
    <groupId>io.ktor</groupId> 
    <artifactId>ktor-client-core</artifactId> 
    <version>2.3.5</version> 
</dependency> 
<dependency> 
    <groupId>io.ktor</groupId> 
    <artifactId>ktor-client-cio</artifactId> 
    <version>2.3.5</version> 
</dependency> 

Chaque client HTTP est représenté par une instance de la classe io.ktor.client.HttpClient. Cette instance est créée en spécifiant le moteur choisi comme suit :

import io.ktor.client.HttpClient 
import io.ktor.client.engine.cio.CIO 
 
val client = HttpClient(CIO) 

Si un seul moteur est présent dans les dépendances de l’application, il est possible de l’omettre lors de la création de l’instance :

import io.ktor.client.HttpClient 
 
val client = HttpClient() 

Dans ce cas, Ktor détecte et utilise automatiquement le moteur HTTP trouvé dans les dépendances.

2. Configuration d’un plugin

Le client HTTP de Ktor se base aussi sur le système de plugins. Il existe différents plugins...

Utilisation des WebSockets

Les WebSockets sont un protocole de communication bidirectionnelle utilisant une seule connexion TCP (Transmission Control Protocol). Ce protocole permet d’échanger des messages en temps réel entre deux applications après avoir établi une connexion réseau avec le protocole TCP. Cette réutilisation de connexion est un avantage très important par rapport au protocole classique HTTP. Ce dernier nécessite une connexion TCP par requête HTTP. De plus, la nature bidirectionnelle des WebSockets permet aux applications serveur d’envoyer des messages ou des notifications aux clients sans avoir reçu de requêtes préalables. Grâce aux WebSockets, les échanges de messages entre un client et un serveur peuvent se faire à travers le réseau de manière efficace et avec une faible latence.

Les WebSockets permettent de simplifier plusieurs types d’applications, notamment :

  • le chat en temps réel ;

  • l’envoi et l’affichage de notifications en temps réel à l’utilisateur ;

  • le suivi des changements des données en temps réel (par exemple, le prix d’un produit financier) ;

  • la collaboration en temps réel (par exemple, l’édition d’un document en ligne par plusieurs utilisateurs).

Avant l’introduction des WebSockets en 2011, ces types d’applications étaient implémentés en utilisant le protocole HTTP avec un mécanisme de polling ou d’attente active. Le client envoyait des requêtes HTTP régulièrement pour vérifier si le serveur avait des changements à communiquer (par exemple, le nouveau prix d’un produit).

Ktor propose un support complet de cette technologie grâce à un plugin dédié, facilitant ainsi l’intégration des WebSockets tant du côté des applications serveur que des clients.

1. Configurer le plugin WebSockets

Le plugin Ktor pour l’intégration des WebSockets nécessite la dépendance ktor-server-websockets :

  • Gradle

implementation("io.ktor:ktor-server-websockets:2.3.5") 
  • Maven

<dependency> 
    <groupId>io.ktor</groupId> 
    <artifactId>ktor-server-websockets</artifactId> 
    <version>2.3.5</version> 
</dependency> 

Une fois la dépendance ajoutée, le plugin peut être installé, de la même façon que les autres plugins, en utilisant la méthode install :

import io.ktor.server.websocket.WebSockets 
 
install(WebSockets) 

Optionnellement, ce plugin permet de configurer les différents paramètres du protocole WebSockets, comme par exemple :

  • pingPeriod : c’est la durée entre les « pings » vers le client. Elle permet au serveur de vérifier que le client est toujours connecté.

  • timeout : c’est la durée d’inactivité du client autorisé. Après cette durée, le serveur ferme la connexion TCP.

  • masking : cette propriété permet d’activer le mécanisme de « masquage » du protocole WebSocket. Il consiste à modifier légèrement les données envoyées grâce à une clé de masquage échangée préalablement entre le serveur et le client au moment de la création de la connexion.

Ces propriétés sont configurables en passant une lambda à la méthode d’installation :

install(WebSockets) { 
    pingPeriod = Duration.of(5, ChronoUnit.SECONDS) 
    timeout = Duration.of(1, ChronoUnit.MINUTES) 
    masking = true 
} 

La configuration précédente demande à Ktor d’envoyer des messages de « ping »...

Monitoring d’une application Ktor

Le monitoring d’une application consiste à mettre en place des outils et des métriques permettant de s’assurer du bon fonctionnement de l’application. Cela inclut la surveillance de ses performances, de sa disponibilité, et éventuellement des erreurs survenues lors du traitement des différentes requêtes.

Divers outils permettent de monitorer une application et de détecter ses potentiels dysfonctionnements. La complexité d’intégration et de l’usage de ces outils varie en fonction des métriques relevées ainsi que la précision de ces mesures.

1. Logging

Le logging consiste à générer un journal d’événements produits par l’application. Ces événements peuvent être normaux. Ils ont dans ce cas un but informatif. Ils permettent de connaître les traitements et les opérations réalisés par l’application durant son fonctionnement nominal. Les événements peuvent également être anormaux. Ils permettent alors de conserver une trace des erreurs générées par l’application. L’ensemble de ces événements est utile pour déboguer une application et pour vérifier le processus des traitements exécutés. Généralement, à chaque événement sont associés un niveau de sévérité, un message et la date où l’événement s’est produit. Toutes ces données sont ensuite regroupées dans un seul fichier de journal (log) suivant un format prédéfini.

Dans l’écosystème de la JVM, plusieurs bibliothèques et frameworks sont disponibles pour la gestion des journaux de logs. Parmi les plus connus figurent Log4j et Logback. Toutefois, il est possible de découpler une application du framework de logging en utilisant la bibliothèque SLF4J. Grâce à cette librairie, il devient facile de passer d’un framework de logging à un autre sans avoir à modifier le code de l’application. Seule la configuration sera impactée par un tel changement.

Le framework Ktor utilise SLF4J comme librairie de logging quand l’application cible la JVM. Il est important de noter que SLF4J est simplement une couche d’abstraction. Il est donc nécessaire d’ajouter comme dépendance un des frameworks de logging.

Dans cette section, nous allons utiliser le framework Logback pour générer les journaux de logs de l’application.

Il est donc nécessaire d’ajouter la dépendance suivante :

  • Gradle

runtimeOnly("ch.qos.logback:logback-classic:1.4.14") 
  • Maven

<dependency> 
    <groupId>ch.qos.logback</groupId> 
    <artifactId>logback-classic</artifactId> 
    <version>1.4.14</version> 
    <scope>runtime</scope> 
</dependency> 

La dépendance est ajoutée avec le scope runtime puisque dans le code on ne retrouvera que des appels aux méthodes de la librairie SLF4J. La compilation ne nécessite donc pas cette dépendance.

Il est ensuite nécessaire d’ajouter un fichier de configuration. Ce fichier XML définit le format des événements de log générés par l’application :

    <appender name="STDOUT" class=
"ch.qos.logback.core.ConsoleAppender"> 
        <encoder> 
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] 
%-5level %logger{36} - %msg%n</pattern> 
        </encoder> 
    </appender> 

Tous les événements de logs respecteront le format %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n.

  • %d{yyyy-MM-dd HH:mm:ss.SSS} : il représente la date de production...

Déploiement de l’application

1. Déploiement sous forme d’un Fat-JAR

Un Fat-JAR est une archive JAR contenant l’application, sa configuration ainsi que toutes ses dépendances. Ce format permet d’avoir un seul fichier à transférer et à déployer sur un serveur. Le fichier JAR est exécutable à l’aide de la commande Java suivante :

java -jar path/to/fatjar.jar 

Ce mode de déploiement est utilisé pour sa simplicité. Il est néanmoins nécessaire de s’assurer que le serveur utilise la même version de Java installée pour pouvoir démarrer l’application.

a. Génération du Fat-JAR avec Gradle

Le plugin Gradle de Ktor contient toute la configuration nécessaire pour générer ce type de JAR. Il suffit de lancer la commande Gradle suivante :

gradle buildFatJar 

Le Fat-JAR est alors généré dans le dossier build/libs. Le nom du JAR généré correspond au nom du projet auquel est ajouté le suffixe -all: nomDuProjetGradle-all.jar.

Il est possible de définir explicitement le nom du JAR généré grâce à la configuration Gradle suivante :

archivesName.set("new-fat-jar-name.jar") 

b. Génération du Fat-JAR avec Maven

La génération du Fat-JAR se fait à l’aide du plugin maven-assembly-plugin. Pour rappel, la configuration de ce plugin est la suivante :

<plugins> 
    <plugin> 
            <groupId>org.apache.maven.plugins</groupId> 
            <artifactId>maven-assembly-plugin</artifactId> 
            <version>2.6</version> 
            <configuration> 
                <descriptorRefs> 
                    <descriptorRef>jar-with-dependencies</descriptorRef> 
                </descriptorRefs> 
                <finalName>my-ktor-application</finalName> 
                <appendAssemblyId>false</appendAssemblyId> 
                <archive> 
                    <manifest> 
                        <mainClass>io.ktor.server.cio.EngineMain</mainClass> 
                    </manifest> ...

Conclusion

Ce chapitre a présenté une vue d’ensemble du framework Ktor en abordant ses principes de base et ses différents plugins permettant d’étendre les capacités du framework, ceci afin de répondre à tous les besoins classiques d’une application web moderne tels que la définition des API REST, l’authentification, la documentation, les tests et le déploiement en production. Le chapitre suivant permettra de découvrir Exposed, un deuxième framework écrit en Kotlin par JetBrains, visant à simplifier l’intégration avec les bases de données relationnelles. Il vient ainsi compléter le framework Ktor pour le développement d’applications web, tout en bénéficiant de la puissance du langage de programmation Kotlin.