JSON形式のAPIレスポンス構造をNode.jsのREPLで理解する

## この記事の対象者

JSON形式のレスポンスをJavaSciptで処理する際に、

- どういう書き方で書けば欲しい情報が取り出せるのか知りたい
- JSONレスポンスが大きすぎて構造がよくわからない
- APIリクエスト制限が厳しくて何度もリクエストを投げられない
- 参考記事には結果のコードしか載ってなくて初見のAPIをどうやればいいのか

ということがある場合。JSON形式のAPIの扱いに慣れていない人向けです。

## どうやって理解するのか

一旦APIレスポンスをJSONファイルとして出力した後にNode.jsのREPLで読み込んで、対話形式で解析します。
一度JSONファイルとして書き込むことで何度もAPIリクエストを投げる必要がないのでAPIリクエスト制限に引っかかる心配がありません。

## やり方

例としてGitHub APIにて `react` で検索した時の結果をAPIで取得します。
[https://developer.github.com/v3/search/#search-repositories](https://developer.github.com/v3/search/#search-repositories)

ターミナルで下記のコマンドを入力します。
JSON形式のデータ整形に `jq` というツールを使っているので無い場合はコマンド `brew install jq` で入れてください。

```bash
$ curl https://api.github.com/search/repositories?q=react | jq .
```

ターミナルを埋め尽くすほどのAPIレスポンスが帰ってきました。
この状態だと何が何だか分からないので一回JSONファイルに出力します。

```bash
$ curl https://api.github.com/search/repositories?q=react | jq . > result.json
```

```json:result.json
{
  "total_count": 1054700,
  "incomplete_results": false,
  "items": [
    {
      "id": 10270250,
      "node_id": "MDEwOlJlcG9zaXRvcnkxMDI3MDI1MA==",
      "name": "react",
      "full_name": "facebook/react",
      "private": false,
      "owner": {
        "login": "facebook",
        "id": 69631,
        ...
      }
      ...
    }
  ]
}
```

ざっくり構造が見えてきました。まずトップ階層に検索件数が表示され、具体的な中身は `items` の中に `Object[]` として格納されているので、`items[n]` または `map` 関数で取り出せそうだなという目安がつきます。

これからNode.jsのREPLでデータを取り出してみます。

```bash

$ node
Welcome to Node.js v12.3.0.
Type ".help" for more information.
> const data = require("./result")
> data
... // Object形式で出力
```
JSONファイルは `require` で読み込むことでJavaScriptの `Object` として読み込まれます。

Object形式なので下記のように入力するとデータを取り出すことができます。

```bash

> data.total_count
1054700
```
ここで `items` の中から `full_name` のみ取り出してみます。

```bash

> data.items.map(item => item.full_name)
[
  'facebook/react',
  'duxianwei520/react',
  'reactphp/react',
  ...
  'reduxjs/react-redux'
]
```

条件を絞ってみます。 `獲得スターが30k以上` のリポジトリの `full_name` のみ取り出してみます。

```bash

> data.items.filter(item => item.stargazers_count >= 30000).map(item => item.full_name)
[
  'facebook/react',
  'facebook/react-native',
  'ReactTraining/react-router',
  'zeit/next.js',
  'facebook/create-react-app',
  'enaqx/awesome-react'
]
```

`data.items.filter(item => item.stargazers_count >= 30000)` では条件に合致する `Object[]` が帰ってくるのでそれを `map` 関数で取り出しました。

これを実際のAPIレスポンスを扱うスクリプトに適応するとこんな感じです。

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

const http = axios.create({
  baseURL: "https://api.github.com"
});

async function main() {
  try {
    const response = await http.get("/search/repositories", {
      params: {
        q: "react"
      }
    });
    const data = await response.data
    const result = await data.items.filter(item => item.stargazers_count >= 30000)
    console.log(`30000 over stars Repository search by 'react'`);
    result.map(item => console.log(item.full_name))
  } catch (error) {
    console.log(error)
  }
}

main();

```
```bash
$ node index.js 
30000 over stars Repository search by 'react'
facebook/react
facebook/react-native
ReactTraining/react-router
zeit/next.js
facebook/create-react-app
enaqx/awesome-react
```

## まとめ

これで初見のJSON形式のAPIでも対応できると思います。
REPLはレスポンス構造を解析するだけでなく構文のチェックも簡単にできるのでド忘れしやすい僕は多用してます。