Retrofit2とOkhttp3を使ったAPI開発

RetrofitとOkHttpを使ってWebAPIを呼び出します。

今回利用するAPIはQiitを使います
[https://qiita.com/api/v2/items?page=1&per_page=20](https://qiita.com/api/v2/items?page=1&per_page=20)

極力コメントアウトして、何が書かれているか残しときました。

#RetrofitとOkhttpとは
RetrofitはOkHttpラッパーでありHTTPクライアントを実装する際によく利用されます。
最近のサービスで通信が必要な処理を実装する時はほとんど使われているそうです。

HTTP通信を実装する際にコールバックの処理を書きやすくします。

#手順
1.gradleとManifest
2.interface
3.Model
4.クライアント
5.呼び出し

#1.gradleとManifest

Gradle Scriptsのbuild.gradle(Module.app)の所にライブラリ導入

```build.gradle
dependencies{
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'

   //書き方として以下もある
   //def retrofitVersion = '2.9.0'
   //implementation 'com.squareup.retrofit2:retrofit:$retrofitVersion'
   //implementation 'com.squareup.retrofit2:converter-gson:$retrofitVersion'
}
```

今回ネットワークを利用した通信なのでAndroidManifestに以下を記入

```app/src/main/AndroidManifest.xml
<manifest xmlns:android=
~省略
//以下を記入
<uses-permission android:name="android.permission.INTERNET"/>

    <application
//~省略

```




#2.interface
今回は HTTP の GET メソッドを使うため@GET をつけました。

```ApiService.kt
interface ApiService {

    //パラメータの前までをここに書く
    @GET("api/v2/items")
    //呼び出す際に必要なリクエストURLのパラメータの設定
    fun apiDemo(
        @Query("page") page: Int,
        @Query("par_page") perPage: Int
    ): Call<List<QiitResponse>>
}
```

#3.Model
APIから取り出したいデータを格納するデータクラス

```QiitResponse.kt
//後に欲しいデータを取得する際に必要となる箱
data class QiitResponse(
    val url: String?,
    val title: String?,
    val user: User?
)

//階層が分かれている時は分ける
data class User(
    val id: String?
)

```

実際に表示する際に必要となるクラス

```Model.kt
class Model {
    var title: String? = null
    var id: String? = null
    var url: String? = null
}
```


#4.クライアント


```Client.kt
    //Clientを作成
    val httpBuilder: OkHttpClient.Builder get() {
        //httpClinetのBuilderを作る
        val httpClient = OkHttpClient.Builder()
        //create http client　headerの追加
            httpClient.addInterceptor(Interceptor { chain ->
                val original = chain.request()
                val request = original.newBuilder()
                    .header("Accept", "application/json")
                    .method(original.method(), original.body())
                    .build()
                //proceedメソッドは再びパーミッション許可ダイアログを表示してその結果を返します
                var response = chain.proceed(request)

                return@Interceptor response
            })
            .readTimeout(30, TimeUnit.SECONDS)

        //log
        val loggingInterceptor = HttpLoggingInterceptor()
        loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
        httpClient.addInterceptor(loggingInterceptor)

        return httpClient
    }

     //繋ぎこみ
     fun createService(): ApiService {
          var client = httpBuilder.build()
          var retrofit = Retrofit.Builder()
              .baseUrl("https://qiita.com/")//基本のurl設定
              .addConverterFactory(GsonConverterFactory.create())//Gsonの使用
              .client(client)//カスタマイズしたokhttpのクライアントの設定
              .build()
          //Interfaceから実装を取得
          var API = retrofit.create(ApiService::class.java)

          return API
      }
```

#5.呼び出し
```a.kt
//データリストに保存し、そのデータの取得
    fun fetchAllUserData(): List<Model> {

        val dataList = mutableListOf<Model>()
        //リクエストURl作成してデータとる パラメータの引数の設定も行う
        Retrofit.createService().apiDemo(page = 1, perPage = 20).enqueue(object : Callback<List<QiitResponse>> {

            //非同期処理
            override fun onResponse(call: Call<List<QiitResponse>>, response: Response<List<QiitResponse>>) {
                Log.d("TAGres","onResponse")

                //ステータスコードが200：OKなので、ここではちゃんと通信できたよ
                if (response.isSuccessful) {
                    response.body()?.let {
                        for (item in it) {
                            val data: Model = Model().also {
                                //取得したいものをAPIから手元のリスト（Model）に
                                it.title = item.title
                                it.url = item.url
                                it.id = item.user!!.id
                            }
                            //取得したデータをModelに追加
                            dataList.add(data)
                        }
                        //今回recyclerViewを利用しているが、これを書かないと先に画面の処理が終えてしまうので表示されなくなります。
                        recyclerView.adapter?.notifyDataSetChanged()
                    }
                } else {
                }
            }
            override fun onFailure(call: Call<List<QiitResponse>>, t: Throwable) {
                Log.d("TAGres","onFailure")
            }
        })
        return dataList
    }
```

Okhttpを利用するとonResponseとonFailureでコールバックを用いた非同期通信が利用できる。



#終わりに
初めてのAPIの周りなのでもっとうまく書ける方法はあると思いますが、自分がわかるようにまとめました。
1つの参考資料になってくれたら嬉しいです。
また、何か違う部分ありましたら、コメントいただけると嬉しいです。

次はMoshi、RxJavaを取り入れてみたいです。