Web APIとパラメータ (J)

はじめに

Web API へのアクセスも、基本 URL を作ってアクセスし、出力結果を Stream として取り出すことはできます。

ただ、色々不便なこともあるので、便利なライブラリを使ってみましょう。 利用するのはRetrofit というライブラリです。github 上で公開されています。

なにが便利かというと、こんな感じです。

  • Web API の引数の処理を簡単に記述可能
  • 問い合わせを同期的におこなったり、非同期におこなったりすることが簡単
  • 取得結果を GSON や JAXB をつかってオブジェクトに変換することもできる

詳しいことに興味がある人は、Retrofitのチュートリアルと API document をみてください。

利用プログラムは konanU.net.retrofit パッケージ以下にあり、起動するプログラムは SampleCallerです。

Web API を Java API に

以前お伝えしたように、 Web API 側は、URL を受け取って、結果を返す関数のようなものです。 でも、引数の与え方などが特殊なので、プログラムからメソッド気分で呼ぶのは大変ですよね。

ってことで、retrofit をつかって、手軽にその差を埋めてていきましょう。

上記チュートリアルの例をそのまま使いますが(ユーザ名だけ octcat から plham に変更しています)、例えば、github Contents API の場合、

にアクセスすることで、plham というユーザの repository 情報をリストの形で返してくれます。plham の部分がパラメータですね。

[
  {
    "id": 54699962,
    "node_id": "MDEwOlJlcG9zaXRvcnk1NDY5OTk2Mg==",
    "name": "plham",
    ...
  },
  {
    "id": 54700048,
    "node_id": "MDEwOlJlcG9zaXRvcnk1NDcwMDA0OA==",
    "name": "plham.github.io",
    ...
  },
  ...
}

これを、Java から簡単にアクセスできるように、

Call<List<Repo>> repos = service.listRepos("plham");

のようなメソッド呼び出しで取得できるようにします。

そのためには、

  • BaseURL が https://api.github.com であり、
  • listRepos(String user) に応じて、 users/{user}/repos という path にアクセスし({user}String userに応じて置き換わる)、
  • 結果を List<Repo>という形で受け取る (GSON を使って変換)
    • Repo というのは、結果の JSON オブジェクトの変換先である Java クラス

と利用者が宣言します。

インタフェイス GitHubService の宣言が下の二つを担当します。

public interface GitHubService {
  @GET("users/{user}/repos")  // path の作り方
  Call<List<Repo>> listRepos(@Path("user") String user); // 引数が path に組み込まれることと、返り値型やメソッド名の宣言
}

BaseURL の指定は、Retrofit オブジェクト生成の段階で指定し、上記インタフェイスのクラスオブジェクト(GitHubService.class)を引数に与えることで、サービスを生成しています。結果を GSON で List<Repo>に変換するので、その指定も行っています(addConverterFactory))。

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .addConverterFactory(GsonConverterFactory.create()) // GSON 変換を行う際に利用
    .build();

GitHubService service = retrofit.create(GitHubService.class);

あとは、以下で呼び出し準備完了です。

Call<List<Repo>> repos = service.listRepos("plham");

この段階では、まだ Web API にリクエストは送っておらず、このあと呼出しをおこないます。だから、Callというクラス名なんでしょうね。

URL encoding

Web API の GET メソッドを呼び出すときは、URL の形で引数が渡されます。 ただ、URL 中には日本語とか書けませんし、space などもかけません。

こういう場合は、引数を URL encoding という形式に変換して送ることになっています。 皆さんも、Web browser の URL 欄には、

https://www.google.com/search?q=甲南大学

とか書いてあるのに、copy & paste すると

https://www.google.com/search?q=%E7%94%B2%E5%8D%97%E5%A4%A7%E5%AD%A6

って変わる経験があるんじゃないでしょうか。

URL encoding を直接おこなうには、Java では java.net.URLEncoder などが利用できますが、 retrofit も対応してくれていますのでご安心を。

結果の取得

では、問い合わせをしてみましょう。 ここでおこなうのは同期呼出しといって、相手から結果が返ってくるまで待つタイプの呼出しです。

Call<List<Repo>> repos = service.listRepos("plham");
Response<List<Repo>> response = repos.execute(); // 同期呼出し
if (response.isSuccessful()) {
    List<Repo> result = response.body();
    System.out.println("Success (Sync): " + result);
} else {
    System.out.println("Failed (Sync): " + response.message());
}

呼出しが成功するとは限らないので、response.isSuccessful()で成否を確認してから、結果を取り出しています。 GSON によって、ちゃんと JSON 文書がオブジェクトに変換されているのが偉いですね。

実は、retrofit では、同期呼出し以外に callback を使った非同期呼出しができます。 ネットワーク処理はまたさせることもあるし、失敗することもあるので、 処理待ちをしているとプログラムが固まったみたいになって嬉しくないことも多いんです。

非同期処理については講義で説明したあとにプログラムの紹介をします。 プログラム自体は、 SampleCaller の後半部分に載っているものです。