HTMLに直書きされたJSONをaxiosで取得する

## はじめに
[axios](https://github.com/axios/axios)便利ですねー。
axiosの`adapter`を使って、HTMLに直書きされたJSONを取得するサンプルコードを書いてみました。

## やりたいこと

こんなことが、できたらいいなーと思いました。

- Ajax通信用のライブラリとして、axiosを使用する
- AjaxでJSONを取得する処理を挿げ替えて、デモ用データを取得するようにしたい
- デモ用データの取得では、サーバへの通信をさせたくない
- デモ用データは、HTMLに直書きしたい
- デモ用データは、純粋なJSONとして記述したい

以下のような利用シーンを想定しています。

- HTMLだけで完結させたい簡単なデモ
- JSONを返すサーバがない状態での動作確認


以降、この記事中では「HTMLに直書きされたJSON」を「直書きJSON」と記載します。


## 実現方法

以下の手順で実現できます。

1. 「直書きJSON」は、`script`タグで埋め込む
2. axiosのHTTP通信処理を、カスタム処理に置き換える

では、順番にみていきましょう。


### 「直書きJSON」は、`script`タグで埋め込む
HTMLにJSONを直書きするには、`script`タグを使用します。
このとき、`type`には`application/json`を指定する必要があります[^note-type]。

また、JavaScriptから操作しやすいように`id`も指定しておきます。

```HTML:HTMLにJSONを埋める例
<script type="application/json" id="mock-json-xxx">
  {"aaa":123,"bbb":"abc","ccc":"def","ddd":456}
</script>
```

[^note-type]: 実際には、JavaScriptとして解釈されない値であれば何でもよいです。ただし、`type`を省略するとJavaScriptとして解釈されるので必ず指定しましょう。


### axiosのHTTP通信処理を、カスタム処理に置き換える

axiosでは`adapter`を指定することで、HTTP通信処理をカスタムできます。
以下、axiosのREADMEから抜粋します。

> `adapter` allows custom handling of requests which makes testing easier.
> Return a promise and supply a valid response (see [lib/adapters/README.md](https://github.com/axios/axios/tree/master/lib/adapters)).

具体的な`adapter`の内容は、つぎのサンプルコードをご参照ください。


## サンプルコード

というわけで、サンプルコードです。
このサンプルでは、Qiitaの[「タグ取得」API](https://qiita.com/api/v2/docs#get-apiv2tagstag_id)の呼び出しを「直書きJSON」の取得に挿げ替えています。

```html:サンプルコード.html
<!-- axios(このサンプルではCDNを使用する) -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

<!--
  「直書きJSON」をHTMLに埋めておく
  (idを`mock-json-xxx`の形式にしておく)
-->
<script type="application/json" id="mock-json-javascript">
  {"followers_count":54321,"icon_url":"http://example.com/icon.png","id":"JavaScript","items_count":12345}
</script>
<script type="application/json" id="mock-json-axios">
  {"followers_count":30,"icon_url":null,"id":"axios","items_count":60}
</script>

<!--
  axiosで「直書きJSON」を取得する準備
-->
<script>
/** axiosのconfigから「直書きJSON」の要素IDを算出する */
function mockElementId(config) {
  var url = config.url; // リクエスト先として指定されたURL

  // URLの最後の'/'の後の文字列をtagIdとして取得
  var s = url.split('/');
  var tagId = s[s.length - 1];

  // 要素IDは、'mock-json-xxx'
  return 'mock-json-' + tagId;
}

// axiosのインスタンスを生成(adapter指定)
var myAxios = axios.create({
  // 「直書きJSON」の内容をResponseとする関数を設定
  adapter: function(config) {
    // リクエスト先ごとに定義した「直書きJSON」を取得
    var elmId = mockElementId(config); // 「直書きJSON」の要素IDを算出
    var mockJson = document.getElementById(elmId).textContent;

    // Responseを模倣したオブジェクトを返す
    // (axiosの仕様に従い、adapterの戻り値はPromiseとする)
    return Promise.resolve({
      'status': 200, // OK
      'data': JSON.parse(mockJson) // JSONのパース結果をdataとする
    });
  }
});
</script>

<!--
  myAxiosを使用する箇所は変更の必要なし
-->
<script>
// タグ取得API呼び出し('javascript')
myAxios
  .get('https://qiita.com/api/v2/tags/javascript')
  .then(function(response) {
    console.log(response.data);
  });
// タグ取得API呼び出し('axios')
myAxios
  .get('https://qiita.com/api/v2/tags/axios')
  .then(function(response) {
    console.log(response.data);
  });
</script>
```

<p data-height="265" data-theme-id="0" data-slug-hash="oqQNpj" data-default-tab="html" data-user="pale2f" data-embed-version="2" data-pen-title="oqQNpj" class="codepen">See the Pen <a href="https://codepen.io/pale2f/pen/oqQNpj/">oqQNpj</a> by pale2f (<a href="https://codepen.io/pale2f">@pale2f</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>
(CodePenを埋め込んでみましたが、consoleに書いているだけなので画面には何も表示されません)

このサンプルでは実装していませんが、`adapter`の指定を簡単に切り替えられるようにしておくとよいでしょう。

## 最後に

最後に、サンプルを動作させる際の注意点を挙げておきます。

- IE11は、Promise未対応
- Chromeは、ローカルHTMLでスクリプトが動作しない

いずれも、解決方法はググればすぐに見つけられるでしょう。