Permintaan HTTP dengan Kotlin dan khttp

1. Perkenalan

Protokol HTTP dan API yang dibangun di atasnya sangat penting dalam pemrograman hari ini.

Di JVM kami memiliki beberapa opsi yang tersedia, dari perpustakaan tingkat rendah hingga sangat tinggi, dari proyek yang sudah mapan hingga anak baru di blok tersebut. Namun, kebanyakan dari mereka ditargetkan terutama pada program Java.

Pada artikel ini, kita akan melihat khttp, pustaka Kotlin idiomatik untuk menggunakan sumber daya dan API berbasis HTTP .

2. Dependensi

Untuk menggunakan pustaka dalam proyek kami, pertama-tama kami harus menambahkannya ke dependensi kami:

 khttp khttp 0.1.0 

Karena ini belum ada di Maven Central, kami juga harus mengaktifkan repositori JCenter:

 central //jcenter.bintray.com 

Versi 0.1.0 adalah yang saat ini pada saat penulisan. Kami dapat, tentu saja, memeriksa JCenter untuk yang lebih baru.

3. Penggunaan Dasar

Dasar-dasar protokol HTTP sederhana, meskipun detail halusnya bisa sangat rumit. Karenanya, khttp juga memiliki antarmuka yang sederhana.

Untuk setiap metode HTTP, kita dapat menemukan fungsi tingkat paket dalam paket khttp , seperti get, post , dan sebagainya.

Semua fungsi mengambil set argumen yang sama dan mengembalikan objek Respon ; kita akan melihat detailnya di bagian berikut.

Dalam kursus artikel ini, kita akan menggunakan formulir yang sepenuhnya memenuhi syarat, misalnya, khttp.put . Dalam proyek kami, kami dapat, tentu saja, mengimpor dan mungkin mengganti nama metode tersebut:

import khttp.delete as httpDelete

Catatan: kami telah menambahkan deklarasi tipe untuk kejelasan di seluruh contoh kode karena tanpa IDE mereka akan sulit diikuti.

4. Permintaan Sederhana

Setiap permintaan HTTP memiliki setidaknya dua komponen yang diperlukan: metode dan URL . Dalam khttp, metode ditentukan oleh fungsi yang kita panggil, seperti yang telah kita lihat di bagian sebelumnya.

URL adalah satu-satunya argumen yang diperlukan untuk metode ini; jadi, kami dapat dengan mudah melakukan permintaan sederhana:

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

Di bagian berikut, kami akan mempertimbangkan semua permintaan untuk diselesaikan dengan sukses.

4.1. Menambahkan Parameter

Kami sering kali harus memberikan parameter kueri selain URL dasar, terutama untuk permintaan GET.

metode khttp menerima argumen params yang merupakan Peta pasangan nilai kunci untuk disertakan dalam kueri String:

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

Perhatikan bahwa kita telah menggunakan fungsi mapOf untuk membuat Peta dengan cepat; URL permintaan yang dihasilkan akan menjadi:

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

5. Badan Permintaan

Operasi umum lainnya yang sering perlu kita lakukan adalah mengirim data, biasanya sebagai payload permintaan POST atau PUT.

Untuk ini, pustaka menawarkan beberapa opsi yang akan kita periksa di bagian berikut.

5.1. Mengirim Payload JSON

Kita dapat menggunakan argumen json untuk mengirim objek atau array JSON. Ini bisa dari beberapa jenis yang berbeda:

  • Sebuah JSONObject atau JSONArray seperti yang disediakan oleh perpustakaan org.json
  • Sebuah Peta , yang berubah menjadi objek JSON
  • Sebuah Collection , Iterable atau array, yang ditransformasikan ke array JSON

Kita dapat dengan mudah mengubah contoh GET kita sebelumnya menjadi POST yang akan mengirim objek JSON sederhana:

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

Perhatikan bahwa transformasi dari koleksi ke objek JSON bersifat dangkal. Misalnya, Daftar dari Peta 's tidak akan dikonversi ke array JSON JSON objek, melainkan untuk array string.

Untuk konversi mendalam, kita membutuhkan pustaka pemetaan JSON yang lebih kompleks seperti Jackson. Fasilitas konversi perpustakaan hanya untuk kasus sederhana.

5.2. Mengirim Data Formulir (URL Dikodekan)

Untuk mengirim data formulir (URL dikodekan, seperti dalam bentuk HTML) kami menggunakan argumen data dengan Peta :

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

5.3. Mengupload File (Formulir Multibagian)

Kami dapat mengirim satu atau lebih file yang dikodekan sebagai permintaan data formulir multi bagian.

Dalam hal ini, kami menggunakan argumen file :

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

Kita dapat melihat bahwa khttp menggunakan abstraksi FileLike , yang merupakan objek dengan nama dan konten. Konten dapat berupa string, array byte, File , atau Path .

5.4. Mengirim Konten Mentah

Jika tidak ada opsi di atas yang cocok, kita dapat menggunakan InputStream untuk mengirim data mentah sebagai isi permintaan HTTP:

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

Dalam kasus ini, kemungkinan besar kita juga perlu mengatur beberapa header secara manual, yang akan kita bahas di bagian selanjutnya.

6. Handling the Response

So far we've seen various ways of sending data to a server. But many HTTP operations are useful because of the data they return as well.

khttp is based on blocking I/O, therefore all functions corresponding to HTTP methods return a Response object containing the response received from the server.

This object has various properties that we can access, depending on the type of content.

6.1. JSON Responses

If we know the response to be a JSON object or array, we can use the jsonObject and jsonArray properties:

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

6.2. Text or Binary Responses

If we want to read the response as a String instead, we can use the text property:

val message : String = response.text

Or, if we want to read it as binary data (e.g. a file download) we use the content property:

val imageData : ByteArray = response.content

Finally, we can also access the underlying InputStream:

val inputStream : InputStream = response.raw

7. Advanced Usage

Let's also take a look at a couple of more advanced usage patterns which are generally useful, and that we haven't yet treated in the previous sections.

7.1. Handling Headers and Cookies

All khttp functions take a headers argument which is a Map of header names and values.

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

Similarly for cookies:

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

We can also access headers and cookies sent by the server in the response:

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

7.2. Handling Errors

There are two types of errors that can arise in HTTP: error responses, such as 404 – Not Found, which are part of the protocol; and low-level errors, such as “connection refused”.

The first kind doesn't result in khttp throwing exceptions; instead, we should check the Response statusCode property:

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

Lower-level errors, instead, result in exceptions being thrown from the underlying Java I/O subsystem, such as ConnectException.

7.3. Streaming Responses

Sometimes the server can respond with a big piece of content, and/or take a long time to respond. In those cases, we may want to process the response in chunks, rather than waiting for it to complete and take up memory.

If we want to instruct the library to give us a streaming response, then we have to pass true as the stream argument:

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

Then, we can process it in chunks:

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

7.4. Non-Standard Methods

In the unlikely case that we need to use an HTTP method (or verb) that khttp doesn't provide natively – say, for some extension of the HTTP protocol, like WebDAV – we're still covered.

In fact, all functions in the khttp package, which correspond to HTTP methods, are implemented using a generic request function that we can use too:

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

7.5. Other Features

We haven't touched all the features of khttp. For example, we haven't discussed timeouts, redirects and history, or asynchronous operations.

Dokumentasi resmi adalah sumber informasi utama tentang perpustakaan dan semua fiturnya.

8. Kesimpulan

Dalam tutorial ini, kita telah melihat cara membuat permintaan HTTP di Kotlin dengan pustaka idiomatik khttp.

Implementasi dari semua contoh ini dapat ditemukan di proyek GitHub.