HTTP-verzoeken met Kotlin en khttp

1. Inleiding

Het HTTP-protocol en de daarop gebouwde API's zijn tegenwoordig van centraal belang bij het programmeren.

Op de JVM hebben we verschillende beschikbare opties, van bibliotheken op een lager niveau tot bibliotheken van zeer hoog niveau, van gevestigde projecten tot nieuwe kinderen in de buurt. De meeste zijn echter voornamelijk gericht op Java-programma's.

In dit artikel, we gaan kijken naar khttp, een idiomatische Kotlin-bibliotheek voor het consumeren van op HTTP gebaseerde bronnen en API's.

2. Afhankelijkheden

Om de bibliotheek in ons project te gebruiken, moeten we deze eerst aan onze afhankelijkheden toevoegen:

 khttp khttp 0.1.0 

Omdat dit nog niet op Maven Central staat, moeten we ook de JCenter-repository inschakelen:

 centraal //jcenter.bintray.com 

Versie 0.1.0 is de huidige versie op het moment van schrijven. We kunnen JCenter natuurlijk controleren op een nieuwere.

3. Basisgebruik

De basis van het HTTP-protocol is eenvoudig, ook al kunnen de fijne details behoorlijk gecompliceerd zijn. Daarom heeft khttp ook een eenvoudige interface.

Voor elke HTTP-methode kunnen we een functie op pakketniveau vinden in het khttp pakket, zoals krijgen, post enzovoorts.

De functies gebruiken allemaal dezelfde set argumenten en retourneren een Reactie voorwerp; we zullen de details hiervan in de volgende secties zien.

In de loop van dit artikel gebruiken we bijvoorbeeld het volledig gekwalificeerde formulier khttp.put. In onze projecten kunnen we deze methoden natuurlijk importeren en eventueel hernoemen:

importeer khttp.delete als httpDelete

Opmerking: we hebben typeverklaringen toegevoegd voor de duidelijkheid in codevoorbeelden want zonder een IDE kunnen ze moeilijk te volgen zijn.

4. Een eenvoudig verzoek

Elk HTTP-verzoek heeft minstens twee vereiste componenten: een methode en een URL. In khttp wordt de methode bepaald door de functie die we aanroepen, zoals we in de vorige sectie hebben gezien.

De URL is het enige vereiste argument voor de methode; dus we kunnen eenvoudig een eenvoudig verzoek uitvoeren:

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

In de volgende secties zullen we alle verzoeken bekijken om met succes te voltooien.

4.1. Parameters toevoegen

We moeten vaak naast de basis-URL queryparameters opgeven, vooral voor GET-verzoeken.

khttp's methoden accepteren een params argument wat een is Kaart van sleutel / waarde-paren die in de query moeten worden opgenomen Draad:

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

Merk op dat we de kaart van functie om een Kaart on the fly; de resulterende verzoek-URL is:

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

5. Een verzoekorgaan

Een andere veel voorkomende bewerking die we vaak moeten uitvoeren, is het verzenden van gegevens, meestal als de payload van een POST- of PUT-verzoek.

Hiervoor biedt de bibliotheek verschillende opties die we in de volgende secties gaan onderzoeken.

5.1. Een JSON-payload verzenden

We kunnen de json argument om een ​​JSON-object of array te verzenden. Het kan van verschillende typen zijn:

  • EEN JSONObject of JSONArray zoals geleverd door de org.json-bibliotheek
  • EEN Kaart, die wordt omgezet in een JSON-object
  • EEN Verzameling, Herhaalbaar of array, die wordt getransformeerd naar een JSON-array

We kunnen ons eerdere GET-voorbeeld gemakkelijk omzetten in een POST-voorbeeld dat een eenvoudig JSON-object verzendt:

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

Merk op dat de transformatie van verzamelingen naar JSON-objecten oppervlakkig is. Bijvoorbeeld een Lijst van Kaart‘S worden niet geconverteerd naar een JSON-array van JSON-objecten, maar naar een array van strings.

Voor diepe conversie hebben we een complexere JSON-toewijzingsbibliotheek nodig, zoals Jackson. De conversiefaciliteit van de bibliotheek is alleen bedoeld voor eenvoudige gevallen.

5.2. Formuliergegevens verzenden (URL gecodeerd)

Om formuliergegevens te verzenden (URL-gecodeerd, zoals in HTML-formulieren) gebruiken we de gegevens argument met een Kaart:

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

5.3. Bestanden uploaden (meerdelig formulier)

We kunnen een of meer bestanden gecodeerd verzenden als een gegevensverzoek met meerdere delen.

In dat geval gebruiken we de bestanden argument:

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

We kunnen zien dat khttp een FileLike abstractie, een object met een naam en een inhoud. De inhoud kan een string, een byte-array, een het dossier, of een Pad.

5.4. Onbewerkte inhoud verzenden

Als geen van de bovenstaande opties geschikt is, kunnen we een InputStream om onbewerkte gegevens te verzenden als de hoofdtekst van een HTTP-verzoek:

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

In dit geval moeten we waarschijnlijk ook enkele kopteksten handmatig instellen, die we in een later gedeelte zullen bespreken.

6. Behandeling van de reactie

Tot nu toe hebben we verschillende manieren gezien om gegevens naar een server te verzenden. Maar veel HTTP-bewerkingen zijn handig vanwege de gegevens die ze ook retourneren.

khttp is daarom gebaseerd op het blokkeren van I / O alle functies die overeenkomen met HTTP-methoden retourneren een Reactie voorwerp met het antwoord dat van de server is ontvangen.

Dit object heeft verschillende eigenschappen waartoe we toegang hebben, afhankelijk van het type inhoud.

6.1. JSON-reacties

Als we weten dat het antwoord een JSON-object of array is, kunnen we de jsonObject en jsonArray eigendommen:

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

6.2. Tekst- of binaire reacties

Als we het antwoord willen lezen als een Draad in plaats daarvan kunnen we de tekst eigendom:

val bericht: String = response. tekst

Of, als we het als binaire gegevens willen lezen (bijvoorbeeld een bestand downloaden), gebruiken we de inhoud eigendom:

val imageData: ByteArray = response.content

Ten slotte hebben we ook toegang tot het onderliggende InputStream:

val inputStream: InputStream = response.raw

7. Geavanceerd gebruik

Laten we ook eens kijken naar een aantal geavanceerdere gebruikspatronen die over het algemeen nuttig zijn en die we in de vorige secties nog niet hebben behandeld.

7.1. Omgaan met kopteksten en cookies

Alle khttp-functies hebben een headers argument wat een is Kaart van koptekstnamen en waarden.

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

Evenzo voor cookies:

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

We hebben ook toegang tot headers en cookies die door de server zijn verzonden in het antwoord:

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

7.2. Fouten afhandelen

Er zijn twee soorten fouten die kunnen optreden in HTTP: foutreacties, zoals 404 - Niet gevonden, die deel uitmaken van het protocol; en fouten op laag niveau, zoals "verbinding geweigerd".

De eerste soort resulteert niet in het gooien van uitzonderingen voor khttp; in plaats daarvan, we moeten de Antwoord statusCode eigendom:

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

Fouten op een lager niveau leiden er daarentegen toe dat er uitzonderingen worden gegenereerd vanuit het onderliggende Java I / O-subsysteem, zoals ConnectException.

7.3. Reacties streamen

Soms kan de server reageren met een groot stuk inhoud, en / of kan het lang duren voordat deze reageert. In die gevallen willen we het antwoord misschien in stukjes verwerken, in plaats van te wachten tot het voltooid is en geheugen in beslag neemt.

Als we de bibliotheek willen instrueren om ons een streamingreactie te geven, dan moeten we slagen waar als de stroom argument:

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

Vervolgens kunnen we het in stukjes verwerken:

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

7.4. Niet-standaardmethoden

In het onwaarschijnlijke geval dat we een HTTP-methode (of werkwoord) moeten gebruiken die khttp niet standaard biedt - bijvoorbeeld voor een extensie van het HTTP-protocol, zoals WebDAV - zijn we nog steeds gedekt.

In feite worden alle functies in het khttp-pakket, die overeenkomen met HTTP-methoden, geïmplementeerd met behulp van een generiek verzoek functie die we ook kunnen gebruiken:

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

7.5. Andere mogelijkheden

We hebben niet alle functies van khttp aangeraakt. We hebben het bijvoorbeeld niet gehad over time-outs, omleidingen en geschiedenis, of asynchrone bewerkingen.

De officiële documentatie is de ultieme bron van informatie over de bibliotheek en al zijn functies.

8. Conclusie

In deze tutorial hebben we gezien hoe je HTTP-verzoeken kunt doen in Kotlin met de idiomatische bibliotheek khttp.

De implementatie van al deze voorbeelden is te vinden in het GitHub-project.