Drivstoff HTTP-bibliotek med Kotlin

1. Oversikt

I denne veiledningen tar vi en titt på Fuel HTTP Library, som er, med forfatterens ord, det enkleste HTTP-nettverksbiblioteket for Kotlin / Android. Videre kan biblioteket også brukes i Java.

Hovedfunksjonene i biblioteket inkluderer:

  • Støtte for grunnleggende HTTP-verb (GET, POST, DELETE, etc.) både asynkrone og blokkeringsforespørsler
  • Evne til å laste ned og laste opp en fil (flerdelt / skjemadata)
  • Mulighet for å administrere global konfigurasjon
  • Innebygde modulariseringsmoduler (Jackson, Gson, Mhosi, Forge)
  • Støtte for Kotlins coroutines-modul og RxJava 2.x
  • Enkelt å konfigurere rutermotiv

2. Avhengigheter

Biblioteket er sammensatt av forskjellige moduler, slik at vi enkelt kan inkludere funksjonene vi trenger. Noen av disse inkluderer:

  • En modul for RxJava og Kotlins Coroutines-støtte
  • En modul for Android og Android LiveData Architecture Components support
  • Fire moduler som vi kan velge objektserialiseringsmodulen for å bruke - Gson, Jackson, Moshi eller Forge.

I denne opplæringen vil vi fokusere på kjernemodulen, modulene for Coroutines, RxJava og Gson-serialiseringsmodulen:

 com.github.kittinunf.fuel fuel $ {fuel.version} com.github.kittinunf.fuel fuel-gson $ {fuel.version} com.github.kittinunf.fuel fuel-rxjava $ {fuel.version} com.github. kittinunf.fuel fuel-coroutines $ {fuel.version} 

Du finner de nyeste versjonene på JFrog Bintray.

3. Forespørsel

For å gjøre en forespørsel, gir Fuel en String Utvidelse. I tillegg og som et alternativ, kan vi bruke Brensel klasse som har en metode for hvert HTTP-verb.

Drivstoff støtter alle HTTP-verb bortsett fra PATCH. Årsaken er at Drivstoff HttpClient er en innpakning over java.net.HttpUrlConnection som ikke støtter PATCH.

For å sidestegge problemet, konverterer HttpClient PATCH-forespørsler til en POST-forespørsel og legger til en X-HTTP-metodeoverstyring: PATCH header, så vi må sørge for at API-ene våre er konfigurert til å godta denne headeren som standard.

For å forklare Fuel's funksjoner, skal vi bruke httpbin.org, en enkel HTTP-forespørsel og svartjeneste, og JsonPlaceholder - en falsk online API for testing og prototyping.

3.1. FÅ forespørsel

La oss begynne å lage enkel HTTP forespørsel i asynkroniseringsmodus:

"//httpbin.org/get".httpGet().response {forespørsel, svar, resultat -> // svarhåndtering}

Ved hjelp av httpGet () over en String gir oss en Trippel.

De Resultat er en datastruktur med funksjonell stil som inneholder resultatet av operasjonen (suksess eller fiasko). Vi kommer tilbake Resultat datastruktur på et senere tidspunkt.

Vi kan også komme med forespørselen i blokkeringsmodus:

val (forespørsel, svar, resultat) = "//httpbin.org/get" .httpGet (). svar ()

Merk at de returnerte parametrene er de samme som async-versjonen, men i dette tilfellet er tråden som gjorde forespørselen blokkert.

Det er også en mulighet til å bruke kodede nettadresseparametere:

val (forespørsel, svar, resultat) = "//jsonplaceholder.typicode.com/posts" .httpGet (listOf ("userId" til "1")). respons () // løse til //jsonplaceholder.typicode.com/ innlegg? userId = 1 

De httpGet () metoden (og de andre lignende) kan motta en Liste for å kode URL-parametere.

3.2. POST-forespørsel

Vi kan gjøre POST-forespørsler på samme måte som for GET, ved hjelp av httpPost () eller bruke post() metoden for Brensel klasse:

"//httpbin.org/post".httpPost (). respons {forespørsel, svar, resultat -> // svarhåndtering}
val (forespørsel, svar, resultat) = Fuel.post ("// httpbin.org/post") .respons () 

Hvis vi har en kropp, kan vi gjennomføre den kropp() metode i JSON strengformat:

val bodyJson = "" "{" title ":" foo "," body ":" bar "," id ":" 1 "}" "" val (forespørsel, svar, resultat) = Fuel.post ("// jsonplaceholder.typicode.com/posts ") .body (bodyJson) .response ()

3.3. Andre verb

Samme som for GET og POST, det er en metode for hvert av de gjenværende verbene:

Fuel.put ("// httpbin.org/put") Fuel.delete ("// httpbin.org/delete") Fuel.head ("// httpbin.org/get") Fuel.patch ("// httpbin .org / patch ")

Husk at Fuel.patch () vil utføre en POST-forespørsel med enX-HTTP-metodeoverstyring: PATCH Overskrift.

4. Konfigurasjon

Biblioteket leverer et enkelt objekt - FuelManager.instance - for å administrere global konfigurasjon.

La oss konfigurere en basisbane, noen overskrifter og vanlige parametre. La oss også konfigurere noen interceptors.

4.1. BasePath

Ved hjelp av basePath variabel kan vi sette en felles bane for alle forespørsler.

FuelManager.instance.basePath = "//httpbin.org" val (forespørsel, respons, resultat) = "/get".httpGet (). Respons () // vil utføre GET //httpbin.org/get

4.2. Overskrifter

Videre kan vi administrere vanlige HTTP-overskrifter ved hjelp av baseHeaders kart:

FuelManager.instance.baseHeaders = mapOf ("OS" til "Debian")

På en alternativ måte, hvis vi vil angi en lokal topptekst, kan vi bruke Overskrift() metode på forespørsel:

val (forespørsel, svar, resultat) = "/ get" .httpGet () .header (mapOf ("OS" til "Debian")) .respons ()

4.3. Params

Til slutt kan vi også angi vanlige parametere ved hjelp av baseParams liste:

FuelManager.instance.baseParams = listOf ("foo" til "bar")

4.4. Andre muligheter

Det er mange flere alternativer som vi kan klare oss gjennom FuelManager:

  • keystore som er null som standard
  • stikkontaktfabrikk som vil bli levert av brukeren eller avledet fra keystore hvis det ikke er det null
  • vertsnavnVerifier som er angitt som standard for å bruke den som tilbys av HttpsURLConnection klasse
  • requestInterceptors og responsInterceptors
  • pause og timeoutLes for en forespørsel

4.5. Forespørsel / svaravlytere

Når det gjelder interceptors, vi kan legge til leverte forespørsel / svaravlyttere som cUrlLoggingRequestInterceptors (), eller vi kan definere vår:

FuelManager.instance.addRequestInterceptor (cUrlLoggingRequestInterceptor ()) 
FuelManager.instance.addRequestInterceptor (tokenInterceptor ()) fun tokenInterceptor () = {next: (Request) -> Request -> {req: Request -> req.header (mapOf ("Authorization" to "Bearer AbCdEf123456")) next ( krav)}}

5. Svarhåndtering

Tidligere introduserte vi en funksjonell datastruktur - Resultat - som representerer operasjonsresultatet (suksess eller fiasko).

Jobber med Resultat er enkelt, det er en dataklasse som kan inneholde svaret i ByteArray, String, JSON, eller en generisk T gjenstand:

morsomt svar (handler: (Request, Response, Result) -> Unit) fun responseString (handler: (Request, Response, Result) -> Unit) fun responseJson (handler: (Request, Response, Result) -> Unit) fun responseObject (deserializer: ResponseDeserializable, handler: (Request, Response, Result) -> Unit) 

La oss få svar som en String for å illustrere dette:

val (forespørsel, svar, resultat) = Fuel.post ("// httpbin.org/post") .responseString () val (nyttelast, feil) = resultat // nyttelast er en streng

Merk at svaret i JSON-format krever Android-avhengigheter.

 com.github.kittinunf.fuel fuel-android $ {fuel.version} 

6. JSON Serialization / Deserialization

Fuel gir innebygd støtte for deserialisering av svar med fire metoder som avhengig av våre behov og JSON-parseringsbiblioteket vi velger, er vi pålagt å implementere:

offentlig moro deserialize (bytes: ByteArray): T? offentlig moro deserialize (inputStream: InputStream): T? offentlig moro deserialisere (leser: Leser): T? offentlig moro deserialize (innhold: String): T?

Ved å inkludere Gson-modulen kan vi deserialisere og serieisere objekter:

dataklasse Post (var userId: Int, var id: Int, var title: String, var body: String) {class Deserializer: ResponseDeserializable {override fun deserialize (content: String): Array = Gson (). fromJson (content, Array :: class.java)}}

Vi kan deserialisere objekter med tilpasset deserializer:

"//jsonplaceholder.typicode.com/posts" .httpGet (). responseObject (Post.Deserializer ()) {_, _, result -> val postsArray = result.component1 ()}

Eller via responseObject som bruker intern Gson deserializer:

"//jsonplaceholder.typicode.com/posts/1" .httpGet (). responseObject {_, _, result -> val post = result.component1 ()}

På den annen side kan vi serialisere ved hjelp av Gson (). ToJson ():

val post = Post (1, 1, "Lorem", "Lorem Ipse dolor sit amet") val (forespørsel, svar, resultat) = Fuel.post ("// jsonplaceholder.typicode.com/posts") .header (" Content-Type "to" application / json ") .body (Gson (). ToJson (post) .toString ())

Det er viktig å stille inn Innholdstype, ellers kan serveren motta objektet i et annet JSON-objekt.

Til slutt, på en lignende måte, kan vi gjøre det ved å bruke avhengigheter Jackson, Moshi eller Forge.

7. Last ned og last opp fil

Drivstoffbiblioteket inneholder alle nødvendige funksjoner for å laste ned og laste opp filer.

7.1. nedlasting

Med nedlasting() metoden kan vi enkelt laste ned en fil og lagre den i filen som returneres av mål() lambda:

Fuel.download ("// httpbin.org/bytes/32768"). Destinasjon {respons, url -> File.createTempFile ("temp", ".tmp")}

Vi kan også laste ned en fil med en fremdriftsbehandler:

Fuel.download ("// httpbin.org/bytes/327680") .progress {readBytes, totalBytes -> val progress = readBytes.toFloat () / totalBytes.toFloat () // ...}

7.2. Laste opp

På samme måten, vi kan laste opp en fil ved hjelp av laste opp() metode, som indikerer filen som skal lastes opp med kilde() metode:

Fuel.upload ("/ upload"). Kilde {forespørsel, url -> File.createTempFile ("temp", ".tmp")}

Noter det laste opp() bruker POST-verbet som standard. Hvis vi vil bruke et annet HTTP-verb, kan vi spesifisere det:

Fuel.upload ("/ upload", Method.PUT) .kilde {forespørsel, url -> File.createTempFile ("temp", ".tmp")}

Videre kan vi laste opp flere filer ved hjelp av kilder () metode som godtar en liste over filer:

Fuel.upload ("/ post"). Kilder {forespørsel, url -> listOf (File.createTempFile ("temp1", ".tmp"), File.createTempFile ("temp2", ".tmp"))}

Til slutt kan vi laste opp en mengde data fra en InputStream:

Fuel.upload ("/ post"). Blob {request, url -> Blob ("filename.png", someObject.length, {someObject.getInputStream ()})}

8. Støtte for RxJava og Coroutines

Fuel gir støtte for RxJava og Coroutines, to måter å skrive asyncrhonus, ikke-blokkerende kode.

RxJava er en Java VM-implementering av Reactive Extensions, et bibliotek for komponering av asynkrone og hendelsesbaserte programmer.

Den utvider Observer-mønsteret for å støtte sekvenser av data / hendelser og legger til operatører som tillater å komponere sekvenser sammen erklærende uten å bekymre seg for synkronisering, trådsikkerhet og samtidige datastrukturer.

Kotlins Coroutines er som lette tråder, og som sådan kan de løpe parallelt, vente på hverandre og kommunisere ... Den største forskjellen er at coroutines er veldig billige; vi kan lage tusenvis av dem, og betale veldig lite når det gjelder minne.

8.1. RxJava

For å støtte RxJava 2.x, gir Fuel seks utvidelser:

moro Request.rx_response (): Singel<>> moro Request.rx_responseString (charset: Charset): Single<>> moro Request.rx_responseObject (deserializable: Deserializable): Single<>> morsom Request.rx_data (): Single moro Request.rx_string (charset: Charset): Single moro Request.rx_object (deserializable: Deserializable): Single

Merk at for å støtte alle forskjellige svarstyper, returnerer hver metode en annen Enkelt.

Vi kan enkelt bruke “Rx” -metoder ved å påkalle den mer relevante over en Be om:

 "//jsonplaceholder.typicode.com/posts?id=1" .httpGet (). rx_object (Post.Deserializer ()). abonner {res, kastbar -> val post = res.component1 ()}

8.2. Coroutines

Med coroutines-modulen, Fuel gir utvidelsesfunksjoner for å pakke et svar inne i en coroutine og håndtere resultatet.

For å bruke Coroutines blir lignende API-er gjort tilgjengelige, f.eks responsString () ble til awaitStringResponse ():

runBlocking {Fuel.get ("// httpbin.org/get"). awaitStringResponse ()}

Det gir også nyttige metoder for å håndtere andre objekter enn String eller ByteArray (awaitByteArrayResponse ()) ved hjelp av awaitObject (), awaitObjectResult () eller awaitObjectResponse ():

runBlocking {Fuel.get ("// jsonplaceholder.typicode.com/posts?id=1") .awaitObjectResult (Post.Deserializer ())}

Husk at Kotlins Coroutines er eksperimentelle, noe som betyr at det kan bli endret i de kommende utgivelsene.

9. API-ruting

Sist, men ikke minst, for å håndtere nettverksruter, gir Fuel støtte ved å implementere Router-designmønsteret.

Med rutermønsteret kan vi sentralisere administrasjonen av API ved hjelp av FuelRouting grensesnitt, som gir en kombinasjon av metoder for å sette riktig HTTP-verb, bane, params og headere i henhold til det endepunktet som kalles.

Grensesnittet definerer fem egenskaper som det er mulig å konfigurere ruteren vår:

forseglet klasse PostRoutingAPI: FuelRouting {class posts (val userId: String, override val body: String?): PostRoutingAPI () class comments (val postId: String, override val body: String?): PostRoutingAPI () override val basePath = "/ /jsonplaceholder.typicode.com "overstyr val-metode: Metode get () {return når (dette) {er PostRoutingAPI.posts -> Method.GET er PostRoutingAPI.comments -> Method.GET}} overstyr valvebane: String get () {return når (dette) {er PostRoutingAPI.posts -> "/ posts" er PostRoutingAPI.comments -> "/ comments"}} overstyr val params: Liste? få () {return når (dette) {er PostRoutingAPI.posts -> listOf ("userId" til this.userId) er PostRoutingAPI.comments -> listOf ("postId" til this.postId)}} overstyr val overskrifter: Map? få () {return null}}

For å velge hvilket HTTP-verb vi skal bruke metode eiendom, på samme måte kan vi overstyre sti eiendom, slik at du velger riktig vei.

Enda mer med params eiendom, har vi muligheten til å angi parametere for forespørselen, og hvis vi trenger å angi HTTP-overskrifter, kan vi gjøre det overstyrende den aktuelle egenskapen.

Derfor bruker vi det på samme måte som vi hadde over hele opplæringen med be om() metode:

Fuel.request (PostRoutingAPI.posts ("1", null)) .responseObject (Post.Deserializer ()) {forespørsel, svar, resultat -> // svarhåndtering}
Fuel.request (PostRoutingAPI.comments ("1", null)) .responseString {forespørsel, svar, resultat -> // svarhåndtering}

10. Konklusjon

I denne artikkelen har vi vist Fuel HTTP Library for Kotlin og dets mer nyttige funksjoner for enhver brukstilfelle.

Biblioteket er i stadig utvikling, så ta en titt på GitHub-repoen deres - for å holde rede på nye funksjoner.

Som vanlig kan alle kodebitene som er nevnt i opplæringen, bli funnet i GitHub-depotet vårt.