読者です 読者をやめる 読者になる 読者になる

Okhttp + Gson を使ったJavaによるWebAPI入門

大学の授業の副手でJavaでWebAPIを使ったプログラムについてまとめることになったのでここにまとめます。

使用するライブラリ

JavaでHTTP通信だったりJSONを扱うのに一から自分で書くのって結構つらいですよね。
またエラーハンドリングとかしっかりやらないととても使えるものにはならないと思います。

よって今回はライブラリを使います。
※ 勉強するのにライブラリ使って良いのかよって思う人もいると思いますが、今回はサクッと使えるようなサンプル用意してくれっていうオーダーだったのでライブラリは使用します。

使用するWebAPI

Livedoor Weather Web Service
Livedoorが提供している天気予報APIです。 てきとうに選びました。まぁ認証は無しのAPIならなんでも良かったです。

HTTP通信

通信部分はOkhttpを使います。

HttpUrl

後述の Request インスタンスを作成するときにURLを指定するんですが、単純に文字列を渡してもいんですがUrlを作成するための HttpUrl クラスも存在します。
こちらはいろんなエンドポイント用に文字列を用意しておいたり、パラメータの指定を簡単に書けるようにしてくれます。
作成するには HttpUrl.Builder クラスが存在するので以下のように作成していきます。

HttpUrl.Builder builder = HttpUrl.Builder()
        .scheme(SCHEME)
        .host(HOST)
        .addPathSegment(FORECAST)
        .addPathSegment(WEB_SERVICE)
        .addPathSegment(JSON)
        .addPathSegment(ROOT);

上記で作成したURLは SCHEME://HOST/FORECAST/WEB_SERVICE/JSON/ROOT になります。

またパラメータを指定するのも簡単で以下のように書きます。

builder.addQueryParameter("city", "400040");

これによって今回使用するURLが作成できました。
SCHEME://HOST/FORECAST/WEB_SERVICE/JSON/ROOT?city=400040

Request

通信するときは Request インスタンスを作り OkHttpClient#newCall(Request request) を使って Call インスタンスを作ります。
通信方法には同期通信と非同期通信があり、同期通信は Call#execute() を、非同期通信は Call#enqueue(Callback callback) を使います。

また、 Request を作るときにHTTPメソッドを指定して作成します。
今回はGETメソッドとPOSTメソッドについて説明します。

GET

Request.Builder にURL渡して Request.Builder#get() を叩くだけ。
まあ Request.Builder のコンストラクタの実装を見るとわかると思いますが、デフォルトはGETメソッドが指定されてるので get() メソッド叩かなくても良いかも。

Request request = new Request.Builder()
      .url(builder.build())
      .get()
      .build();

builder はHttpUrlの項目で作成したもの。

POST

POSTメソッドは以下のように使用します。
JSONオブジェクトをつけてPOSTの Request を作成してみます。

MediaType jsonMedia = MediaType.parse("application/json; charset=utf-8");
Request request = new Request.Builder()
    .url(buildStateUrl())
    .post(RequestBody.create(jsonMedia, "{\"key\": \"value\"}"))
    .build();

だいたいこんな感じです。他にもいろいろあるので気になる人は自分で調べてみてください。

通信

あと残りは仕上げです。
先程述べた通り通信には2種類あり、同期通信と非同期通信です。

また、通信するには Call オブジェクトが必要です。
これまでに作ってきたRequestから以下のように作成します。

OkHttpClient client = new OkHttpClient();
Call call = client.newCall(request);

同期通信

特に難しいことはありません。 Call#execute() を叩くだけです。

Response response = client.newCall(request).execute();

非同期通信

こちらもそんなに難しいことはありません。非同期通信なのでCallbackが必要になるだけです。

client.newCall(request).enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
        // Error
    }

    @Override
    public void onResponse(Call call, Response response) {
        // Success
    }
});

どちらも通信が終わったあとに Response オブジェクトが返ってくるのでそこから結果を取得します。
今回使用するAPIではbody部分にJSONオブジェクトが返ってくるので以下の用に受け取ります。

String result = response.body().string();

これで通信部分は終了です。
次はWebAPIから取得したJSONオブジェクトGsonを使って実際に使えるようにします。

Gson

それでは取得できたJSONJavaオブジェクトに変換して使えるようにしましょう。
まずJavaオブジェクトに変換するにはそれに対応するクラスを定義しないといけません。
例として以下のようなJSONがあるとします。

{
  "id": 321,
  "name": "nshiba",
  "birth": {
    "country": "Japan",
    "day": "1990-01-01"
  },
  "friends": [
    123,
    234,
    345,
    456
  ]
}

これをJavaオブジェクトに変換しようと思ったら、全体用のクラスと birth 用のクラス、2つのクラスが必要です。

public class UserEntity {
    @SerializedName("id")
    private int id;

    @SerializedName("name")
    private String name;

    @SerializedName("birth")
    private BirthEntity birth;

    @SerializedName("friends")
    private List<Integer> friendList;

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public BirthEntity getBirth() {
        return birth;
    }

    public List<Integer> getFriendList() {
        return friendList;
    }
}
public class BirthEntity {
    @SerializedName("country")
    private String country;

    @SerializedName("day")
    private String day;

    public String getCountry() {
        return country;
    }

    public String getDay() {
        return day;
    }
}

これでクラスの宣言はできたので以下のようにGsonを使って変換します。

UserEntity userEntity = gson.fromJson(result, UserEntity.class);

まとめ

これで一通り入門できたのかもしれないです。
一応こんな感じで実装していけば問題ないかな、思う範囲でサクッと作ったのですが問題がでそうな部分があったら教えてもらえると幸いです。
質問などあればコメントでお願いします。

また、今回作成したサンプルは公開していますので、コードはそちらの方が参考にできると思います。

github.com