初めてのNode.js〜天気予報APIを取得してみた

#0.前提
+ Node.js超入門者
+ APIを使って何をするかもまだイメージが湧かないレベル

#1.npmを使ってライブラリaxiosをインストール
1.PCのデスクトップに `wether` という名前のフォルダを作成
2.VSコードで　作成した`wether`フォルダ開く
3.`wether`フォルダ 内に　`app.js`ファイルを作成しておく
4.ターミナルで　`npm init -y` を実行

```terminal
tomoko@MB wether % npm init -y
Wrote to /Users/tomoko/Desktop/wether/package.json:

{
  "name": "wether",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}
```

→フォルダに package.jsonが生成された
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1565008/31971cd4-710e-1357-c9d1-483699c760d0.png)


###`npm init -y`とは？
+ 今いる`wether`フォルダ　をNode.jsプロジェクトとして初期化するコマンド。最初に１回だけ行えばOK。
+ `-y` とは　Yes　の略で、`npm init` だけだといくつか選択肢を聞かれる。基本的にデフォルト設定でOKなので、　`-y` を付加しておけば、デフォルトの選択をしてくれる

4.ターミナルで `npm i axios` を実行

```terminal
tomoko@MB wether % npm i axios
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN wether@1.0.0 No description
npm WARN wether@1.0.0 No repository field.

+ axios@0.21.1
added 2 packages from 4 contributors and audited 2 packages in 1.924s

1 package is looking for funding
  run `npm fund` for details

found 0 vulnerabilities
```

→フォルダにnode_modules、package-lock.jsonが生成された
　　package.jsonにaxiosが追加された
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1565008/edb56ddc-7f9e-8d89-793a-3aa8b63a5bb6.png)

###`npm i axios`とは？
+ よく使うコマンド
+ ライブラリaxiosをインストールする　という意味のコマンド
+ インストールしたライブラリは、`node_modules`の中に追加される。
+ axios　自体もjsで書かれているプログラム
+ 他のライブラリをインストールする場合は、`npm i {ライブラリ名}`という構文を書けばよい。


#2.初めてのAPIたたき　　
+ 界隈で言われる　`APIを叩く`　＝　APIからデータを取ってみる
+ 叩く対象は[天気予報のAPI]（https://weather.tsukumijima.net/api/forecast/city/130010）
+ ↑の元ネタは[こちら](https://weather.tsukumijima.net/)

+ 基本の型

```js
const axios = require('axios');

const main = async () => {
  try {
    const res = await axios.get('URL');  // URLを書き換える
    console.log(res.data); // データ全体を表示する(なくてもOK)

    /* さらに細かくデータを見る場合は、ここに処理を書く */

  } catch (error) {
    console.error(error);
  }
}

main();
```


#3.app.js に　プログラムを書く
```app.js
const axios = require('axios');

const main = async () => {
  try {
    const res = await axios.get('https://weather.tsukumijima.net/api/forecast/city/130010');  // URLを書き換える
    console.log(res.data); // データ全体を表示する(なくてもOK)

    /* さらに細かくデータを見る場合は、ここに処理を書く */

  } catch (error) {
    console.error(error);
  }
}

main();

```

#4.実行

```terminal
tomoko@MB wether % node app.js
{
  publicTime: '2021-06-29T17:00:00+09:00',
  publicTimeFormatted: '2021/06/29 17:00:00',
  publishingOffice: '気象庁',
  title: '東京都 東京 の天気',
  link: 'https://www.jma.go.jp/bosai/forecast/#area_type=offices&area_code=130000',
  description: {
    publicTime: '2021-06-29T20:52:00+09:00',
    publicTimeFormatted: '2021/06/29 20:52:00',
    headlineText: '東京地方では低い土地の浸水や河川の増水に、伊豆諸島では高波に、東京地方、伊豆諸島南部では落雷に、伊豆諸島南部では濃霧による視程障害に注意してください。',
    bodyText: '　梅雨前線が華中から日本の南を通って日本の東へのびており、前線上の三陸沖には低気圧があって北東へ進んでいます。\n' +
      '\n' +
      '　東京地方は、おおむね雨となっています。\n' +
      '\n' +
      '　２９日は、梅雨前線が日本の南に停滞し、湿った空気や気圧の谷の影響を受ける見込みです。このため、曇りや雨で、雷を伴い激しく降る所があるでしょう。伊豆諸島では、雨や雷雨となる所がある見込みです。\n' +
      '\n' +
      '　３０日は、梅雨前線が華中から伊豆諸島付近を通って日本の東に停滞し、湿った空気の影響を受けるでしょう。このため、曇りで、朝晩は雨の降る所がある見込みです。伊豆諸島では、夜は雷を伴い激しい雨となる所があるでしょう。\n' +
      '\n' +
      '【関東甲信地方】\n' +
      '　関東甲信地方は、曇りや雨で、雷を伴い激しく降っている所があります。\n' +
      '\n' +
      '　２９日は、梅雨前線が日本の南に停滞し、湿った空気や気圧の谷の影響を受ける見込みです。このため、曇りや雨で、雷を伴い激しく降る所があるでしょう。\n' +
      '\n' +
      '　３０日は、梅雨前線が華中から伊豆諸島付近を通って日本の東に停滞し、湿った空気の影響を受ける見込みです。このため、曇りや雨で、伊豆諸島では雷を伴い激しく降る所があるでしょう。\n' +
      '\n' +
      '　関東地方と伊豆諸島の海上では、うねりを伴い、２９日はしけとなり、３０日は波が高いでしょう。また、所々で霧が発生しています。船舶は高波や視程障害に注意してください。',
    text: '東京地方では低い土地の浸水や河川の増水に、伊豆諸島では高波に、東京地方、伊豆諸島南部では落雷に、伊豆諸島南部では濃霧による視程障害に注意してください。\n' +
      '\n' +
      '　梅雨前線が華中から日本の南を通って日本の東へのびており、前線上の三陸沖には低気圧があって北東へ進んでいます。\n' +
      '\n' +
      '　東京地方は、おおむね雨となっています。\n' +
      '\n' +
      '　２９日は、梅雨前線が日本の南に停滞し、湿った空気や気圧の谷の影響を受ける見込みです。このため、曇りや雨で、雷を伴い激しく降る所があるでしょう。伊豆諸島では、雨や雷雨となる所がある見込みです。\n' +
      '\n' +
      '　３０日は、梅雨前線が華中から伊豆諸島付近を通って日本の東に停滞し、湿った空気の影響を受けるでしょう。このため、曇りで、朝晩は雨の降る所がある見込みです。伊豆諸島では、夜は雷を伴い激しい雨となる所があるでしょう。\n' +
      '\n' +
      '【関東甲信地方】\n' +
      '　関東甲信地方は、曇りや雨で、雷を伴い激しく降っている所があります。\n' +
      '\n' +
      '　２９日は、梅雨前線が日本の南に停滞し、湿った空気や気圧の谷の影響を受ける見込みです。このため、曇りや雨で、雷を伴い激しく降る所があるでしょう。\n' +
      '\n' +
      '　３０日は、梅雨前線が華中から伊豆諸島付近を通って日本の東に停滞し、湿った空気の影響を受ける見込みです。このため、曇りや雨で、伊豆諸島では雷を伴い激しく降る所があるでしょう。\n' +
      '\n' +
      '　関東地方と伊豆諸島の海上では、うねりを伴い、２９日はしけとなり、３０日は波が高いでしょう。また、所々で霧が発生しています。船舶は高波や視程障害に注意してください。'
  },
  forecasts: [
    {
      date: '2021-06-29',
      dateLabel: '今日',
      telop: '曇時々雨',
      detail: [Object],
      temperature: [Object],
      chanceOfRain: [Object],
      image: [Object]
    },
    {
      date: '2021-06-30',
      dateLabel: '明日',
      telop: '曇り',
      detail: [Object],
      temperature: [Object],
      chanceOfRain: [Object],
      image: [Object]
    },
    {
      date: '2021-07-01',
      dateLabel: '明後日',
      telop: '曇り',
      detail: [Object],
      temperature: [Object],
      chanceOfRain: [Object],
      image: [Object]
    }
  ],
  location: { area: '関東', prefecture: '東京都', district: '東京地方', city: '東京' },
  copyright: {
    title: '(C) 天気予報 API（livedoor 天気互換）',
    link: 'https://weather.tsukumijima.net/',
    image: {
      title: '天気予報 API（livedoor 天気互換）',
      link: 'https://weather.tsukumijima.net/',
      url: 'https://weather.tsukumijima.net/logo.png',
      width: 120,
      height: 120
    },
    provider: [ [Object] ]
  }
}
```

大量の結果が返ってきた。
次の5.で、必要な情報だけに絞り込んで取得する

###（知識の補足）APIでおさえておくポイントは３つ
1.どのURLか？
[全国の地点定義表]（https://weather.tsukumijima.net/）　によれば、東京は、
`<city title="東京" id="130010" source="http://weather.livedoor.com/forecast/rss/area/130010.xml"/>
`とあるので、東京の天気データを取得するURLは
`https://weather.tsukumijima.net/api/forecast/city/130010`
である。

２．パラメーター
基本的にデフォルトだと全部の情報がかえってくる。↓はその一部。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1565008/6b844f43-780c-e433-1c9e-793f3807192f.png)
全部の情報はいらないときに、絞り込むためにパラメーターを付与して必要な情報だけとってくる

３．認証
このAPIは無料なので、割愛。

#5.結果をパラメーターを利用して絞り込む
1. `description`の中の`headlineText`
2. `明日`
3. `forecasts`の中の`detail`の中の`weather`
4. `forecasts`の中の`chanceOfRain`の中の`T06_12`

一気に表示するのは難しそうなので、一つずつ考える。

##5-1.`description`の中の`headlineText`を取得

```app.js
const axios = require('axios');

const main = async () => {
  try {
    const res = await axios.get('https://weather.tsukumijima.net/api/forecast/city/130010');  
    console.log(res.data.description.headlineText); // ←今ココ

    /* さらに細かくデータを見る場合は、ここに処理を書く */

  } catch (error) {
    console.error(error);
  }
}

main();
```
オブジェクトの中身をドット記法で書いてみた。


結果

```terminal
tomoko@MB wether % node app.js
東京地方では低い土地の浸水や河川の増水に、伊豆諸島では高波に、東京地方、伊豆諸島南部では落雷に、伊豆諸島南部では濃霧による視程障害に注意してください。
```
無事、絞り込んで取得できた。

###前提知識:オブジェクトと配列という概念　
+ [オブジェクト](https://jsprimer.net/basic/object/) は `{`　で始まり、　`}`　で終わるのが特徴

```js
const obj = {
    key: "value"
};
// ドット記法で参照
console.log(obj.key); // => "value"
// ブラケット記法で参照
console.log(obj["key"]); // => "value"
```

+ [配列]　(https://jsprimer.net/basic/array/）

```js
const array = ["one", "two", "three"];
console.log(array[0]); // => "one"
```
どちらも複数の情報を一まとまりとして扱うもの

+ `{}` か　`[]` のどちらかで表記されているか見極めて、
`[]` なら　配列なので、何番目かを指定する。　
`{}` なら オブジェクトなので、　key　と　value　がコロンで組み合わさって一セットになっているので、keyの部分をドットの後にしていくことで中身にアクセスできる。

##5-2.以下を配列で取得してみる
2. `明日`の
3. `forecasts`の中の`detail`の中の`telop`
4. `forecasts`の中の`chanceOfRain`の中の`T06_12`


```app.js
const axios = require('axios');

const main = async () => {
  try {
    const res = await axios.get('https://weather.tsukumijima.net/api/forecast/city/130010');  
    console.log(res.data.description.headlineText);
    console.log(res.data.forecasts[1].dateLabel);//`明日`は配列の１番目に相当
    console.log(res.data.forecasts[1].telop);
    console.log(res.data.forecasts[1].chanceOfRain);
    
  } catch (error) {
    console.error(error);
  }
}

main();
```

```terminal
tomoko@MB wether % node app.js
東京地方では低い土地の浸水や河川の増水に、伊豆諸島では高波に、東京地方、伊豆諸島南部では落雷に、伊豆諸島南部では濃霧による視程障害に注意してください。
明日
曇り
{ T00_06: '30%', T06_12: '10%', T12_18: '20%', T18_24: '30%' }
```
まだ、`chanceOfRain`の中の`T06_12`　を取得できていないので、もう一工夫。
`chanceOfRain`の中身はオブジェクトなので、ドット記法で書いてみる。

```app.js
const axios = require('axios');

const main = async () => {
  try {
    const res = await axios.get('https://weather.tsukumijima.net/api/forecast/city/130010');  // URLを書き換える
    console.log(res.data.description.headlineText);
    console.log(res.data.forecasts[1].dateLabel);//`明日`は配列の１番目に相当
    console.log(res.data.forecasts[1].telop);
    console.log(res.data.forecasts[1].chanceOfRain.T06_12);//←今ココ
    
  } catch (error) {
    console.error(error);
  }
}

main();
```

```terminal
tomoko@MB wether % node app.js
東京地方では低い土地の浸水や河川の増水に、伊豆諸島では高波に、東京地方、伊豆諸島南部では落雷に、伊豆諸島南部では濃霧による視程障害に注意してください。
明日
曇り
10%
```
無事、欲しい情報を絞り込めた。

#6.結果を会話調にターミナルで表示してみる
できれば、5.で絞り込んだ結果をニュースで聞くような会話調で表示してみたい。
例：`明日`の東京の朝の通勤時間帯のお天気は`曇り`降水確率は　`10%` でしょう。

```app.js
const axios = require('axios');

const main = async () => {
  try {
    const res = await axios.get('https://weather.tsukumijima.net/api/forecast/city/130010');  // URLを書き換える
    const date = res.data.forecasts[1].dateLabel;
    const weather = res.data.forecasts[1].telop;
    const rateOfRain = res.data.forecasts[1].chanceOfRain.T06_12;
    console.log(date + 'の東京の朝の通勤時間帯のお天気は' + weather + '降水確率は' + rateOfRain+'でしょう');

    //console.log(res.data.description.headlineText);
    //console.log(res.data.forecasts[1].dateLabel);//`明日`は配列の１番目に相当
    //console.log(res.data.forecasts[1].telop);
    //console.log(res.data.forecasts[1].chanceOfRain.T06_12);
    
  } catch (error) {
    console.error(error);
  }
}

main();
```

```terminal
tomoko@MB wether % node app.js
明日の東京の朝の通勤時間帯のお天気は曇り降水確率は40%でしょう
```

無事、出力できた。