[Weather Kit] WWDC2022で発表されたWeatherKitについて調べてみた

## はじめに
WWDC2022でグローバルな気象情報を提供するWatherKitが発表されました。
WeatherKitの活用に関して、公式では以下のように紹介されています。
> WeatherKitは、最先端でグローバルな気象予報サービスである、まったく新しいApple Weatherサービスを活用しており、タイムリーかつ地域に密着した気象情報によってAppを強化するために必要なあらゆるデータを提供します。これにより、現在の気象状況のほか、10日間の気温、降水量、風、UV指数などの時間別の予報をAppで提供できます。一部の地域では、今後1時間の分刻みでの降水量や、重大な気象警報も提供できます。

https://developer.apple.com/jp/weatherkit/

## 利用可能なプラットフォーム
WeatherKit Swift API：iOS 16、iPadOS 16、macOS 13、tvOS 16、watchOS 9
WeatherKit REST API：全てのプラットフォーム

## 利用要件
- Apple Developer Programのメンバーシップ
- アトリビューション

## 取得可能なデータ

取得可能なデータは、大きく分けると以下の6点になります。
- `Current weather` 現在の天気（気温、風、UV指数など）
- `Minute forecast` 分単位の予報（現在から1時間分の降水状況）
- `Hourly forecast` 時間単位の予報（現在から240時間分）
- `Daily forecast` 日単位の予報（現在から10日間）
- `Weather alerts` 指定した地点の気象警報　
- `Historical weather` 過去の気象情報
※ 過去の気象情報に関しては、開始日と終了日を指定し、「1日もしくは1時間単位」で取得が可能です。(実際に試して、`2021-07-31T10:00:00Z`以降は取得可能でした。）
### 気象情報詳細
気象情報として取得できるデータは以下のようになっております。([Current weather](https://developer.apple.com/documentation/weatherkitrestapi/currentweather/currentweatherdata))
- `asOf(date-time)` 日付と時間
- `cloudVocer(number)` 空に対する雲の比率(0~1)
- `conditionCode(string)` 列挙型、その時の天気の状態(例：MostlyCloudy)
    - [取得可能な天気データ一覧(41項目)](https://github.com/hrbrmstr/weatherkit/blob/batman/R/enumerations.R)：
- `daylight(boolean)` 日差しがあるかどうか
- `humidity(number)` 湿度
- `precipitationAmount`
- `precipitationIntensity(number)` 降水量(mm/h)
- `precipitationChance`
- `precipitationType`
- `pressure(number)` 海面気圧(millibars)
- `pressureTrend(PressureTrend)` 海面気圧の傾向
    - `PressureTrend` -> raising, falling, steady
- `snowfallIntensity`(number): 
- `snowfallAmount`(number): 
- `temperature(number)` 現在の気温(摂氏)
- `temperatureApparent(number)` 体感温度
- `temperatureDewPoint(number)` 露天温度
- `uvIndex(integer)` UI指数
- `visibility(number)` 視程(物体をはっきりと確認できる距離)(meters)
- `windDirection(integer)` 風向き
- `windGust(number)` 最高風速
- `windSpeed(number)` 風速

## 料金
##### 無料
50万回の呼び出し／月：無料（メンバーシップに含まれています）
##### 有料
100万回の呼び出し／月：49.99米ドル
200万回の呼び出し／月：99.99米ドル
500万回の呼び出し／月：249.99米ドル
1,000万回の呼び出し／月：499.99米ドル
2,000万回の呼び出し／月：999.99米ドル

有料枠に関しては、サブスクリプション形式で、あらかじめ登録することでそれぞれのプランが利用可能になります。プランのアップグレードは登録した段階で適応されるため、いつでも利用可能です。
また、ダウングレードに関しても、以前のプランの期間が終了するまでは、適応されます。

## 導入方法
次に実際にAPIを使用するにあたっての事前準備です。
Swift APIではApple developerでWeatherKitの使用の登録をします。(1の手順のみ)
REST APIの使用には、加えてKeyの発行やそれを使用してJWTを作成する必要があります。
1. App Developer Programの「Certificates, Identifiers & Profiles」から任意の**App ID**に対して、「Capability」と「App Services」の両方でWeatherKitの欄にチェックする。（両方にチェックしてないと、エラーになります。）

1. 次にKeyを作成します。同じく、「Certificates, Identifiers & Profiles」からWeatherKitにチェックを入れKeyの作成を行います。ここで発行される**Key ID**を控えておき、同時に**Private Key File**をダウンロードします。

1. ダウンロードした`.p8`ファイルから**public key**を作成します。（手順については、下記URLの「Preparing The Keys」を参考にしてください。）

1. ここまで完了したら、**TeamID**を確認し、**AppID**, **KeyID**, **publicKey**, **privateKey**からJWTを作成する。今回は、[jwt.io](https://jwt.io/)を使用します。

HEADERとPAYLOADを以下のように指定します。
```
// HEADER
{
  "alg": "ES256",
  "kid": "{KeyID}",
  "id": "{TeamID}.{AppID}",
  "typ": "JWT"
}
// PAYLOAD
{
  "iat": 1662903288, // 作成時刻(UNIX時刻)
  "exp": 1662906888, // 有効期限(UNIX時刻)
  "iss": "{TeamID}",
  "sub": "{AppID}",
}
```
**publicKey**, **privateKey**を元に署名を行い、`✔️Signature Verified`の表示になれば、JWTの作成完了です。
以下、URLが同じ手順で画像もあるので参考にしてみてください。

https://dev.iachieved.it/iachievedit/weatherkit-rest-api/

## 実際に叩いてみる
準備ができたので、Headerに先ほど作成したJWTを指定し、実際にAPIを叩いてみます。

### 現在の天気
##### パス(必須)
`language: ja_JP`
`latitude: 35.710063`
`langitude: 139.8107`
##### クエリ
`dataSets: currentWeather`
```
$ curl -H 'Authorization: Bearer <Token>’ \
"https://weatherkit.apple.com/api/v1/weather/ja_JP/35.710063/139.8107?dataSets=currentWeather"
```
レスポンス
```
{
  "forecastHourly": {
    "name": "HourlyForecast",
    "metadata": {
      "attributionURL": "https://weatherkit.apple.com/legal-attribution.html",
      "expireTime": "2022-12-01T09:48:03Z",
      "latitude": 35.71,
      "longitude": 139.814,
      "readTime": "2022-12-01T08:48:03Z",
      "reportedTime": "2022-12-01T07:00:00Z",
      "units": "m",
      "version": 1
    },
    "hours": [
      {
        "forecastStart": "2021-07-31T10:00:00Z",
        "cloudCover": 0.23,
        "conditionCode": "MostlyClear",
        "daylight": false,
        "humidity": 0.69,
        "precipitationAmount": 0,
        "precipitationIntensity": 0,
        "precipitationChance": 0,
        "precipitationType": "clear",
        "pressure": 1001.91,
        "pressureTrend": "rising",
        "snowfallIntensity": 0,
        "snowfallAmount": 0,
        "temperature": 27.9,
        "temperatureApparent": 30.49,
        "temperatureDewPoint": 21.63,
        "uvIndex": 0,
        "visibility": 24134,
        "windDirection": 96,
        "windGust": 16.96,
        "windSpeed": 12.03
      }
    ]
  }
}
```
過去や未来の天気を取得したい場合は、`dataSets`に`forecastHourly`か`forecastDaily`を指定して、以下のように取得したい開始時刻、終了時刻を指定します。
### 過去の天気(1時間単位)
パスは同様
##### クエリ
`dataSets: forecastHourly`（1日単位で取得したい場合は、forecastDaily）
`hourlyStart: 2021-07-31T10:00:00Z`
`hourlyEnd: 2021-07-31T11:00:00Z`
```
$ curl -H 'Authorization: Bearer <Token>' \
"https://weatherkit.apple.com/api/v1/weather/ja_JP/35.710063/139.8137?dataSets=forecastHourly&hourlyStart=2021-07-31T10:00:00Z&hourlyEnd=2021-07-31T11:00:00Z"
```
レスポンス
```

{
  "forecastHourly": {
    "name": "HourlyForecast",
    "metadata": {
      "attributionURL": "https://weatherkit.apple.com/legal-attribution.html",
      "expireTime": "2022-12-01T09:48:03Z",
      "latitude": 35.71,
      "longitude": 139.814,
      "readTime": "2022-12-01T08:48:03Z",
      "reportedTime": "2022-12-01T07:00:00Z",
      "units": "m",
      "version": 1
    },
    "hours": [
      {
        "forecastStart": "2021-07-31T10:00:00Z",
        "cloudCover": 0.23,
        "conditionCode": "MostlyClear",
        "daylight": false,
        "humidity": 0.69,
        "precipitationAmount": 0,
        "precipitationIntensity": 0,
        "precipitationChance": 0,
        "precipitationType": "clear",
        "pressure": 1001.91,
        "pressureTrend": "rising",
        "snowfallIntensity": 0,
        "snowfallAmount": 0,
        "temperature": 27.9,
        "temperatureApparent": 30.49,
        "temperatureDewPoint": 21.63,
        "uvIndex": 0,
        "visibility": 24134,
        "windDirection": 96,
        "windGust": 16.96,
        "windSpeed": 12.03
      }
    ]
  }
}
```
他にも指定できるパラメータがあるので、必要に応じて確認してみてください！

https://developer.apple.com/documentation/weatherkitrestapi/get_api_v1_weather_language_latitude_longitude

## まとめ
今回紹介したWeatherKitですが、なんと言っても50万コールまで無料というのは大きかなと思います。(Apple Developer Programに登録しておく必要はありますが😅)
導入する手順も簡単でREST APIとして全てのプラットフォームに対しても提供もしているため、iOS等以外でも使用できるのもgoodですね。今回は紹介していませんが、（あまり調べられてないだけです。。。）気象警報など、他にもさまざまな機能もあるので、天気の情報を取得したい場合は、ぜひ検討してみてはいかかでしょうか！

## 参考
https://developer.apple.com/jp/weatherkit/

https://developer.apple.com/documentation/weatherkitrestapi/currentweather/currentweatherdata

https://github.com/hrbrmstr/weatherkit/blob/batman/R/enumerations.R

https://dev.iachieved.it/iachievedit/weatherkit-rest-api/

https://zenn.dev/bon/articles/weatherkit-restapi