Node.js 18 から実験的にグローバルスコープで利用可能になった fetch API を試す（鉄道遅延情報の JSON を取得してみる）

この記事は、最近の技術記事でも話題を見かける「Node.js の fetch API」に関するものです。

●「Node.js 18」がリリース ～fetch API、Web Streams APIがグローバルスコープで利用可能に - 窓の杜
　https://forest.watch.impress.co.jp/docs/news/1404310.html

以前のバージョンでも利用可能にはなっていた fetch API（以前のバージョンだと `--no-experimental-fetch` というフラグが必要だった）ですが、Node.js 18 からはグローバルスコープで利用可能になりました。これを試してみようと思います。

### 余談： ブラウザの Fetch API
なお、ブラウザでは以前から特別な対応なしに [Fetch API](https://developer.mozilla.org/ja/docs/Web/API/Fetch_API) が利用可能でした。そのためブラウザで Fetch API を利用する話は、過去に以下の記事などで取り扱ったことがありました。

●Discordサーバー上のテキストチャンネルへのメッセージングを UIFlow や Fetch API を使って行う（ #GWアドベントカレンダー 4/29 ） - Qiita
　https://qiita.com/youtoy/items/c77106a23b60b364b9a0
　
## Node.js 18 での fetch API
Node.js 18 での fetch API の対応について、公式の情報を見てみます。
以下を見ると __「New globally available browser-compatible APIs」__ と書かれた部分で __「experimental global fetch API」__ という記載があります。

●Node.js 18 is now available! | Node.js
　https://nodejs.org/en/blog/announcements/v18-release-announce/
![Node.js 18 is now available!](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/a018a07a-b386-7737-14f9-1ed927559436.png)

グローバルスコープで利用可能にはなったものの、まだ実験的なものという位置付けは継続となるようです。そして、掲載されているコードは以下のようにシンプルなものです。

```javascript
const res = await fetch('https://nodejs.org/api/documentation.json');
if (res.ok) {
  const data = await res.json();
  console.log(data);
}
```

上記の例は JSON を取得してログに出力しているので、何か JSON でレスポンスを返す API を使ってみることにします。

## 鉄道遅延情報のjson
今回利用するのは、以下の「鉄道遅延情報のjson」です。

●鉄道遅延情報のjson
　https://rti-giken.jp/fhc/api/train_tetsudo/
![鉄道遅延情報のjson](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/c8409277-29fa-e912-cbfe-95b1c8659039.png)

ページトップの説明を見ると、「[Tetsudo.com（鉄道コム）](https://www.tetsudo.com/) の RSS を集計して、遅延している電車を JSON で返す」という仕組みのようです。また、その後の説明を見ていくと、取得元から「10分毎のアクセス」という条件で許可を得ているようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/7505e82f-d7b7-f3fe-9705-b3a3f722a9bf.png)
この部分は、常時情報を取得するような運用をする場合、情報取得頻度を決めるための情報として覚えておくと良さそうです。

利用する際のアクセス先は、公式ページに書かれている `https://tetsudo.rti-giken.jp/free/delay.json` になるようです。

## 鉄道遅延情報のjson を Node.js 18 の fetch API で取得する
JSON の取得元も決まったところで、実際に Node.js 18　の fetch API を使って情報を取得してみます。

「実験的」とは書かれているもののグローバルスコープで利用可能になったということで、Node.js のバージョンを 18 にしておけば、パッケージの追加などなしに利用できそうです。つまり、以下のプログラムを書いて nodeコマンドで実行すれば終わり、となりそう...

```javascript
const res = await fetch("https://tetsudo.rti-giken.jp/free/delay.json");
if (res.ok) {
  const data = await res.json();
  console.log(data);
}
```

`node -v` で、nodeコマンドのバージョンが 18 であることを確認し、上記のプログラムを実行してみます。1点、このプログラムを実行する前に注意が必要なポイントが。

このプログラムをそのまま使うと、fetch の行で「Top-Level Await」を使える必要があり、それに関する対応が必用です。今回は、一番簡単な「拡張子を `js` でなく `mjs` にする」という対処をして進めます。

![コマンドの実行結果](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/6e74b979-bd60-7d21-701d-d37ed4080d36.png)
上記の画像のとおり、 __「ExperimentalWarning: The Fetch API is an experimental feature. This feature could change at any time」__ というメッセージが表示されるものの、無事に鉄道遅延情報の JSON を取得できました。

## おわりに
やる前から想定されてた流れですが、特別苦労するポイントもなく、API からの情報取得があっさりと完了してしまいました。

処理の実行時にも注意されていた、 __「ExperimentalWarning: The Fetch API is an experimental feature. This feature could change at any time」__ という部分、この「仕様が突然変わることがありそう」という記載に注意が必要そうではありますが、これから Node.js で HTTPリクエストの処理を使う際に便利に活用できそうです。

## 【追記】 JSON の内容を使った処理
とりあえずのお試しが、あっさりと終わってしまったため、少しだけ追加の対応をしてみました。具体的な内容は、以下の記事を書いた時にも行ったような、Node.js を使った JSON の中身を扱うような処理です。

●気象庁公式の天気予報の情報を Node.js で取得し中身を検索する（ライブラリに Got を用いる） - Qiita
　https://qiita.com/youtoy/items/c7dba010ab7d0763e879

特定の路線の遅延情報が出ているときに、それに合わせたメッセージを出すような処理を追加してみます。

### 鉄道遅延情報のjson の仕様
[鉄道遅延情報のjson](https://rti-giken.jp/fhc/api/train_tetsudo/) のレスポンスの仕様を確認してみます。

以下の内容は、記事執筆時点で取得した JSON の冒頭部分の抜粋です。

```json
[
  {
    name: '中央･総武各駅停車',
    company: 'JR東日本',
    lastupdate_gmt: 1650796741,
    source: '鉄道com RSS'
  },
  {
    name: '青梅線',
    company: 'JR東日本',
    lastupdate_gmt: 1650796741,
    source: '鉄道com RSS'
  },
  ・・・（省略）・・・
]
```

取得した情報の中の「name」を見ていき、自分が利用している路線の名前があるかどうかを判定すれば良さそうです。とりあえず、記事執筆時点で遅延情報が出ているものの中の 1つの「青梅線」を対象に処理を追加してみます。

```javascript
const res = await fetch("https://tetsudo.rti-giken.jp/free/delay.json");
if (res.ok) {
  const data = await res.json();
  // console.log(data);

  for (const element of data) {
    if(element.name === "青梅線") {
      console.log("青梅線が遅延しています！");
    }
  }
}
```

あとは、念のため[鉄道遅延情報のjson のトップページ](https://rti-giken.jp/fhc/api/train_tetsudo/)で、上記の条件に利用した「青梅線」が JSON に含まれた状態であることを確認してから、nodeコマンドによる実行をします（以下が、確認時に表示されていた内容です）。
![処理の実行直前の JSON の内容](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/de360512-8fa9-8056-17a1-89242922c0f3.png)

そして、「青梅線が遅延しています！」というメッセージが表示されるのを確認できました。

## 【追記】