1. 序章

HTTPプロトコルとそれに基づいて構築されたAPIは、最近のプログラミングにおいて中心的な重要性を持っています。

JVMには、低レベルのライブラリから非常に高レベルのライブラリまで、確立されたプロジェクトからブロック上の新しい子供まで、いくつかの利用可能なオプションがあります。 ただし、それらのほとんどは主にJavaプログラムを対象としています。

この記事では、HTTPベースのリソースとAPIを使用するための慣用的なKotlinライブラリであるkhttpについて説明します。

2. 依存関係

プロジェクトでライブラリを使用するには、まず、ライブラリを依存関係に追加する必要があります。

<dependency>
    <groupId>khttp</groupId>
    <artifactId>khttp</artifactId>
    <version>0.1.0</version>
</dependency>

これはまだMavenCentralにないため、JCenterリポジトリも有効にする必要があります。

<repository>
    <id>central</id>
    <url>http://jcenter.bintray.com</url>
</repository>

バージョン0.1.0は、執筆時点での現在のバージョンです。 もちろん、JCenterで新しいを確認することもできます。

3. 基本的な使用法

細かい詳細は非常に複雑になる可能性がありますが、HTTPプロトコルの基本は単純です。 したがって、khttpにもシンプルなインターフェイスがあります。

すべてのHTTPメソッドについて、 get、 postなどのパッケージレベルの関数がkhttpパッケージにあります。

関数はすべて同じ引数のセットを取り、Responseオブジェクトを返します。 これらの詳細については、次のセクションで説明します。

この記事では、khttp.putなどの完全修飾形式を使用します。 もちろん、私たちのプロジェクトでは、これらのメソッドをインポートし、場合によっては名前を変更できます。

import khttp.delete as httpDelete

注:コード例全体でわかりやすくするために型宣言を追加しました。IDEがないと、型宣言を理解するのが難しい場合があるためです。

4. 簡単なリクエスト

すべてのHTTPリクエストには、メソッドとURLの少なくとも2つの必須コンポーネントがあります。 khttpでは、前のセクションで見たように、メソッドは呼び出す関数によって決定されます。

このメソッドに必要な引数はURLだけです。 したがって、簡単なリクエストを簡単に実行できます。

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

次のセクションでは、すべてのリクエストが正常に完了することを検討します。

4.1. パラメータの追加

特にGETリクエストの場合、ベースURLに加えてクエリパラメータを提供する必要があることがよくあります。

khttpのメソッドは、クエリ String:に含めるキーと値のペアのMapであるparams引数を受け入れます。

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

mapOf 関数を使用して、Mapをオンザフライで作成したことに注意してください。 結果のリクエストURLは次のようになります。

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

5. リクエストボディ

頻繁に実行する必要があるもう1つの一般的な操作は、通常はPOSTまたはPUT要求のペイロードとしてデータを送信することです。

このために、ライブラリには、次のセクションで検討するいくつかのオプションが用意されています。

5.1. JSONペイロードの送信

json引数を使用して、JSONオブジェクトまたは配列を送信できます。いくつかの異なるタイプにすることができます。

  • org.jsonライブラリによって提供されるAJSONObjectまたはJSONArray
  • JSONオブジェクトに変換されるMap
  • JSON配列に変換されるCollectionIterableまたは配列。

以前のGETの例をPOSTの例に簡単に変換して、単純なJSONオブジェクトを送信できます。

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

コレクションからJSONオブジェクトへの変換は浅いことに注意してください。 たとえば、MapListは、JSONオブジェクトのJSON配列ではなく、文字列の配列に変換されます。

深い変換には、Jacksonなどのより複雑なJSONマッピングライブラリが必要です。 ライブラリの変換機能は、単純な場合のみを対象としています。

5.2. フォームデータの送信(URLエンコード)

フォームデータ(HTMLフォームのようにURLエンコード)を送信するには、data引数とMapを使用します。

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

5.3. ファイルのアップロード(マルチパートフォーム)

マルチパートフォームデータリクエストとしてエンコードされた1つ以上のファイルを送信できます。

その場合、files引数を使用します。

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

khttpがFileLike abstractを使用していることがわかります。これは、名前とコンテンツを持つオブジェクトです。 コンテンツは、文字列、バイト配列、ファイル、またはパスにすることができます。

5.4. 生コンテンツの送信

上記のオプションのいずれも適切でない場合は、 InputStream を使用して、生データをHTTPリクエストの本文として送信できます。

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

この場合、いくつかのヘッダーも手動で設定する必要があります。これについては、後のセクションで説明します。

6. 応答の処理

これまで、サーバーにデータを送信するさまざまな方法を見てきました。 ただし、多くのHTTP操作は、データも返すため便利です。

khttpはI/Oのブロックに基づいているため、 HTTPメソッドに対応するすべての関数は、サーバーから受信した応答を含む応答オブジェクトを返します。

このオブジェクトには、コンテンツのタイプに応じてアクセスできるさまざまなプロパティがあります。

6.1. JSON応答

応答がJSONオブジェクトまたは配列であることがわかっている場合は、jsonObjectおよびjsonArrayプロパティを使用できます。

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

6.2. テキストまたはバイナリ応答

代わりに応答をStringとして読み取りたい場合は、textプロパティを使用できます。

val message : String = response.text

または、バイナリデータとして読み取りたい場合(例: ファイルのダウンロード)コンテンツプロパティを使用します。

val imageData : ByteArray = response.content

最後に、基になるInputStreamにアクセスすることもできます。

val inputStream : InputStream = response.raw

7. 高度な使用法

また、一般的に有用であり、前のセクションではまだ扱っていない、より高度な使用パターンをいくつか見てみましょう。

7.1. ヘッダーとCookieの処理

すべてのkhttp関数は、ヘッダーの名前と値のMapであるヘッダー引数を取ります。

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

同様にクッキーの場合:

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

また、応答でサーバーから送信されたヘッダーとCookieにアクセスすることもできます。

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

7.2. エラーの処理

HTTPで発生する可能性のあるエラーには2つのタイプがあります。プロトコルの一部である404–NotFoundなどのエラー応答。 「接続が拒否されました」などの低レベルのエラー。

最初の種類では、khttpが例外をスローすることはありません。 代わりに、ResponsestatusCodeプロパティを確認する必要があります。

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

代わりに、下位レベルのエラーにより、ConnectExceptionなどの基盤となるJavaI/Oサブシステムから例外がスローされます。

7.3. ストリーミング応答

サーバーが大きなコンテンツで応答したり、応答に時間がかかる場合があります。 そのような場合、応答が完了してメモリを消費するのを待つのではなく、応答をチャンクで処理したい場合があります。

ライブラリにストリーミング応答を返すように指示する場合は、trueストリーム引数として渡す必要があります。

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

次に、それをチャンクで処理できます。

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

7.4. 非標準的な方法

khttpがネイティブに提供しないHTTPメソッド(または動詞)を使用する必要があるというまれなケースでは、たとえば、WebDAVなどのHTTPプロトコルの拡張については、まだカバーされています。

実際、HTTPメソッドに対応するkhttpパッケージのすべての関数は、次のような汎用のrequest関数を使用して実装されています。

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

7.5. その他の機能

khttpのすべての機能に触れたわけではありません。 たとえば、タイムアウト、リダイレクトと履歴、または非同期操作については説明していません。

公式ドキュメントは、ライブラリとそのすべての機能に関する究極の情報源です。

8. 結論

このチュートリアルでは、慣用的なライブラリkhttpを使用してKotlinでHTTPリクエストを作成する方法を説明しました。

これらすべての例の実装は、GitHubプロジェクトにあります。