HttpURLConnectionをOkHttp3に書き換えた時の話

2015年から始まったqnote Advent Calendar
今年で3回目になります。
皆様、よろしくお願いします。  

さて、今回はHttpURLConnectionをOkHttp3に書き換えた時のことを書いてみようかと思います。

# まずは元となるHttpURLConnectionを使った記述から

requestメソッドにパラメータのjsonを渡すことでpost、何も渡さなければgetを行い、jsonのレスポンスを受け取るというものです。

よくある書き方なので、詳細は説明しません。

```java
    public JSONObject request(JSONObject requestJson) {
        try {
            URL url = new URL("path");
            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setConnectTimeout(20 * 1000); // 20秒
            urlConnection.setReadTimeout(20 * 1000); // 20秒
            urlConnection.setRequestProperty("User-Agent", "hoge");

            if (null != requestJson) {
                urlConnection.setRequestMethod("POST");
                urlConnection.setDoOutput(true);
                byte[] bytes = requestJson.toString().getBytes();
                urlConnection.setRequestProperty("Content-Length", String.valueOf(bytes.length));
                urlConnection.getOutputStream().write(bytes);
                urlConnection.getOutputStream().flush();
            } else {
                urlConnection.setRequestMethod("GET");
            }

            urlConnection.connect();
            int responseCode = urlConnection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_NOT_FOUND) {
                return null;
            }

            InputStream inputStream = urlConnection.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
            String s;
            StringBuilder sb = new StringBuilder();
            while ((s = br.readLine()) != null) {
                sb.append(s);
            }
            br.close();
            return new JSONObject(sb.toString());

        } catch (IOException e) {
            e.printStackTrace();
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return null;
    }
```


#そして書き換えます
今回はOkHttp3の導入方法は記載しません。
gradelを使うなりして、使えるようにして下さい。

```java
    public JSONObject request(JSONObject requestJson) {
        try {
            OkHttpClient.Builder builder = new OkHttpClient.Builder()
                    .readTimeout(30 * 1000, TimeUnit.MILLISECONDS)
                    .writeTimeout(20 * 1000, TimeUnit.MILLISECONDS)
                    .connectTimeout(20 * 1000, TimeUnit.MILLISECONDS);

            OkHttpClient client = builder.build();
            Call call = client.newCall(getRequest(requestJson));
            Response response = call.execute();

            int responseCode = response.code();
            if (responseCode == HttpURLConnection.HTTP_NOT_FOUND) {
                return null;
            }
            retrun new JSONObject(response.body().string());
        } catch (IOException e) {
            e.printStackTrace();
        } catch (JSONException e) {
            e.printStackTrace();
        }
        retrun null
    }

    private Request getRequest(JSONObject requestJson) {
        Request request;

        Headers headers = new Headers.Builder()
                .add("User-Agent", "hoge")
                .build();

        if (requestJson == null) {
            request = new Request.Builder()
                    .headers(headers)
                    .url("path")
                    .get()
                    .build();
        } else {
            request = new Request.Builder()
                    .headers(headers)
                    .url("path")
                    .post(RequestBody.create(JSON, requestJson.toString()))
                    .build();
        }
        return request;
    }
 ```

#解説
見ていただける通り、特に難しいところはないと思います。
文字列の取得に関してはresponse.body().toString()にてレスポンスがStringで取れるので、とてもスッキリしていまね。
もしバイナリファイルを取得する際にはInputStreamを使う必要があるかと思います。
その場合は下記の書き方でInputStreamが取得できます。

```java
    InputStream inputStream = response.body().byteStream();
```

execute()ではなくenqueue()を使うこともできますが、今回はもともと非同期処理の中に書かれている部分の書き換えでしたので、そのままexecute()を使いました。

余談ですが、本来OkHttpClientはインスタンスを使いまわすのが正しい使い方となります。
ここでは簡単に書くために都度生成する記述になっています。
ですのでシングルトンやマネージャークラスを作ってOkHttpClientを管理するようにして下さい。

#まとめ
最初書き換えを行おうと思ったときには大きな工事になると想像していましたが、思った以上に簡単にできました。
仕事を始めたばかりの頃はライブラリを使うのは邪道みたいな感覚がありましたが、短時間で簡単に先を走る方々の力を借りるのは悪いことではないです。
なんでもライブラリに頼るのも良くはないですが、自分で情報を集め、吟味し、これは良いと思ったものに関してはどんどん使って行くべきだと思います。
まとめは少し話がそれましたが、以上となります。