KotlinによるFuel HTTPライブラリ
1概要
-
このチュートリアルでは、https://github.com/kittinunf/Fuel[Fuel HTTP Library]** を見ていきます。これは、作者の言葉で言うと、Kotlin/Android用の最も簡単なHTTPネットワークライブラリです。さらに、このライブラリーはJavaでも使用できます。
ライブラリの主な機能は次のとおりです。
-
基本的なHTTP動詞(GET、POST、DELETEなど)の両方のサポート
非同期リクエストとブロックリクエスト
** ファイルをダウンロードおよびアップロードする機能(
multipart/form-data
)
-
グローバル設定を管理する可能性
-
組み込みオブジェクト直列化モジュール(Jackson、Gson、Mhosi、Forge)
-
KotlinのコルーチンモジュールとRxJava 2.xのサポート
-
ルーターのデザインパターンを簡単に設定
2依存関係
-
ライブラリはさまざまなモジュールで構成されているので、必要な機能を簡単に含めることができます。
-
RxJavaとKotlinのCoroutinesをサポートするためのモジュール
-
AndroidおよびAndroid LiveData Architectureコンポーネント用のモジュール
サポート
** オブジェクト直列化モジュールを選択できる4つのモジュール
使用する – Gson、ジャクソン、モシまたはフォージ。
このチュートリアルでは、コアモジュール、Coroutines用モジュール、RxJava、Gsonシリアライゼーションモジュールに焦点を当てます。
<dependency>
<groupId>com.github.kittinunf.fuel</groupId>
<artifactId>fuel</artifactId>
<version>${fuel.version}</version>
</dependency>
<dependency>
<groupId>com.github.kittinunf.fuel</groupId>
<artifactId>fuel-gson</artifactId>
<version>${fuel.version}</version>
</dependency>
<dependency>
<groupId>com.github.kittinunf.fuel</groupId>
<artifactId>fuel-rxjava</artifactId>
<version>${fuel.version}</version>
</dependency>
<dependency>
<groupId>com.github.kittinunf.fuel</groupId>
<artifactId>fuel-coroutines</artifactId>
<version>${fuel.version}</version>
</dependency>
JFrog Bintray
には、最新バージョンがあります。
3リクエストをする
-
リクエストを出すために、Fuelは
String
拡張子を提供します** さらに、そして代わりとして、それぞれのHTTP動詞のためのメソッドを持つ
Fuel
クラスを使うことができます。
FuelはPATCH以外のすべてのHTTP動詞をサポートします。その理由は、
Fuelの
HttpClient
は、PATCHをサポートしていない
java.net.HttpUrlConnection
のラッパーです。
この問題を回避するために、HttpClientはPATCH要求をPOST要求に変換し、
X-HTTP-Method-Override:PATCH
ヘッダーを追加します。したがって、このヘッダーをデフォルトで受け入れるようにAPIを構成する必要があります。
Fuelの機能を説明するために、http://httpbin.org/#/[httpbin.org]、単純なHTTP要求および応答サービス、およびhttps://jsonplaceholder.typicode.com[JsonPlaceholder]を使用します。 – テストとプロトタイピングのための偽のオンラインAPI。
3.1. GETリクエスト
非同期モードで簡単なHTTP
GET
リクエストを作成しましょう:
"http://httpbin.org/get".httpGet().response {
request, response, result ->
//response handling
}
String
の上で
httpGet()
を使うと、
Triple <Request、Response、Result>
が得られます。
-
https://github.com/kittinunf/Result
は、操作の結果(成功または失敗)を含む機能スタイルのデータ構造です。
後の段階で
Result
データ構造を再検討します。
ブロッキングモードでリクエストを行うこともできます。
val (request, response, result) = "http://httpbin.org/get"
.httpGet().response()
返されるパラメータは非同期バージョンと同じですが、この場合、リクエストを行ったスレッドはブロックされています。
また、エンコードされたURLパラメータを使用する可能性があります。
val (request, response, result) =
"https://jsonplaceholder.typicode.com/posts"
.httpGet(listOf("userId" to "1")).response()
//resolve to https://jsonplaceholder.typicode.com/posts?userId=1
httpGet()
メソッド(および他の類似のメソッド)は、URLパラメータをエンコードするための
List <Pair>
を受け取ることができます。
3.2. POSTリクエスト
GETの場合と同じ方法で、
httpPost()
を使用するか、または
Fuel
クラスの
post()
メソッドを使用して、POST要求を実行できます。
"http://httpbin.org/post".httpPost().response{
request, response, result ->
//response handling
}
val (request, response, result) = Fuel.post("http://httpbin.org/post")
.response()
ボディがある場合は、JSON文字列形式の
body()
メソッドを使用してそれを配置できます。
val bodyJson = """
{ "title" : "foo",
"body" : "bar",
"id" : "1"
}
"""
val (request, response, result) = Fuel.post("https://jsonplaceholder.typicode.com/posts")
.body(bodyJson)
.response()
3.3. 他の動詞
GETおよびPOSTと同様に、残りの各動詞にもメソッドがあります。
Fuel.put("http://httpbin.org/put")
Fuel.delete("http://httpbin.org/delete")
Fuel.head("http://httpbin.org/get")
Fuel.patch("http://httpbin.org/patch")
Fuel.patch()
は、
X-HTTP-Method-Override:PATCH
__ヘッダーを使用してPOSTリクエストを実行します。
4構成
-
このライブラリは、グローバル設定を管理するためのシングルトンオブジェクト
FuelManager.instance
を提供しています。
基本パス、いくつかのヘッダ、および共通パラメータを設定しましょう。また、いくつかのインターセプターを設定しましょう。
4.1.
BasePath
__basePath
__variableを使用して、すべてのリクエストに共通のパスを設定できます。
FuelManager.instance.basePath = "http://httpbin.org"
val (request, response, result) = "/get".httpGet().response()//will perform GET http://httpbin.org/get
4.2. ヘッダ
さらに、
baseHeaders
mapを使用して一般的なHTTPヘッダーを管理できます。
FuelManager.instance.baseHeaders = mapOf("OS" to "Debian")
別の方法で、ローカルヘッダを設定したい場合は、リクエストに
header()
メソッドを使用できます。
val (request, response, result) = "/get"
.httpGet()
.header(mapOf("OS" to "Debian"))
.response()
4.3. パームス
最後に、
baseParams
リストを使って共通のパラメータを設定することもできます。
FuelManager.instance.baseParams = listOf("foo" to "bar")
4.4. 別のオプション
__FuelManagerで管理できるオプションは他にもたくさんあります。
-
__keystore
whichはデフォルトで
null__です -
socketFactory
はユーザによって提供されるか派生します
keystore
から
null
でない場合
**
hostnameVerifier
はデフォルトで設定されているものを使用する
HttpsURLConnection
クラス
**
requestInterceptors
と
responseInterceptors
-
timeout
および
timeoutRead
(リクエスト用)
4.5. 要求/応答インターセプター
インターセプターに関しては、**
cUrlLoggingRequestInterceptors()、
のような提供されたリクエスト/レスポンスインターセプターを追加することができます。
FuelManager.instance.addRequestInterceptor(cUrlLoggingRequestInterceptor())
FuelManager.instance.addRequestInterceptor(tokenInterceptor())
fun tokenInterceptor() = {
next: (Request) -> Request ->
{ req: Request ->
req.header(mapOf("Authorization" to "Bearer AbCdEf123456"))
next(req)
}
}
5レスポンス処理
以前は、操作結果(成功または失敗)を表す機能データ構造体
Result
を導入しました。
Result
を使うのは簡単です。これは、
ByteArray
、
__String、JSON、または一般的な
T__オブジェクトにレスポンスを含めることができるデータクラスです。
fun response(handler: (Request, Response, Result<ByteArray, FuelError>) -> Unit)
fun responseString(handler: (Request, Response, Result<String, FuelError>) -> Unit)
fun responseJson(handler: (Request, Response, Result<Json, FuelError>) -> Unit)
fun <T> responseObject(deserializer: ResponseDeserializable<T>,
handler: (Request, Response, Result<T, FuelError>) -> Unit)
これを説明するために
String
として応答を取得しましょう。
val (request, response, result) = Fuel.post("http://httpbin.org/post")
.responseString()
val (payload, error) = result//payload is a String
JSON形式の応答にはAndroidの依存関係が必要であることに注意してください。
<dependency>
<groupId>com.github.kittinunf.fuel</groupId>
<artifactId>fuel-android</artifactId>
<version>${fuel.version}</version>
</dependency>
6. JSONシリアライゼーション/デシリアライゼーション
Fuelは、私たちのニーズと私たちが選択したJSON解析ライブラリに応じて、実装する必要がある4つの方法でレスポンスのデシリアライゼーションをサポートしています。
public fun deserialize(bytes: ByteArray): T?
public fun deserialize(inputStream: InputStream): T?
public fun deserialize(reader: Reader): T?
public fun deserialize(content: String): T?
Gsonモジュールを含めることで、オブジェクトをデシリアライズおよびシリアライズできます。
data class Post(var userId:Int,
var id:Int,
var title:String,
var body:String){
class Deserializer : ResponseDeserializable<Array<Post>> {
override fun deserialize(content: String): Array<Post>
= Gson().fromJson(content, Array<Post>::class.java)
}
}
カスタムのデシリアライザを使ってオブジェクトをデシリアライズできます。
"https://jsonplaceholder.typicode.com/posts"
.httpGet().responseObject(Post.Deserializer()){
__,__, result ->
val postsArray = result.component1()
}
あるいは、Gsonの内部デシリアライザを使用するresponseObject <T>を介して:
"https://jsonplaceholder.typicode.com/posts/1"
.httpGet().responseObject<Post> { __, __, result ->
val post = result.component1()
}
一方、
Gson()。toJson()
を使用して直列化することができます。
val post = Post(1, 1, "Lorem", "Lorem Ipse dolor sit amet")
val (request, response, result)
= Fuel.post("https://jsonplaceholder.typicode.com/posts")
.header("Content-Type" to "application/json")
.body(Gson().toJson(post).toString())
Content-Type
を設定することが重要です。そうしないと、サーバーは別のJSONオブジェクト内のオブジェクトを受け取る可能性があります。
最終的には、同様の方法で、Jackson、Moshi、Forgeなどの依存関係を使用して実行できます。
7. ファイルをダウンロードしてアップロードする
Fuelライブラリには、ファイルをダウンロードおよびアップロードするために必要なすべての機能が含まれています。
7.1. ダウンロード
download()メソッドを使用すると、ファイルを簡単にダウンロードして、
destination()
lambda
__によって返されるファイルに保存できます。
Fuel.download("http://httpbin.org/bytes/32768")
.destination { response, url ->
File.createTempFile("temp", ".tmp")
}
-
プログレスハンドラ付きのファイルをダウンロードすることもできます** :
Fuel.download("http://httpbin.org/bytes/327680")
.progress { readBytes, totalBytes ->
val progress = readBytes.toFloat()/totalBytes.toFloat()
//...
}
7.2. アップロードする
同様に、
upload()
メソッドを使用してファイルをアップロードできます。
source()
メソッドでアップロードするファイルを示します。
Fuel.upload("/upload").source { request, url ->
File.createTempFile("temp", ".tmp")
}
upload()
はデフォルトでPOST動詞を使用します。別のHTTP動詞を使用したい場合は、それを指定できます。
Fuel.upload("/upload", Method.PUT).source { request, url ->
File.createTempFile("temp", ".tmp")
}
さらに、ファイルのリストを受け取る
sources()
メソッドを使用して複数のファイルをアップロードできます。
Fuel.upload("/post").sources { request, url ->
listOf(
File.createTempFile("temp1", ".tmp"),
File.createTempFile("temp2", ".tmp")
)
}
最後に、__InputStreamからデータのBLOBをアップロードできます。
Fuel.upload("/post").blob { request, url ->
Blob("filename.png", someObject.length, { someObject.getInputStream() })
}
8 RxJavaとコルーチンのサポート
FuelはRxJavaとCoroutinesのサポートを提供しています。これは非同期のノンブロッキングコードです。
RxJava
はhttp://reactivex.io[Reactive Extensions]のJava VM実装で、非同期およびイベントベースのプログラムを作成するためのライブラリです。
Observer pattern
を拡張してデータ/イベントのシーケンスをサポートし、同期、スレッドセーフ、および並行データを気にせずに宣言的にシーケンスを組み合わせて作成できる演算子を追加構造
Kotlinのコルーチン
は、軽量のスレッドのようなものです。そのため、並行して実行し、相互に待機して通信することができます。とても安い;私たちはそれらの何千ものものを作成することができ、そして記憶に関してはほとんど支払うことができません。
8.1. RxJava
RxJava 2.xをサポートするために、Fuelは6つの拡張機能を提供します。
fun Request.rx__response(): Single<Pair<Response, Result<ByteArray, FuelError>>>
fun Request.rx__responseString(charset: Charset): Single<Pair<Response, Result<String, FuelError>>>
fun <T : Any> Request.rx__responseObject(deserializable: Deserializable<T>):
Single<Pair<Response, Result<T, FuelError>>>
fun Request.rx__data(): Single<Result<ByteArray, FuelError>>
fun Request.rx__string(charset: Charset): Single<Result<String, FuelError>>
fun <T : Any> Request.rx__object(deserializable: Deserializable<T>): Single<Result<T, FuelError>>
すべての異なるレスポンスタイプをサポートするために、各メソッドは異なる
Single <Result <>> .
を返します。
Request
を介してより関連性のあるメソッドを呼び出すことで、「Rx」メソッドを簡単に使用できます。
"https://jsonplaceholder.typicode.com/posts?id=1"
.httpGet().rx__object(Post.Deserializer()).subscribe{
res, throwable ->
val post = res.component1()
}
8.2. コルーチン
coroutinesモジュールで、** Fuelはコルーチンの中に応答をラップしてその結果を処理するための拡張機能を提供します。
コルーチンを使用するために、同様のAPIが利用可能になります。例えば、
responseString()
は
awaitStringResponse()になりました:
runBlocking {
Fuel.get("http://httpbin.org/get").awaitStringResponse()
}
awaitObject()、awaitObjectResult()、またはawaitObjectResponse()を使用して、
String
または
ByteArray
(
awaitByteArrayResponse())__以外のオブジェクトを処理するための便利なメソッドも提供されます。
runBlocking {
Fuel.get("https://jsonplaceholder.typicode.com/posts?id=1")
.awaitObjectResult(Post.Deserializer())
}
Kotlinのコルーチンは実験的なものであることを忘れないでください。
9 APIルーティング
大事なことを言い忘れましたが、ネットワークルートを処理するために、FuelはRouterデザインパターンを実装することによってサポートを提供します。
ルーターパターンでは、呼び出されたエンドポイントに応じて適切なHTTP動詞、パス、パラメーター、およびヘッダーを設定するためのメソッドの組み合わせを提供する
FuelRouting
インターフェースを使用して、APIの管理を集中化できます。
インターフェースは私達のルーターを設定することが可能である5つの特性を定義します:
sealed class 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 = "https://jsonplaceholder.typicode.com"
override val method: Method
get() {
return when(this) {
is PostRoutingAPI.posts -> Method.GET
is PostRoutingAPI.comments -> Method.GET
}
}
override val path: String
get() {
return when(this) {
is PostRoutingAPI.posts -> "/posts"
is PostRoutingAPI.comments -> "/comments"
}
}
override val params: List<Pair<String, Any?>>?
get() {
return when(this) {
is PostRoutingAPI.posts -> listOf("userId" to this.userId)
is PostRoutingAPI.comments -> listOf("postId" to this.postId)
}
}
override val headers: Map<String, String>?
get() {
return null
}
}
どのHTTP動詞を使用するかを選択するために、
method
プロパティがあります。同様に、適切なパスを選択するために
path
プロパティをオーバーライドできます。
さらに
params
プロパティを使用して、リクエストのパラメータを設定する機会があります。HTTPヘッダーを設定する必要がある場合は、それは関係のあるプロパティをオーバーライドして行うことができます。
したがって、
request()
メソッドを使用して、チュートリアル全体で使用したのと同じ方法で使用します。
Fuel.request(PostRoutingAPI.posts("1",null))
.responseObject(Post.Deserializer()) {
request, response, result ->
//response handling
}
Fuel.request(PostRoutingAPI.comments("1",null))
.responseString { request, response, result ->
//response handling
}
10結論
この記事では、Kotlin用のFuel HTTPライブラリと、どんなユースケースにも役立つその便利な機能を紹介しました。
このライブラリは絶えず進化しているので、新しい機能を追跡するためにhttps://github.com/kittinunf/Fuel[GitHub]リポジトリをご覧ください。
いつものように、チュートリアルで言及されたコードスニペットの全ては私達のhttps://github.com/eugenp/tutorials/tree/master/core-kotlin[GitHubレポジトリ]にあります。