前回のお話でREST APIを気軽に確認する内容を書きましたが、今回は実際にスマホアプリ内でREST APIのやりとりを行う方法をまとめます。
以前はOkHttpというライブラリを使うことが多く、現在もそれが主流になりますが、今回はkotlinで使えるRetrofitと呼ばれるライブラリを使っていきましょう
インストール
通信するので当然アプリ側にインターネット接続の設定をする必要があります。
1 2 3 4 5 6 7 |
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="[パッケージ名]"> <uses-permission android:name="android.permission.INTERNET" /> ← 追加 </manifest> |
/app/build.gradleにRetrofitを書きましょう。
JSONでやりとりするのでGsonも入れましょう。
1 2 3 |
def retrofit_version = '2.6.2' implementation "com.squareup.retrofit2:retrofit:$retrofit_version" implementation "com.squareup.retrofit2:converter-gson:$retrofit_version" |
バージョンは2022.08時点ですが、多分3年くらい変わってない気がします…
これで簡単にsyncを押すと利用可能です。
使い方
使い方と言ってもREST APIの基本的な設定(メソッドやヘッダーなど)をInterface、データの構造をクラス化して、各画面で呼び出す感じとなります。名前は何でもいいですが、こんな感じで各ファイルにまとめたいと思います。
Interface | ApiService.kt |
---|---|
Model | ApiModel.kt |
Fragment | MainFragment.kt |
GETの場合
例として架空のREST APIを用意します。内容 | メンバー情報取得 | ||
---|---|---|---|
詳細 | メンバー情報を取得する | ||
URI | /gray/ | ||
METHOD | GET | ||
認証 | Authorization: Bearer ais7Uki8d300ibGhQOee51die | ||
パラメータ | No parameters | ||
レスポンス |
|
こんな感じです。
認証用のトークンをheaderに設定して、GETで叩くとメンバー情報を取得できるという感じですね。
まずはデータクラスをまとめましょう。
今回はレスポンスの値を渡すので、ApiModel.ktに以下のように定義します。
1 2 3 4 5 6 7 8 9 10 11 |
class ResponseMembers( val code: Int, val message: String, val members: ArrayList<Members>, ) class Members( val id: Int, val name: String, val type: String, ) |
[members]は複数の配列で来るので、Membersの配列として定義します。
定義ができたところで、Interfaceに書いちゃいましょう。
1 2 3 4 5 6 7 |
/* * メンバー情報を取得 */ @Headers("User-Agent:" + user_agent) @GET("users/") fun getMembers(@Header("Authorization") token: String): Call<ResponseMembers> |
@Headersには今回UserAgentを設定してます。
@GETや@POSTや@PUT、@DELETEもあるので簡単にメソッドを設定できますね。
getMembers関数を定義してます。
引数は認証用のtokenを渡すことでHeaderに記載されます。
戻り値は先ほど定義した[ResponseMembers]ですね。
これで設定完了です。
実際に呼び出す場合は
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
val token = "sdasdasdsa" val service = Retrofit.Builder() .baseUrl("https://hoge.api.net/") .addConverterFactory(GsonConverterFactory.create()) .build() .create(ApiService::class.java) thread { try { val response = service.getMembers(token).execute() // レスポンスコード if(response.code() == 200){ response.body()?.let{ val members: ArrayList<Members> = it.members members.forEach { member-> Log.d("test", "id:"+member.id) Log.d("test", "name:"+member.name) Log.d("test", "type:"+member.type) } } }else{ response.errorBody()?.let { // エラー時の処理 } } }catch (e:HttpException){ Log.e("text", e.localizedMessage) } } |
簡単な実装ですが、これで簡単に取得できます。
シンプルで簡単にできますよね。
ただ、TextViewに反映しようとするとメインスレッドでないと怒られるのでそこだけ注意してください
POSTの場合
POSTの場合も実は簡単です。内容 | メンバー情報新規登録 | ||
---|---|---|---|
詳細 | メンバー情報を新規登録する | ||
URI | /gray/ | ||
METHOD | POST | ||
認証 | Authorization: Bearer ais7Uki8d300ibGhQOee51die | ||
パラメータ |
|
||
レスポンス |
|
モデルクラスを設定しましょう
1 2 3 4 5 6 7 8 9 10 |
class ResponseApi( val code: Int, val message: String, val member: Members, ) class PostMember( val name: String, val type: String, ) |
インターフェースです
1 2 3 4 5 6 7 |
/* * メンバー情報を新規登録 */ @Headers("User-Agent:" + user_agent) @POST("users/") fun postMember(@Header("Authorization") token: String, @Body post: postmember): Call<ResponseApi> |
取得時とあまり変わりません。変わった点はメソッドがPOSTになったのと、@Bodyでデータクラスを渡すところですね。
それでは実装しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
val postData = PostMember(name = "omiokurigeinin-shinichi", type = "guiter") val token = "sdasdasdsa" val service = Retrofit.Builder() .baseUrl("https://hoge.api.net/") .addConverterFactory(GsonConverterFactory.create()) .build() .create(ApiService::class.java) thread { try { val response = service.postMember(token, postData).execute() // レスポンスコード if(response.code() == 200){ }else{ response.errorBody()?.let { // エラー時の処理 } } }catch (e:HttpException){ Log.e("text", e.localizedMessage) } } |
GETとの違いは引き渡す値をまとめて引数に渡してますね。
これだけで簡単にPOST通信することが可能です。
PUT通信の場合
PUTは主に更新系で使うメソッドですが、この場合もPOSTとよく似た形です。内容 | メンバー情報の変更 | ||
---|---|---|---|
詳細 | メンバー情報を変更する | ||
URI | /gray/{id} | ||
METHOD | PUT | ||
認証 | Authorization: Bearer ais7Uki8d300ibGhQOee51die | ||
パラメータ |
|
||
レスポンス |
|
変更するIDをURIにつけてPUTします。 例) /gray/1
データクラスは既存のものを流用できるのでInterfaceを作ります。
1 2 3 4 5 6 7 |
/* * メンバー情報を変更 */ @Headers("User-Agent:" + user_agent) @POST("users/{id}") fun putMember(@Header("Authorization") token: String, @Path("id") id: Int, @Body post: postmember): Call<ResponseApi> |
putMember関数の第二引数に変更するIDを渡します。
実装は以下のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
val postData = PostMember(name = "Hisashi", type = "guiter") val id = 3 val token = "sdasdasdsa" val service = Retrofit.Builder() .baseUrl("https://hoge.api.net/") .addConverterFactory(GsonConverterFactory.create()) .build() .create(ApiService::class.java) thread { try { val response = service.putMember(token, id, postData).execute() // レスポンスコード if(response.code() == 200){ }else{ response.errorBody()?.let { // エラー時の処理 } } }catch (e:HttpException){ Log.e("text", e.localizedMessage) } } |
これでPUTが行えます。
今回は取り上げませんがDELETEも同様な感じで実装が可能です。
まとめ
油断すると新しいトレンドがどんどん出てくるスマホアプリ開発ですが、Retrofitを使うと、わかりやすく実装できるので、非常に楽ですね。次はSwiftでもREST APIの使い方の紹介ができればいいかなと思います。
個人的にはViewModelを使っていきたいのでそっちを勉強がてら投稿するかもしれませんが…