16
8

More than 3 years have passed since last update.

kotlin + coroutines + Okhttp3 を使って同期/非同期対応のHTTPクライアントを作ってみた

Last updated at Posted at 2021-05-19

動機

  • ググっても簡単に使えるHTTPクライアントが見つからなかったので、Okhttp3とcoroutinesを使って作ってみました

HTTPクライアント

import kotlinx.coroutines.*
import okhttp3.FormBody
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody
import org.json.JSONObject
import java.io.IOException

class HttpClient {
    companion object {
        val instance = OkHttpClient()

        fun get(url: String): JSONObject {
            val request = Request.Builder()
                    .url(url)
                    .build()
            val response = instance.newCall(request).execute()
            return JSONObject(response.body?.string().orEmpty())
        }

        fun getAsync(url: String, onFailed: (Exception) -> Unit = {}, onSuccess:  (JSONObject) -> Unit = {}) {
            GlobalScope.launch(Dispatchers.Main) {
                try {
                    coroutineScope {
                        async(Dispatchers.Default) { get(url) }.await().let {
                            onSuccess(it)
                        }
                    }
                } catch (e: Exception) {
                    onFailed(e)
                }
            }
        }

        fun post(url: String, params: Map<String, String>? = null): JSONObject {
            val formBuilder = FormBody.Builder()
            params?.forEach { (name: String, value: String) -> formBuilder.add(name, value) }
            val requestBody: RequestBody = formBuilder.build()
            val request = Request.Builder()
                    .url(url)
                    .post(requestBody)
                    .build()
            val response = instance.newCall(request).execute()
            if (!response.isSuccessful) throw IOException("Unexpected code $response");
            return JSONObject(response.body?.string().orEmpty())
        }

        fun postAsync(url: String, params: Map<String, String>? = null, onFailed: (Exception) -> Unit = {}, onSuccess:  (JSONObject) -> Unit = {}) {
            GlobalScope.launch(Dispatchers.Main) {
                try {
                    coroutineScope {
                        async(Dispatchers.Default) { post(url, params) }.await().let {
                            onSuccess(it)
                        }
                    }
                } catch (e: Exception) {
                    onFailed(e)
                }
            }
        }
    }
}

使い方

同期的にGET

val response = HttpClient.get("https://hoge/api/fuga")
Log.i(TAG, "同期的にGET:${response}")

非同期でGET

HttpClient.getAsync("https://hoge/api/fuga"){
    Log.i(TAG, "非同期でGET:${it}")
}

同期的にPOST

val params = mapOf(
    "name" to "ryota",
    "job" to "neet"
)
val response = HttpClient.post("https://hoge/api/fuga", params)
Log.i(TAG, "同期的にPOST:${response}")

非同期でPOST

val params = mapOf(
    "name" to "ryota",
    "job" to "neet"
)
HttpClient.postAsync("https://hoge/api/fuga", params) {
    Log.i(TAG, "非同期でPOST:${it}")
}

非同期でPOST + エラーハンドリング

val handleError: (Exception) -> Unit = {
    e -> Log.e(TAG, "エラー:${e}")
}
HttpClient.postAsync("https://hoge/api/fuga", params, onFailed = handleError) {
    Log.i(TAG, "非同期でPOST + エラーハンドリング:${it}")
}

使いやすいようにカスタマイズして使って下さい。

16
8
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
8