【Java】HttpClientでAPIを叩いてみる②

# 前回の記事

https://qiita.com/syoshika_/items/dd1d699aed7ffe1d36e2

# やること

Dog APIを試してみる。
リクエストを送ると写真を表示するurlを返してくれる。

こんな感じ

```shell:
{
    "message": "https://images.dog.ceo/breeds/pointer-germanlonghair/hans1.jpg",
    "status": "success"
}
```

https://dog.ceo


# 環境

| System | Version |
| :-: | :-: |
| OS | MacOS Monterey(12.1) |
| Intelli J | 2022/2/2 |
| sdk | Temurin 11.0.14 |


# APIを叩く

> jdk11で進めていきます。

```java:Dog.java
package API;

import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import org.json.JSONObject;

public class Dog {
    public static void main(String[] args) {
        String url = "https://dog.ceo/api/breeds/image/random";
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest req = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .GET()
                .build();
        String dogURL = "";
        try {
            HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString());
            JSONObject jsonObject = new JSONObject(res.body());
            dogURL = (String)jsonObject.get("message");
            System.out.println(dogURL);
        } catch (IOException | InterruptedException ex) {
            ex.printStackTrace();
        }
    }
}

```


```shell:実行結果
https://images.dog.ceo/breeds/stbernard/n02109525_9522.jpg
```

アクセスしてみると

![スクリーンショット 2023-03-02 14.24.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/777324/ec08c001-36fd-170e-1118-985a89fae7f9.png)


# 自動で表示するようにする

urlだけ出されてもパッとしないので、`Desktop`ライブラリを使って開くとこまでやる。

https://docs.oracle.com/javase/jp/11/docs/api/java.desktop/java/awt/Desktop.html

```java:Dog.java
try {
    if (Desktop.isDesktopSupported()) {
        Desktop desktop = Desktop.getDesktop();
        desktop.browse(new URI(dogURL));
    }
} catch (IOException | URISyntaxException ex) {
    ex.printStackTrace();
}
```

* `isDesktopSupported()`で環境がサポートされているかを確認
* `getDesktop()`でインスタンス生成
* `browse()`メソッドに`dogURL`を入れて開いてもらう。

思ったより簡単に使えた。

> `IOException, URISyntaxException`の例外処理は必須です。

## isDesktopSupported()

```java:
 158:   private static boolean isDesktopSupported()
 159:   {
 160:     if (GraphicsEnvironment.isHeadless())
 161:       return false;
 162:     
 163:     return true;
 164:   }
```

https://developer.classpath.org/doc/java/awt/Desktop-source.html


## GraphicsEnvironment.isHeadless()

```java:
 122:   public static boolean isHeadless()
 123:   {
 124:     String headless = SystemProperties.getProperty("java.awt.headless", null);
 125:     return "true".equalsIgnoreCase(headless);
 126:   }
```

https://developer.classpath.org/doc/java/awt/GraphicsEnvironment-source.html

## SystemProperties.getProperty()

`java.awt.headless`の設定を調べて、なければ`null`を代入。
`true`か`True`か`TRUE`あたりが来るので`equalsIgnoreCase()`で比較した結果を返す。

![スクリーンショット 2023-03-02 16.29.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/777324/fb257ec4-c6e2-46ec-97a3-75069d7f913b.png)

> 画像引用：https://www.task-notes.com/entry/20151004/1443951543

これが`true`であった場合、ヘッドレスモードで動いていることにになる。

> ヘッドレス・モードは、Java アプリケーションがユーザーと直接対話しない場合に使用できます。つまり、**ウィンドウやダイアログ・ボックスが表示されず、キーボードやマウスによる入力がなく**、Heavyweight AWT コンポーネントを使用しない Java アプリケーションの場合です。

https://www.ibm.com/docs/ja/i/7.1?topic=toolkit-selecting-awt-mode

実行時に`-Djava.awt.headless=false`とするとそういったウィンドウを立ち上げるような`GUI`操作が無効化されるみたい。

https://stackoverflow.com/questions/41067235/what-is-the-benefit-of-setting-java-awt-headless-true

`isDesktopSupported()`はOSとかの低レベル層をチェックしているのではなく、単に`GUI`環境がサポートされているか確認しているだったので`false`になることはほとんどなさそう。

# 画像を保存する

`URLConnection`を使って指定したurlのリソースを読み込みます。

https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/net/URLConnection.html

```java:Dog.java
try {
    URL url = new URL(dogURL);
    URLConnection conn = url.openConnection();
    InputStream is = conn.getInputStream();

    File file = new File("/Users/syoshika/Downloads/dog.jpg");
    FileOutputStream fos = new FileOutputStream(file);

    int len = 1024;
    byte[] buf = new byte[len];
    while ((len = is.read(buf, 0, len)) != -1) {
        fos.write(buf, 0, len);
    }
    fos.close();
    is.close();
} catch (IOException ex) {
    ex.printStackTrace();
}
```

* `getInputStream()`でリソースを読み込む
* `FileOutputStream()`で書き込む準備(`dog.jpg`にした)
* bufに`read`してファイルに`write`をひたすら繰り返す。
* 1024は気分。これぐらいが早い気がした。

実際に`read()`で読み込んだ文字数分を書き込むようにするため、返り値をlen保存しておく。

> 戻り値:
バッファに読み込まれたバイトの合計数。
ストリームの終わりに達してデータがない場合は-1。

https://docs.oracle.com/javase/jp/8/docs/api/java/io/InputStream.html#read-byte:A-int-int-

# CaaS

`Cat as a service`って意味らしい、草

https://cataas.com/#/

せっかくなので`gif`でやってみる。

```java:Cat.java
try {
    URL url = new URL("https://cataas.com/cat/gif");
    URLConnection conn = url.openConnection();
    InputStream is = conn.getInputStream();

    File file = new File("/Users/syoshika/Downloads/cat.gif");
    FileOutputStream fos = new FileOutputStream(file);
    int len = 1024;
    byte[] buf = new byte[len];
    while ((len = is.read(buf, 0, len)) != -1) {
        System.out.println(len);
        fos.write(buf, 0, len);
    }
    fos.close();
    is.close();
} catch (IOException ex) {
    ex.printStackTrace();
}
```

GIFは単に複数の画像を連続的に表示してるだけなので、
犬の時とやることは変わらず`InputStream()`で読み込めるし`FileOutputStream()`で対応できる。

![cat.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/777324/a5e4fc33-a467-e200-cf83-63b287981b07.gif)

飛んでる最中が情けなくて可愛い。

# 次やること

POSTに触れる