Call for Code：Node-REDでThe Weather Company APIを呼び出してみる


# はじめに
Call for Codeチャレンジの一環で、Call for Codeへの応募を目的とした場合に限り、The Weather Company APIを期間限定で使えるようになっています。「[Call for CodeでThe Weather Company APIを試してみよう (開発編)](https://qiita.com/ayatokura/items/39fcdf140dc6567505bb)」にAPI Keyの取得方法やAPI Docからの呼び出し方は書いてあるので、こちらを参照しつつ、Node-REDからAPIを呼び出す方法について試してみます。

今回の対象は、15分ごとの気象予報データの取得（[Fifteen Minute Forecast (v1) API](https://callforcode.weather.com/doc/v1-fifteen-minute-forecast/)）とします。このAPIには、緯度/経度をパラメータとして予報を取得するものと、郵便番号をパラメータとして予報を取得とするものの2種類がありますが、今回は緯度/経度を使うようにします。さらに、「東京都中央区」のような住所からAPIを呼び出せたほうが自然なので、Fifteen Minute Forecast (v1) APIの呼び出し前に、[Location Microservice API](https://callforcode.weather.com/doc/v3-location-services/)を呼び出して、緯度/経度を取得するようにします。

# Location Microservice API
地名から緯度経度を取得するAPIのURLは、以下となります。
> https://api.weather.com/v3/location/search

パラメータとして以下を指定しますが、cityの部分以外は固定でよいでしょう。

| パラメータ名      | 指定場所     | 内容 |
|:----------------|:------------|:------------|
| Accept          | Header      | application/jsonで固定 |
| Accept-Encoding | Header | gzip |
| apiKey | Query | 取得したAPI Keyを指定します。|
| language | Query | 出力の言語指定。日本語の場合はja-JP |
| countryCode | Query | ISO 3166-1 alpha-2形式の国コード指定。日本の場合はJP |
| format | Query | 出力形式。jsonで固定 |
| query | Query | 緯度経度を求めたい地名。ここに検索したい地名を設定する。 |


# Fifteen Minute Forecast API
緯度経度から15分ごとの気象予報を取得するAPIのURLは、以下となります。URL中に緯度と経度を指定します。
> https://api.weather.com/v1/geocode/{latitude}/{longitude}/forecast/fifteenminute.json

パラメータとして以下を指定しますが、cityの部分以外は固定でよいでしょう。

| パラメータ名      | 指定場所     | 内容 |
|:----------------|:------------|:------------|
| Accept          | Header      | application/jsonで固定 |
| Accept-Encoding | Header | gzip |
| latitude | URL | 緯度。気象予報を検索する土地の緯度を指定します。 |
| longitude | URL | 経度。気象予報を検索する土地の経度を指定します。 |
| apiKey | Query | 取得したAPI Keyを指定します。|
| units | Query | 出力形式。違いが分からなかったのでとりあえずm (Metrics)を指定しています。 |
| language | Query | 出力の言語指定。日本語の場合はja-JP |


# フローサンプル

サンプルのフローを用意しました。お手元のNode-REDにインポートして試してみてください。API呼び出し用のパラメータを設定するFunctionノードのなかでAPI Keyを指定しています。入手したAPI Keyを設定ください。Injectionノードで検索する地名を指定し、Debugノードで出力を確認できルのに加え、以下のURLでWeb APIライクにデータを取得できるようにもしていますので、試してみてください。

> https://{みなさんのNode-REDのURL}/weathersample?query={気象予報を検索する地名}


``` JavaScript
[{"id":"a324187c.942ea","type":"inject","z":"dd87133a.d244f","name":"","topic":"","payload":"千葉県千葉市","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":160,"wires":[["e017de52.33fdf"]]},{"id":"e017de52.33fdf","type":"function","z":"dd87133a.d244f","name":"Location Microservice APIのパラメータセット","func":"// Location Microservice API - search\nvar url = \"https://api.weather.com/v3/location/search\";\n\n// HTTP Method\nvar method = \"GET\";\n\n// HTTP Header\nvar headers = {\n    \"Accept\": \"application/json\",\n    \"Accept-Encoding\": \"gzip\"\n}\n\n// API Key\nvar apiKey = \"\";\n\n// Query\nvar query = msg.payload;\n\n// URLの生成\nurl += \"?apiKey=\" + apiKey;\nurl += \"&format=json&language=ja-JP&countryCode=JP&locationType=city\";\nurl += \"&query=\" + encodeURI(query);\n\nmsg.url = url;\nmsg.method = method;\nmsg.haders = headers;\n\nreturn msg;","outputs":1,"noerr":0,"x":520,"y":160,"wires":[["9beaf54.ab27508"]]},{"id":"9beaf54.ab27508","type":"http request","z":"dd87133a.d244f","name":"","method":"GET","ret":"txt","url":"","tls":"f7aac905.1f5b38","x":410,"y":220,"wires":[["3f8be40.0a0d91c","9098a65f.43235"]]},{"id":"3f8be40.0a0d91c","type":"debug","z":"dd87133a.d244f","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":710,"y":220,"wires":[]},{"id":"9098a65f.43235","type":"function","z":"dd87133a.d244f","name":"緯度経度の抽出","func":"// APIのレスポンスを文字列として受信しているのでJSONに変換\nvar response = JSON.parse(msg.payload);\n\nmsg.payload = {\n    latitude: response.location.latitude[0],\n    longitude: response.location.longitude[0]\n}\n\nreturn msg;","outputs":1,"noerr":0,"x":420,"y":280,"wires":[["934ddb04.c7d44","805c74d4.90d438"]]},{"id":"934ddb04.c7d44","type":"debug","z":"dd87133a.d244f","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":710,"y":280,"wires":[]},{"id":"805c74d4.90d438","type":"function","z":"dd87133a.d244f","name":"Fifteen Minute Forecast APIのパラメータセット（緯度/経度）","func":"// Fifteen Minute Forecast API - search\nvar url = \"https://api.weather.com/v1/geocode\";\n\n// HTTP Method\nvar method = \"GET\";\n\n// HTTP Header\nvar headers = {\n    \"Accept\": \"application/json\",\n    \"Accept-Encoding\": \"gzip\"\n}\n\n// API Key\nvar apiKey = \"\";\n\n// URLの生成\nurl += \"/\" + msg.payload.latitude;\nurl += \"/\" + msg.payload.longitude;\nurl += \"/forecast/fifteenminute.json\"\nurl += \"?apiKey=\" + apiKey;\nurl += \"&units=m&language=ja-JP\"\n\nmsg.url = url;\nmsg.method = method;\nmsg.haders = headers;\n\nreturn msg;","outputs":1,"noerr":0,"x":570,"y":360,"wires":[["98d421a4.fd42e8"]]},{"id":"98d421a4.fd42e8","type":"http request","z":"dd87133a.d244f","name":"","method":"GET","ret":"txt","url":"","tls":"f7aac905.1f5b38","x":410,"y":420,"wires":[["5839b187.2db34"]]},{"id":"2f1a5c51.610d74","type":"debug","z":"dd87133a.d244f","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":710,"y":480,"wires":[]},{"id":"5839b187.2db34","type":"function","z":"dd87133a.d244f","name":"時刻と天気を抽出する","func":"var response = JSON.parse(msg.payload);\n\nvar forecasts = [];\n\nresponse.forecasts.forEach(function(data) {\n   var forecast = {\n       localTime: data.fcst_valid_local,\n       weather: data.phrase_32char\n   }\n   forecasts.push(forecast);\n});\n\nmsg.payload = forecasts;\n\nreturn msg;","outputs":1,"noerr":0,"x":620,"y":420,"wires":[["2f1a5c51.610d74","9b2d6a28.88adb"]]},{"id":"df23870.af2adf8","type":"http in","z":"dd87133a.d244f","name":"","url":"/weathersample","method":"get","upload":false,"swaggerDoc":"","x":140,"y":100,"wires":[["a5489a6.f26e868"]]},{"id":"9b2d6a28.88adb","type":"http response","z":"dd87133a.d244f","name":"","statusCode":"","headers":{},"x":690,"y":520,"wires":[]},{"id":"a5489a6.f26e868","type":"function","z":"dd87133a.d244f","name":"","func":"msg.payload = msg.payload.query;\n\nreturn msg;","outputs":1,"noerr":0,"x":390,"y":100,"wires":[["e017de52.33fdf"]]},{"id":"841d8bd8.96637","type":"comment","z":"dd87133a.d244f","name":"queryに指定された地名の天気を検索する","info":"","x":200,"y":60,"wires":[]},{"id":"f7aac905.1f5b38","type":"tls-config","z":"","name":"","cert":"","key":"","ca":"","certname":"","keyname":"","caname":"","servername":"","verifyservercert":true}]
```