Requêtes HTTP avec Kotlin et khttp

Requêtes HTTP avec Kotlin et khttp

1. introduction

Le protocole HTTP et les API qui en découlent sont d’une importance capitale pour la programmation de nos jours.

Sur la JVM, nous avons plusieurs options disponibles, des bibliothèques de niveau inférieur aux bibliothèques de très haut niveau, des projets établis aux nouveaux enfants du bloc. Cependant, la plupart d'entre eux sont principalement destinés aux programmes Java.

Dans cet article,we’re going to look at khttp, an idiomatic Kotlin library for consuming HTTP-based resources et API.

2. Les dépendances

Pour utiliser la bibliothèque dans notre projet, nous devons d'abord l'ajouter à nos dépendances:


    khttp
    khttp
    0.1.0

Comme ceci n’est pas encore sur Maven Central, nous devons également activer le référentiel JCenter:


    central
    http://jcenter.bintray.com

La version 0.1.0 est la version actuelle au moment de la rédaction. Nous pouvons, bien sûr,check JCenter for a newer one.

3. Utilisation de base

Les bases du protocole HTTP sont simples, même si les détails peuvent être compliqués. Par conséquent, khttp a aussi une interface simple.

For every HTTP method, we can find a package-level function in the khttp package, commeget,post et ainsi de suite.

Les fonctions prennent toutes le même ensemble d'arguments et renvoient un objetResponse; nous en verrons les détails dans les sections suivantes.

Au cours de cet article, nous utiliserons le formulaire complet, par exemple,khttp.put. Bien entendu, dans nos projets, nous pouvons importer et éventuellement renommer ces méthodes:

import khttp.delete as httpDelete

Note: we’ve added type declarations for clarity throughout code examples car sans IDE, ils pourraient être difficiles à suivre.

4. Une simple demande

Every HTTP request has at least two required components: a method and a URL. Dans khttp, la méthode est déterminée par la fonction que nous appelons, comme nous l’avons vu dans la section précédente.

L'URL est le seul argument requis pour la méthode. alors, nous pouvons facilement effectuer une requête simple:

khttp.get("http://httpbin.org/get")

Dans les sections suivantes, nous considérerons que toutes les demandes sont traitées avec succès.

4.1. Ajout de paramètres

Nous devons souvent fournir des paramètres de requête en plus de l'URL de base, en particulier pour les requêtes GET.

khttp’s methods accept a params argument qui est unMap de paires clé-valeur à inclure dans la requêteString:

khttp.get(
  url = "http://httpbin.org/get",
  params = mapOf("key1" to "value1", "keyn" to "valuen"))

Notez que nous avons utilisé la fonctionmapOf pour construire unMap à la volée; l'URL de la requête résultante sera:

http://httpbin.org/get?key1=value1&keyn=valuen

5. Un corps de requête

Une autre opération courante que nous devons souvent effectuer consiste à envoyer des données, généralement en tant que charge utile d'une demande POST ou PUT.

Pour cela, la bibliothèque propose plusieurs options que nous allons examiner dans les sections suivantes.

5.1. Envoi d'une charge utile JSON

We can use the json argument to send a JSON object or array. Il peut être de plusieurs types différents:

  • UnJSONObject ouJSONArray tel que fourni par la bibliothèque org.json

  • UnMap, qui est transformé en objet JSON

  • UnCollection,Iterable ou un tableau, qui est transformé en tableau JSON

Nous pouvons facilement transformer notre précédent exemple GET en un exemple POST qui enverra un objet JSON simple:

khttp.post(
  url = "http://httpbin.org/post",
  json = mapOf("key1" to "value1", "keyn" to "valuen"))

Notez que la transformation des collections en objets JSON est superficielle. Par exemple, unList deMap ne sera pas converti en un tableau JSON d'objets JSON, mais plutôt en un tableau de chaînes.

Pour une conversion profonde, nous aurions besoin d'une bibliothèque de mappage JSON plus complexe telle que Jackson. La fonction de conversion de la bibliothèque n’est destinée qu’à des cas simples.

5.2. Envoi de données de formulaire (URL encodées)

Pour envoyer des données de formulaire (URL encodées, comme dans les formulaires HTML), nous utilisons l'argumentdata avec unMap:

khttp.post(
  url = "http://httpbin.org/post",
  data = mapOf("key1" to "value1", "keyn" to "valuen"))

5.3. Téléchargement de fichiers (formulaire en plusieurs parties)

Nous pouvons envoyer un ou plusieurs fichiers encodés en tant que demande de données de formulaire multipartie.

Dans ce cas, nous utilisons l'argumentfiles:

khttp.post(
  url = "http://httpbin.org/post",
  files = listOf(
    FileLike("file1", "content1"),
    FileLike("file2", File("kitty.jpg"))))

Nous pouvons voir que khttp utilise une abstractionFileLike, qui est un objet avec un nom et un contenu. Le contenu peut être une chaîne, un tableau d'octets, unFile ou unPath.

5.4. Envoi de contenu brut

Si aucune des options ci-dessus ne convient, nous pouvons utiliser unInputStream pour envoyer des données brutes comme corps d'une requête HTTP:

khttp.post(url = "http://httpbin.org/post", data = someInputStream)

Dans ce cas, nous devrons probablement également définir manuellement certains en-têtes, ce que nous aborderons dans une section ultérieure.

6. Traitement de la réponse

Jusqu'à présent, nous avons vu différentes manières d'envoyer des données à un serveur. Mais de nombreuses opérations HTTP sont utiles en raison des données qu'elles renvoient également.

khttp est basé sur le blocage des E / S, doncall functions corresponding to HTTP methods return a Response object contenant la réponse reçue du serveur.

Cet objet a diverses propriétés auxquelles nous pouvons accéder, en fonction du type de contenu.

6.1. Réponses JSON

Si nous savons que la réponse est un objet ou un tableau JSON, nous pouvons utiliser les propriétésjsonObject etjsonArray:

val response : Response = khttp.get("http://httpbin.org/get")
val obj : JSONObject = response.jsonObject
print(obj["someProperty"])

6.2. Réponses textuelles ou binaires

Si nous voulons plutôt lire la réponse en tant queString, nous pouvons utiliser la propriététext:

val message : String = response.text

Ou, si nous voulons le lire sous forme de données binaires (par exemple, un téléchargement de fichier) nous utilisons la propriétécontent:

val imageData : ByteArray = response.content

Enfin, nous pouvons également accéder auxInputStream sous-jacents:

val inputStream : InputStream = response.raw

7. Utilisation avancée

Jetons également un œil à quelques modèles d'utilisation plus avancés qui sont généralement utiles et que nous n'avons pas encore traités dans les sections précédentes.

7.1. Gestion des en-têtes et des cookies

All khttp functions take a headers argument qui est unMap des noms et valeurs d'en-tête.

val response = khttp.get(
  url = "http://httpbin.org/get",
  headers = mapOf("header1" to "1", "header2" to "2"))

De même pour les cookies:

val response = khttp.get(
  url = "http://httpbin.org/get",
  cookies = mapOf("cookie1" to "1", "cookie2" to "2"))

Nous pouvons également accéder aux en-têtes et aux cookies envoyés par le serveur dans la réponse:

val contentType : String = response.headers["Content-Type"]
val sessionID : String = response.cookies["JSESSIONID"]

7.2. Gestion des erreurs

Il existe deux types d’erreurs dans HTTP: les réponses aux erreurs, telles que 404 - non trouvé, qui font partie du protocole; et les erreurs de bas niveau, telles que «connexion refusée».

Le premier type n'entraîne pas la levée d'exceptions par khttp; à la place,we should check the Response statusCode property:

val response = khttp.get(url = "http://httpbin.org/nothing/to/see/here")
if(response.statusCode == 200) {
    process(response)
} else {
    handleError(response)
}

Les erreurs de niveau inférieur entraînent à la place des exceptions levées à partir du sous-système d'E / S Java sous-jacent, commeConnectException.

7.3. Réponses en streaming

Parfois, le serveur peut répondre avec un gros contenu et / ou mettre longtemps à répondre. Dans ces cas-là, nous pouvons vouloir traiter la réponse par fragments plutôt que d’attendre qu’elle se termine et utilise de la mémoire.

Si nous voulons demander à la bibliothèque de nous donner une réponse en continu, nous devons alors passertrue comme argumentstream:

val response = khttp.get(url = "http://httpbin.org", stream = true)

Ensuite, nous pouvons le traiter en morceaux:

response.contentIterator(chunkSize = 1024).forEach { arr : ByteArray -> handleChunk(arr) }

7.4. Méthodes non standard

Dans le cas peu probable où nous aurions besoin d'utiliser une méthode HTTP (ou un verbe) que khttp ne fournit pas de manière native - par exemple, pour une extension du protocole HTTP, comme WebDAV - nous sommes toujours couverts.

En fait, toutes les fonctions du package khttp, qui correspondent aux méthodes HTTP, sont implémentées à l'aide d'une fonction génériquerequest que nous pouvons également utiliser:

khttp.request(
  method = "COPY",
  url = "http://httpbin.org/get",
  headers = mapOf("Destination" to "/copy-of-get"))

7.5. Autres caractéristiques

Nous n'avons pas touché à toutes les fonctionnalités de khttp. Par exemple, nous n'avons pas discuté des délais d'expiration, des redirections et de l'historique, ni des opérations asynchrones.

The official documentation est la source ultime d'informations sur la bibliothèque et toutes ses fonctionnalités.

8. Conclusion

Dans ce tutoriel, nous avons vu comment effectuer des requêtes HTTP dans Kotlin avec la bibliothèque idiomatique khttp.

L'implémentation de tous ces exemples peut être trouvée dansthe GitHub project - c'est un projet Maven, il devrait donc être facile à importer et à exécuter tel quel.