Retrofit2 + Kotlin + 楽天商品検索APIを用いて検索結果をAndroidアプリに表示してみる

はじめに

 今日はタイトルにもあるようにRetrofit2というライブラリを用いてKotlinで制作しているAndroidアプリに、楽天商品検索APIを叩いてその結果を表示してみるということをやっていきます。

読者の対象は以下になります。

  • API通信をしたことがないけどAndroid開発はやっている人
  • Retrofit2を使ったことがない人、もしくはこれから使ってみたい人
  • 楽天のAPIを使ってみたい人

ちなみに、僕は楽天の中の人ではありません。

Retrofit自体は一年以上前から触っていたのですが、楽天APIとの連携は初めてだったので、単純に学んだことの復習としても残しておこうかなと思って書いてます。

Retrofit2とは?

先駆者の説明がすでにあったので、以下の通りです。

Retrofitは型安全なHTTPクライアントライブラリで、JavaやKotlinやAndroidからできるだけ楽しくREST APIを使えるようにするために作られました。これを使うとBacklog APIからJSONデータを読み出したり利用したりするのがだいぶ簡単になります。 Retrofit 2で使うBacklog APIとは–Kotlinで作るAndroidアプリの場合 | ヌーラボ

公式はこちら

Retrofit2

REST APIについてはこちらを参照してください

REST API

Retrofitを既存のAndroidアプリに導入する

Retrofitをまずはapp gradleに記述することで使えるようにしましょう!

Androidアプリのプロジェクトの中のbuild.gradleファイルに以下を追加してください。

compile 'com.squareup.retrofit2:retrofit:2.4.0'
compile 'com.squareup.retrofit2:converter-gson:2.4.0'

2018年3月現在では最新のバージョンが2.4.0になります。

導入はこれだけです!

一応通信を行うので、AndroidManifestの中に以下の一文を追加してください。

<uses-permission android:name="android.permission.INTERNET" />

場所はのタグの中ならOKです。

 

これを追加しないと通信の接続ができなくてシステムエラーを吐いてクラッシュするので忘れずに追加してください。

今回は、proguardは追加しませんが、リリース前には追加する必要があったはずです。今回は割愛します。

次に楽天のAPIを使えるようにする

 楽天の商品検索APIを使うのでまずはそのための準備を行いましょう。

「楽天ウェブサービス」とまずは検索してください。

多分トップの方に出てくるリンクをクリックすると以下のようなサイトが表示されると思います。

ここから右上の方にある「アプリID発行」を選択して楽天ログイン後下記のような画面が出てくるので、必要事項の記入を行ってください。

アプリ名は任意の名前を付けてください、アプリURLは適当でいいですのでブログのリンクなどでもよいと思います。実際にリリースしたら後で変更もできます。

登録が終わると以下のような画面が出てきます。

当たり前ですが、黒くしている部分は他人に見せてはいけないので気を付けてください。

この黒い部分の情報を使って楽天APIを実際に叩いてデータを取ってくることができます。

作ったアプリIDを使ってレスポンスを確かめてみる

実際に楽天APIを用いてレスポンスを確認してみましょう!

 

今回は、Postmanというアプリを使います。

開発の現場では実際のレスポンスがどのように返ってきているのかでしばしば用いられるアプリケーションです。

まだ入っていない人は下記リンクからPostmanを入れてください。

Postman

ダウンロード後に立ち上げると以下のような画面が出てきます。

このPostmanを使ってレスポンスの確認をしてみましょう

 

以下の楽天のAPIの詳細を見ると

楽天ウェブサービス: 楽天商品検索API(version:2017-07-06) | API一覧

リクエストURL https://app.rakuten.co.jp/services/api/IchibaItem/Search/20170706?[parameter]=[value]… ※JSONP形式は、JSON形式で入力パラメーターにcallbackを指定することで出力されます。 フィールド名keyword, sortに対応する[value]はUTF-8でURLエンコードされている必要があります。 (リクエストURL全体をエンコードするのではなく、[value]部分を個別にエンコードしてください。) たとえば、「福袋」という検索キーワードで検索し、結果を価格が安い順に並べたい(sort=+itemPrice)場合のリクエストURLは下記になります。(実際には改行せずに1行につなげてリクエストしてください。) https://app.rakuten.co.jp/services/api/IchibaItem/Search/20170706? applicationId=[アプリID] &keyword=%E7%A6%8F%E8%A2%8B &sort=%2BitemPrice ※短い時間の間に大量に、同一のリクエストURLへアクセスすると、一定時間利用できなくなる場合がございます。テストの際にはご注意ください。

と、書かれています。Postmanとさっき作成したアプリIDを使ってレスポンスを確かめてみましょう。

 

下記の画面にて矢印のところに、

https://app.rakuten.co.jp/services/api/IchibaItem/Search/20170706?/

を入力してください。

次に、下記の画像のようにParamsをタップするとkeyとvalueを入れるフォームが出てくると思います。

その中で以下のようにkeyとvalueを設定してください

今回は、「福袋」というKeyWordで検索した際の結果のレスポンスを確認します。

 

keywordは任意の文字列で良いです。

Androidアプリに組み込むならSearchViewで組み合わせてRxを使って非同期にAPIを叩いて情報を取得して表示するのもアリだと思います

applicationIdは下記の矢印のところの値をコピーして入れてください。

これは各々違うのでコピーした値を入れて、PostmanのSendをクリックしましょう。

 

そうすると以下のようなレスポンスが返ってきます。

これで、楽天のAPIを叩いて商品情報のレスポンスを確認することができました!

今回は、検索結果の総合数のcountをアプリに表示するところまでですので、

今までやってきたことをもとにRetrofit2を使ってAndroidアプリに表示してみましょう!

まずはbaseUrlをSettingFileに記述する

アプリの設定ファイルを作成して、そこにbaseUrlを記述しましょう

僕はいま、個人アプリをリリースしようと作成しようとしているので、その作成しているアプリをもとに説明していこうと思います。

 

下記のような設定ファイルを作成しましょう。

どこのディレクトリに作ってもいいと思います。

class MakePuraConfig(application: Application) {

private val prefFileName = "jp.com.zukkey.makepura"
private val pref = application.getSharedPreferences(prefFileName, Context.MODE_PRIVATE)

/*
* 楽天商品検索APIを利用するために必要なもの
* API詳細ページ
* https://webservice.rakuten.co.jp/api/ichibaitemsearch/
*/
val rakutenBaseUrl = "https://app.rakuten.co.jp/services/"
val applicationId = "hogehoge"
val affiliateId = "hogehoge"
val formatVersion = 2


}

hogehogeのところは楽天の管理画面のところから各々書いてください。

baseUrlを僕は、https://app.rakuten.co.jp/services/api/IchibaItem/Search/20170706? の中の https://app.rakuten.co.jp/services/ に設定しました。

 

RetrofitではこのbaseUrlの後に続いてGETするUrlを定義するので自分が必要と思うAPIによってbaseUrlを適宜変えてください。今回、いろいろなAPIを利用することを考えて僕はこの部分をbaseUrlにしました。

なお、さいごに「/」がないとエラーを吐くので気をつけてください。

 

一応コメントを残してありますが、必要なければ基本的に書かなくていいと思います。

 

脱線しますが、コメントやプログラミングのお作法に関しては、下記の本を読むといいと思います。僕は一番初めの現場に入る前に買って読みましたが、今なお度々注意されたり勉強になったりすることが多いので目を通しておくといいと思います。

リーダブルコード より良いコードを書くためのシンプルで実践的なテクニック

APIを叩くinterfaceを作成する

 僕はMakePuraという商品の相場を見るアプリを今作成しているので、下記のようにRetrofitを使ってAPIのinterfaceを作成しました。

interface MakePuraApi {
    @GET("api/IchibaItem/Search/20170706?")
    fun rakuten(@Query("applicationId") applicationId: String, @Query("keyword") keyword: String): Call<RakutenIchibaSearchData>
}

GETに書くのはbaseUrlの続きで情報を取得してきたいUrlを書きます。Queryでは、PostmanでParamsに設定したもので、楽天APIの場合はapplicationIdは必須で、keywordは任意の文字列を必要とするので今回はこのように書いています。

 

Queryが分かんねーよという人は、下記リンクを参照してください。

クエリ式の基本

これでAPIエンドポイントの設定は完了しました。

次はモデルの作成です。

モデルを作成する

APIを叩いて帰ってきたレスポンスがJSONになっているのでそれをモデルというデータを持つクラスに変換します。

そのモデルを作成します。今回は総量だけを定義するのでカウントを持つdata classを作成しました。

data class RakutenIchibaSearchData(
        val count: Int
)

API詳細を見ながら適宜、ほしいデータを定義して使ってください。

楽天APIの場合はItemという名前で、itemNameなどで商品のタイトルを取得できるためリストに入れてitem[0].itemNameなどで実際の商品名を取る必要があります。

つぎは、Retrofitオブジェクトを作成して実際のエンドポイントの作成を行います。

 

Serviceを作成する

Retrofitオブジェクトを作成して実際のエンドポイントの作成を行う関数を下記のように定義します。

baseUrlでは設定ファイルにあらかじめ記述していたbaseUrlを書いて、addConverterFactoryではJSONをJavaに変換してくれています。

 

class MakePuraService(val application: Application){

    fun createService(): MakePuraApi {
        val retrofit = Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create())
                .baseUrl(MakePuraConfig(application).rakutenBaseUrl)
                .build()
        return retrofit.create(MakePuraApi::class.java)
    }

}

これでようやくエンドポイントの実装が完了しました。

通信で取得してきたデータをアプリに表示してみる

今回はFragmentの中で行っています。Fragmentが作られた段階でAPIを叩いてデータを取ってきてアプリのTextViewにて商品の検索結果の合計の値を表示するようにしています。

Fragmentで表示する場合は以下のように記述してください。

class RankingFragment : Fragment() {

    private lateinit var binding: FragmentRankingBinding
    private val makePuraConfig by lazy {
        activity?.application?.let { MakePuraConfig(it) }
    }
    private val makePuraService by lazy {
        activity?.application?.let { MakePuraService(it).createService() }
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        super.onCreateView(inflater, container, savedInstanceState)
        binding = FragmentRankingBinding.inflate(inflater, container, false)
        makePuraService?.rakuten(makePuraConfig?.applicationId!!, "福袋")?.enqueue(object :Callback<RakutenIchibaSearchData> {
            override fun onFailure(call: Call<RakutenIchibaSearchData>?, t: Throwable?) {
                TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
            }

            override fun onResponse(call: Call<RakutenIchibaSearchData>, response: Response<RakutenIchibaSearchData>) {
               if (response.isSuccessful) {
                   response.body()?.let {
                       binding.rankingTitle.text = it.count.toString()
                   }
               }
            }

        })
        return binding.root
    }
}

onCreateViewはFragmentが作られるときに呼ばれる関数でこの中で先ほど作ったエンドポイントを「福袋」というワードを添えて呼び出し、TextViewのテキストに表示するようにしています。

めんどうなので書いていないだけですが、onFailureの中でエラーを吐き出すように書きましょう。

これが終わると初めて以下のように通信で取ってきたデータを表示することができます。

ランキングはデフォルトで設定している文字列です。上のgifを見ると少し経った後に先ほどPostmanで確認したcountの値が返ってきていることが分かります。

これはテスト的に行っているので、本来ならばFragmentが起動するときに呼び出すのではなくアプリ起動時にすでにfetchしてアプリに保存しておくのがいいのではないかと思いますが誰でも簡単に通信のできるアプリを作ることができたと思います。

さいごに

Retrofit2は今のAndroid開発では知っておくべきライブラリの一つです。

案外難しくないので公式のドキュメントをよんで実際にサンプルを作ってみるのがいいと思います。

自分はヒィヒィ言いながら一年以上前に勉強しながら実践していた覚えがあります。

まあ、まずは試してみるのが一番大切だと思うので良いと思ったら試してもらえると嬉しいです。

間違っていたり、質問などあればコメントしてください!

 

最後まで見ていただきありがとうございました!!