0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【初心者向け】Retrofit入門:REST APIとの通信をまとめてみた

Posted at

【Android/Kotlin】RetrofitとREST APIの仕組みをまとめる(基礎編)

こんにちは。この記事では、Androidアプリ開発で頻出の「Retrofit」と「REST API」の関係や使い方について、自分の学習をまとめたものになります。


通信に関して復習

image.png

登場人物は主にクライアントとサーバーの2人です。
この2人のやり取り(通信)における決まり事がRESTです。
次にRESTについて詳しく説明していきます。


RESTとは?

REST(Representational State Transfer)とは、Webサービスの設計原則の1つで、「HTTPの仕組みを最大限に活かして、データにアクセスするためのルール」です。
RESTは広く一般的に用いられています。例えば検索やゲームの時など

RESTの特徴

  • URLでリソース(データ)を一意に表現
    ⇒データの保存場所をURLが担う(住所みたいな)

  • HTTPメソッドを使い分ける

    操作 メソッド
    読み込み GET
    作成 POST
    更新 PUT
    削除 DELETE
  • ステートレス(サーバーがクライアントの状態を保持しない)
    ⇒サーバーに依存しない。つまり、サーバー側でサーバーを横に増やしたり変化が起きてもクライアントは何もしなくていい(柔軟)

クライアント→サーバー
このデータが欲しい⇒(このURL先のデータがGETしたい)


Retrofitとは?

Retrofitは、Square社が提供する「REST API通信を簡単にしてくれるKotlin/Java用のライブラリ」です。

Retrofitがやってくれること

  • APIリクエストの送信(GET, POST など)
  • サーバーからのレスポンス(JSONなど)をKotlinオブジェクトに変換
  • 必要なコードを自動生成
  • 非同期処理(Coroutines対応)

image.png

Retrofitはクライアントの代わりにサーバーとやり取りしてくれる便利な仲介者
ここでいう翻訳とは、データはJSON形式やXML形式で管理されていることがほとんどであるため、それらを人間が読みやすい形(Stringなど)に変換することを意味します。


コードでみるRetrofit

"想定するJSONデータ"
{
  "id": 1,
  "name": "Taro Yamada",
  "email": "taro@example.com"
}
ディレクトリ構造
└── com.example.retrofitexample/
    ├── model/
    │   └── User.kt⇒シリアル化
    ├── network/
    │   ├── ApiService.kt⇒APIのインターフェースの定義
    │   └── RetrofitClient.kt⇒クライアント側での翻訳等
    ├── viewmodel/
    │   └── UserViewModel.kt⇒状態を管理
    └── MainActivity.kt⇒UI管理

詳細

それでは順番にコードの中身を見てみましょう。
まずはmodel/User.ktに関して

package com.example.retrofitexample.model

import kotlinx.serialization.Serializable

@Serializable
data class User(
    val id: Int,
    val name: String,
    val email: String
)

ここではシリアル化を行っています。
シリアル化とは、ユーザーの入力などをKotlinのオブジェクトとして保持し、それをサーバーに送信できるようにJSON形式へ変換する処理のことです。

続いてnetwork/ApiService.ktに関してです。

package com.example.retrofitexample.network

import com.example.retrofitexample.model.User
import retrofit2.http.GET
import retrofit2.http.Path

interface ApiService {
    @GET("users/{id}")
    suspend fun getUser(@Path("id") id: Int): User
}

ここでは、Retrofitを使ってAPIのインターフェースを定義しています。
つまりAPIの設計書を定義したようなことです。
ここで定義した関数は、Retrofitのクライアントによって自動的に実装されるため、他のクラス(ViewModelなど)から簡単にAPIを呼び出すことができるようになります。

続いてnetwork/RetrofitClientについてです。

package com.example.retrofitexample.network

import kotlinx.serialization.json.Json
import okhttp3.MediaType.Companion.toMediaType
import retrofit2.Retrofit
import retrofit2.converter.kotlinx.serialization.asConverterFactory

object RetrofitClient {
    private val retrofit = Retrofit.Builder()
        .baseUrl("https://example.com/api/")
        .addConverterFactory(Json.asConverterFactory("application/json".toMediaType()))
        .build()

    val api: ApiService = retrofit.create(ApiService::class.java)
}

このRetrofitClientretrofitインスタンスを1回だけ生成し保持するシングルトンオブジェクトです。
Builder()build()で挟んで、その間に何をするのかをチェーンメソッド形式で書いていきます。
ここでは、addConverterFactory()を使って JSONとKotlinデータクラスの相互変換(シリアル化/デシリアル化) を行うためのコンバーターを追加しています。

最後にviewmodel/UserViewModel.ktに関してです。

package com.example.retrofitexample.viewmodel

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.retrofitexample.model.User
import com.example.retrofitexample.network.RetrofitClient
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch

sealed interface UserUiState {
    data class Success(val user: User): UserUiState
    object Loading : UserUiState
    object Error : UserUiState
}

class UserViewModel : ViewModel() {
    private val _uiState = MutableStateFlow<UserUiState>(UserUiState.Loading)
    val uiState: StateFlow<UserUiState> = _uiState

    fun fetchUser(id: Int) {
        viewModelScope.launch {
            try {
                val user = RetrofitClient.api.getUser(id)
                _uiState.value = UserUiState.Success(user)
            } catch (e: Exception) {
                _uiState.value = UserUiState.Error
            }
        }
    }
}

ここでは状態管理がされています。具体的には、コードの冒頭でSuccessLoadingErrorと明記して状態を定義します。
また、UserViewModelクラス内のfetchUser関数ではviewModelScope.launch を使って非同期にAPIを呼び出し、取得結果に応じて状態を更新しています。
これにより、UIは状態に応じた表示切替が可能になります。

最後に

これらはhttps://example.com/api/のような架空のURLを用いていますが、

この公式のドキュメントに沿った内容となっています。良ければこのサイトから本格的に手を動かしながら学習してみてください。

通信に関して概ね理解が深まったと感じています。今後はより発展した内容や、DBに関しても広げていきたいです。

0
0
0

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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?