📝

sealed class

に公開

はじめに

sealed class を初めて使ってみた内容を記事にしました。


背景

OkHttp3を使ったAPIリクエストのレスポンスを、「成功」と「失敗」で明確に分けて扱いたい場合、Kotlinのsealed classを使う設計が非常に便利です。このアプローチにより、レスポンスの管理が簡潔で明確になります。

この記事では、sealed classを使ってレスポンスを処理する方法を解説します。


実装例

1. sealed classの定義

以下のように、ApiResponseというsealed classを定義します。

sealed class ApiResponse<out T> {
    data class Success<out T>(val data: T) : ApiResponse<T>()
    data class Error(val errorCode: Int, val message: String? = null) : ApiResponse<Nothing>()
}
  • Successクラスは、成功した場合のデータをラップします。
  • Errorクラスは、エラーコードとエラーメッセージを保持します。

2. APIクライアントの実装

OkHttp3を使ったAPIリクエストをラップするApiClientクラスを実装します。

import okhttp3.*
import java.io.IOException

class ApiClient(private val client: OkHttpClient) {

    fun <T> makeRequest(
        request: Request,
        responseParser: (String) -> T?,
        callback: (ApiResponse<T>) -> Unit
    ) {
        client.newCall(request).enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
                callback(ApiResponse.Error(500, e.message))
            }

            override fun onResponse(call: Call, response: Response) {
                if (response.isSuccessful) {
                    val body = response.body?.string()
                    val parsedData = body?.let { responseParser(it) }
                    if (parsedData != null) {
                        callback(ApiResponse.Success(parsedData))
                    } else {
                        callback(ApiResponse.Error(400, "Parsing error"))
                    }
                } else {
                    callback(ApiResponse.Error(response.code, response.message))
                }
            }
        })
    }
}

ポイント

  • 成功時にはApiResponse.Successを返します。
  • エラー時にはApiResponse.Errorを返し、HTTPステータスコードやエラーメッセージを含めます。

3. 使用例

実際にApiClientを使ってAPIリクエストを行う例です。

fun main() {
    val client = OkHttpClient()
    val apiClient = ApiClient(client)

    val request = Request.Builder()
        .url("https://api.example.com/data")
        .build()

    apiClient.makeRequest(
        request,
        responseParser = { body -> body }, // ボディをそのまま返す例
    ) { response ->
        when (response) {
            is ApiResponse.Success -> {
                println("Success: ${response.data}")
            }
            is ApiResponse.Error -> {
                println("Error: Code=${response.errorCode}, Message=${response.message}")
            }
        }
    }
}

なぜsealed classが便利なのか?

  1. 型安全: 成功と失敗のケースを明確に分けられるため、適切にハンドリングできます。
  2. 拡張性: 必要に応じて新しいケース(例: Loading)を追加できます。
  3. 簡潔な記述: 呼び出し側でwhenを使って分岐処理を簡単に記述可能。

Kotlin標準のResult

Kotlin標準で Result というものが用意されている...!!

   result.fold(
       onSuccess = { data -> println("Success: $data") },
       onFailure = { error -> println("Error: ${error.message}") }
   )

まとめ

sealed classを使うことで、OkHttp3のレスポンスをわかりやすく管理できるようになります。特に、成功と失敗を型で区別したい場合に最適です。

もっと早く知りたかった... ^^;


参考文献

Discussion