SpringBootで外部APIにリクエストしてみた

# 概要
SpringBoot の RestTemplate を使用して、
外部 API にリクエストするサンプルコードを記載します。
ほぼ無料で利用できるので天気予報を取得する [Open Weather API](https://openweathermap.org/) を利用します。

# 天気予報を取得する
[Current weather data API] (https://openweathermap.org/current) は、
都市名と API Key をパラメータに指定して
GET リクエストで指定した都市名の天気予報が取得できます。

# コード
#### SampleApplication.java
RestTemplate を bean に定義する

```java
@SpringBootApplication
public class SampleApplication {

    public static void main(String[] args) {
        SpringApplication.run(SampleApplication.class, args);
    }

    @Bean
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}
```

#### application.yml
設定ファイル

```
open:
  weather:
    api:
      currentWeatherUrl: http://api.openweathermap.org/data/2.5/weather
      apiKey: {API Key}
```

#### OpenWeatherApiProperties.java
設定ファイルに記載した設定値を参照するクラス

```java
@Component
@Data
@ConfigurationProperties(prefix = "open.weather.api")
public class OpenWeatherApiProperties {
    private String currentWeatherUrl;
    private String apiKey;
}
```

#### OpenWeatherRestComponent.java
RestTemplate のコンポーネントクラス
以下をリクエスト時のパラメータにセットする

  - `q`：都市名、getWeatherByCityName メソッドの引数として受け取る
  - `appid`： API Key

API リクエストしたレスポンスのボディー部を戻り値として返しています

```java
@Component
public class OpenWeatherRestComponent {

    @Autowired
    RestTemplate restTemplate;

    @Autowired
    OpenWeatherApiProperties openWeatherApiProperties;

    /**
     * Open Weather API 都市名から天気予報を取得する
     * @throws URISyntaxException 
     */
    public String getWeatherByCityName(String cityName)
            throws URISyntaxException {

        String uri =
                openWeatherApiProperties.getCurrentWeatherUrl();

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<?> entity = new HttpEntity<>(headers);

        UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(uri)
            .queryParam("q", cityName)
            .queryParam("appid", openWeatherApiProperties.getApiKey());

        HttpEntity<String> responseEntity = restTemplate.exchange(
            builder.toUriString(), 
            HttpMethod.GET,
            entity,
            String.class);
        return responseEntity.getBody();
    }
}
```

#### SampleController.java
コントローラークラス
Rest API として GET /sample API を実装する

```java
@RestController
public class SampleController {

    @Autowired
    OpenWeatherRestComponent openWeatherRestComponent;

    @GetMapping("/sample")
    String getWeatherByCityName(
            @RequestParam(name="cityName") String cityName)
                    throws URISyntaxException {
        return openWeatherRestComponent.getWeatherByCityName(cityName);
    }
}
```

# 動作確認

GET /sample API をリクエストすると、
パラメータで指定した都市の天気予報情報が取得できました！
※ jq は JSON 形式のデータを整形するコマンド

```java
curl "http://localhost:8080/sample?cityName=London"  | jq .
```

```java
{
  "coord": {
    "lon": -0.13,
    "lat": 51.51
  },
  "weather": [
    {
      "id": 501,
      "main": "Rain",
      "description": "moderate rain",
      "icon": "10n"
    }
  ],
  "base": "stations",
  "main": {
    "temp": 282.3,
    "feels_like": 274.54,
    "temp_min": 281.48,
    "temp_max": 283.15,
    "pressure": 980,
    "humidity": 81
  },
  "visibility": 7000,
  "wind": {
    "speed": 9.8,
    "deg": 220,
    "gust": 21.6
  },
  "rain": {
    "1h": 3.99
  },
  "clouds": {
    "all": 100
  },
  "dt": 1609046221,
  "sys": {
    "type": 1,
    "id": 1414,
    "country": "GB",
    "sunrise": 1609056361,
    "sunset": 1609084635
  },
  "timezone": 0,
  "id": 2643743,
  "name": "London",
  "cod": 200
}
```