Riot.jsでAjaxではなくFetchを使って標準的なやりかたでAPIを取得する

Riot.js はカスタムタグを追加していくことで、ひとつのアプリケーションを構築していきます。

たいていのアプリケーションでは外部の RESTful API を呼び出して、そのデータを元に UI を組み立てていきたいと考えるでしょう。

Riot.js のカスタムタグを使って、Facebook のいいね数を取得して表示するというシンプルなカスタムタグを作ってみます。さらに今回は、HTML の新たな標準仕様 [Fetch](https://developer.mozilla.org/ja/docs/Web/API/Fetch_API) を使って**標準的なやりかた**で取得します。

# TL;DR

`<sns-count-facebook>` というカスタムタグを定義して、以下のように呼び出すことを前提にします。

```html
<sns-count-facebook url="https://www.google.com"></sns-count-facebook>
```

カスタムタグの定義はこんな感じになります。

```html:sns-count-facebook.tag
<sns-count-facebook>

    <span>{ count }</span>

    <script>

        this.count = '( Loading... )'

        var self = this

        fetch( 'https://api.facebook.com/restserver.php?method=links.getStats&format=json&urls=' + opts.url )
        .then( function ( data ) {
            return data.json()
        } )
        .then( function ( json ) {
            self.count = json[ 0 ].total_count
            self.update()
        } )
        
    </script>

</sns-count-facebook>
```

ES2015 に対応している場合は [後述](#%E3%83%A2%E3%83%80%E3%83%B3%E3%81%AA%E7%92%B0%E5%A2%83%E3%81%A7%E3%81%AF) のようにシンプルに記述できます。

では詳しく見ていきます。

# まずは静的なカスタムタグを定義

分かりやすくするために Facebook の RESTful API を呼び出さない状態から作ってみます。

```html:sns-count-facebook.tag
<sns-count-facebook>

    <span>{ count }</span>

    <script>

        this.count = '( Loading... )'

    </script>

</sns-count-facebook>
```

表示はこうなります。

```
( Loading... )
```

もちろんこのままでは使い物になりません。

[Fetch](https://developer.mozilla.org/ja/docs/Web/API/Fetch_API) を使って Facebook の RESTful API を呼び出してみます。

# RESTful API の呼び出し

Facebook の RESTful API を呼び出す Fetch はこのようなコードになります。

```js
fetch( 'https://api.facebook.com/restserver.php?method=links.getStats&format=json&urls=' + url )
.then( function ( data ) {
    return data.json()
} )
.then( function ( json ) {
    console.log( json )
} )
```

Ajax は面倒なので jQuery の `$.ajax()` を使いたくなりますが、今や標準でも十分便利な API ができています。

そもそも Ajax は XMLHttpRequest( XHR )を利用した _手法_ の話ですが、Fetch は _低レベルの API_ です。しかも、何もしなくても Promise を返してくれます。

Riot.js には Fetch や Ajax 関連の API はありませんが、標準でできることは標準でやるのが Riot.js の方針です。

ただし Fetch はまだモバイルブラウザなどが対応していないので、[この polyfill](https://www.npmjs.com/package/whatwg-fetch) を利用すると便利です。

# 完成

カスタムタグに Fetch を追記すれば完成です。

```html
<sns-count-facebook>

    <span>{ count }</span>

    <script>

        this.count = '( Loading... )'

        var self = this

        fetch( 'https://api.facebook.com/restserver.php?method=links.getStats&format=json&urls=' + opts.url )
        .then( function ( data ) {
            return data.json()
        } )
        .then( function ( json ) {
            self.count = json[ 0 ].total_count
            self.update()
        } )
        
    </script>

</sns-count-facebook>
```

`count` というテンプレート変数にはデフォルトで `( Loading... )` を入れておいて、Facebook からのレスポンスによって書き換えます。

ポイントは、`this` を `self` にアサインしていることです。

Riot.js はユーザーのインタラクション( `onclick` など )に応じたデータストアの更新は自動的に UI に反映してくれますが、Fetch などそれ以外の場合は `this.update()` を明示的に呼び出す必要があります。[^1]

[^1]: 公式ドキュメントより > http://riotjs.com/ja/api/#tag-update

しかし、Fetch の中では `this` が Riot.js のタグインスタンスを指さないため、事前に `self` のようなその他の変数にアサインしておく必要があります。

## モダンな環境では

ES2015 が利用できる環境か ES5 へのトランスパイルする場合には、アロー関数によってシンプルに書くことができます。

```html
<sns-count-facebook>

    <span>{ count }</span>

    <script>

        this.count = '( Loading... )'

        fetch( 'https://api.facebook.com/restserver.php?method=links.getStats&format=json&urls=' + opts.url )
        .then( data => data.json() )
        .then( json => {
            this.count = json[ 0 ].total_count
            this.update()
        } )
        
    </script>

</sns-count-facebook>
```


## カスタムタグの応用

先ほど作った `<sns-count-facebook>` タグは、単純に Facebook でのいいね数を数字で表示するだけです。

実際には他のカスタムタグから呼び出されることによって、Riot.js の効果を発揮します。

例えば、指定した複数のサイトのいいね数を出す `<sns-count>` というタグを定義してみます。

```html:sns-count.tag
<sns-count>

    <p each="{ opts.items }">
        { title } の Facebook いいね数は <sns-count-facebook url="{ url }"></sns-count-facebook> です。
    </p>

</sns-count>
```

この `<sns-count>` タグを以下のようにマウントすると...

```js
riot.mount( 'sns-count', {
    items : [
        { title : 'Google', url : 'https://www.google.com' },
        { title : 'Facebook', url : 'https://www.facebook.com' },
        { title : 'Twitter', url : 'https://www.twitter.com' }
    ]
} )
```

このように表示されます。

```html
Google の Facebook いいね数は 3704625 です。
Facebook の Facebook いいね数は 75911262 です。
Twitter の Facebook いいね数は 526350 です。
```

Facebook のいいね数を取得/表示するという一連のロジックを呼び出す側から隠蔽できました。

# ライブデモ

ご自分で試されたいという方は Plunker に [ライブデモ](http://plnkr.co/edit/39pvqscrdrJv2aDG12Is?p=preview) を置いたので、いろいろ弄ってみてください。