LINE Messaging APIの新機能 Flex Messageを試してみた

# はじめに

先月(2018/6/12)、LINE BOTの作成に用いられるLINE Messaging APIに新しいメッセージタイプ **Flex Message** が
追加されました。

これはいくつか準備されている構成要素を組み合わせることで今までのメッセージタイプより一層自由に
カスタマイズできるようになったメッセージです。

![28626_2.jpg](https://qiita-image-store.s3.amazonaws.com/0/203817/011f2fec-494d-8e43-b73e-a46e9c3495cf.jpeg)

上記のように、画像やボタン、テキストを自由に組み合わせ、
よりフロントエンドに近しいメッセージを簡単に作成することができます。

今回はこれをドキュメントに沿って、どんなことができるのかを追っていこうと思います。
こちらが公式のドキュメントになります。
https://developers.line.me/ja/docs/messaging-api/flex-message-elements/

# 想定読者
- LINE BOTに興味があり、簡易なBOTを作成したことがある方
- LINE BOTの新機能を取り入れてみたい方

# つくりかた
LINE BOT自体の作成方法については、以前投稿したものがあるので、
今回はFlex Messageの機能に絞って書いていきます。

LINE BOTの作成方法については、以下をご覧ください。
[ディズニーの待ち時間を教えてくれるLINE botを作ってみた](https://qiita.com/daitasu/items/8f568ee72fe99899cdd6)
※現在はDOM構成が変わってBOTが動かなくなってます、ごめんなさい。

今回はNode.jsのSDKを用いて作成していきます。

## 簡易なBOTの作成
Flex Messageに入る前に、比較として標準のテキストタイプ、画像タイプを用いたBOTを作成します。
まずは、以下のようなBOTを作ります。
- 「疲れた」 というとねぎらいの猫画像を返す
- それ以外のメッセージにはおうむ返しする

```js
const express = require('express');
const linebot = require('@line/bot-sdk');
const config = {
    channelAccessToken: process.env.YOUR_CHANNEL_ACCESS_TOKEN,
    channelSecret: process.env.YOUR_CHANNEL_SECRET
};
const app = express();

app.set('port', (process.env.PORT || 3030));
app.post('/', linebot.middleware(config), (req, res) => {
    Promise
        .all(req.body.events.map(handleEvent))
        .then(result => res.json(result));
});

const client = new linebot.Client(config);
function handleEvent(event) {
    this.line = event;
    switch(event.type) {
        case 'message':
            messageEvent();
            break;
        case 'follow':
            followEvent();
            break;
        case 'unfollow':
            unfollowEvent();
            break;
        default:
            return Promise.resolve(null);
    }
}

function messageEvent() {
    const {
        type,
        text,
    } = this.line.message;

    if (type !== 'text') {
        return Promise.resolve(null);
    }

    if (text.includes('疲れた') || text.includes('つかれた') || text.includes('ツカレタ')) {
        return client.replyMessage(this.line.replyToken, {
            "type": "image",
            "originalContentUrl": "<猫の画像Url>",
            "previewImageUrl": "<猫の画像Url>"
        });
    }
    return client.replyMessage(this.line.replyToken, {
        type: 'text',
        text: text
    });
}

app.listen(app.get('port'), function() {
    console.log('Node app is running -> port:', app.get('port'));
});
```

これで以下のようなBOTが完成します。
<img width="300" alt="Image from iOS.png" src="https://qiita-image-store.s3.amazonaws.com/0/203817/a6190b39-81fa-e5ce-e1fe-b2ec311081c2.png">

## Flex MessageでのBOT作成
さて、ここから本題に入ります。利用方法は、上記で作成したBotにおけるreplyMessageのオブジェクト部分を
書き換えていただければ動くかと思います。
Flex Messageは色々な要素の組み合わせから成るのですが、
大枠として理解しないといけないのは3つの構成要素です。

1. コンテナ
2. ブロック
3. コンポーネント

## コンテナ
コンテナはFlex Messageの最上位の構造です。
バブルとカルーセルの二つのタイプからなります。
バブルは1つのメッセージバブルを構成するコンテナです。
今回はQiita記事を取得する1つのバブルコンテナを作成していきます。

バブルを横にずらっと並べてスクロールできるようにしたのがカルーセルになります。
最大バブル数は10個のようです。

## ブロック
ひとつのバブルを構成する要素がブロックです。

| タイプ             | 詳細 | 
|:-----------------|:------------------|
| Header           |  メッセージのタイトルを配置します。 |      
| Hero             |  主要な画像コンテンツを配置します。画像コンポーネント(後述)を指定します。| 
| Body             |  メインとなるメッセージ、説明文などを記載します。|  
| Footer           |  ボタンや補足情報などを記載します。| 

4つとも必須なわけではなく、省略することも可能です。
また、stylesプロパティというものを用いて、背景色の変更なども可能です。

```json
{
        "type": "flex",
        "altText": "hogehoge",
        "contents": {
            "type": "bubble",
            "styles": {
                "header": {
                    "backgroundColor": "#ff62ae"
                },
                "body": {
                    "backgroundColor": "#5bff54"
                },
                "footer": {
                    "backgroundColor": "#7b78ff"
                }
            },
            "header": {
                "type": "box",
                "layout": "vertical",
                "contents": [
                    {
                        "type": "text",
                        "text": "header"
                    }
                ]
            },
            "hero": {
                "type": "image",
                "url": "<imageUrl>",
                "size": "full",
                "aspectRatio": "1:1"
            },
            "body": {
                "type": "box",
                "layout": "vertical",
                "contents": [
                    {
                        "type": "text",
                        "text": "body"
                    }
                ]
            },
            "footer": {
                "type": "box",
                "layout": "vertical",
                "contents": [
                    {
                        "type": "text",
                        "text": "footer"
                    }
                ]
            }
        }
}
```

<img width="300" alt="Image from iOS.png" src="https://qiita-image-store.s3.amazonaws.com/0/203817/56ca9ed2-36f9-da02-3f76-edd9cc461754.png">

## コンポーネント
ブロック要素を構成するものです。
以下のような種類から組み合わせることが可能です。

- ボックス
- ボタン
- フィラー
- アイコン
- 画像
- セパレータ
- スペーサー
- テキスト

いくつか具体例をあげてみましょう。
### アイコン

上記のbodyブロックだけを残し、body配下を書き換えていきます。
※サンプル画像と同じにするには、`<>`内をQiita APIから取得して書き換えて下さい。

```json
  {
            "type": "box",
            "layout": "vertical",
            "contents": [
                {
                    "type": "box",
                    "layout": "baseline",
                    "contents": [
                        {
                            "type": "icon",
                            "url": "<imageUrl>",
                            "size": "xl"
                        },
                        {
                            "type": "text",
                            "text": "<text>",
                            "size": "lg"
                        }
                    ]
                },
                {
                    "type": "box",
                    "layout": "baseline",
                    "contents": [
                        {
                            "type": "icon",
                            "url": "<imageUrl>",
                            "size": "xl"
                        },
                        {
                            "type": "text",
                            "text": "<text>",
                            "size": "lg"
                        }
                    ]
                }
            ]
}
```

![Image from iOS (1).png](https://qiita-image-store.s3.amazonaws.com/0/203817/b8a76d12-7732-d8de-6231-27043bf04993.png)


### セパレータ
次に、セパレータというものを入れて見やすくしてみます。
上記の各Boxの間に以下を挟んでみましょう。

```json
{
   "type": "separator"
}
```

![Image from iOS (2).png](https://qiita-image-store.s3.amazonaws.com/0/203817/afba6872-9c10-390d-1f5f-92dd9a282912.png)

### 画像
アイコンだとちょっと形がずれてるのが気になるので、画像コンポーネントを使いいくつかのプロパティを試してみます。
それぞれのboxを書き換えます。
- gravity・・・垂直方向の配置スタイル。上下中央揃えができます
- flex・・・contents内のそれぞれのコンポーネントをその比率で配置します
- aspectMode・・・画像の表示形式。描画領域全体に画像を写すか、余白をいれるかを決められます
他にも色々あるので試してみて下さい。

```json
{
                "type": "box",
                "layout": "horizontal",
                "contents": [
                    {
                        "type": "image",
                        "url": "<imageUrl>",
                        "size": "xxs",
                        "aspectMode": "cover",
                        "backgroundColor": "#DDDDDD",
                        "gravity": "center",
                        "flex": 1
                    },
                    {
                        "type": "text",
                        "text": "<text>",
                        "gravity": "center",
                        "size": "xs",
                        "flex": 7
                    }
                ]
}
```

![imageCon.png](https://qiita-image-store.s3.amazonaws.com/0/203817/4d7fa596-dbac-c2ea-6be4-a9ee5d57e86a.png)


### ボタン
やはり、各記事やQiitaへのリンクを貼りたいので、ボタンコンポーネントを使います。
各boxを以下のように書き換えます。
この際、`label`は20字以内なので注意しましょう。

```json
{
                "type": "box",
                "layout": "horizontal",
                "contents": [
                    {
                        "type": "image",
                        "url": "<imageUrl>",
                        "size": "xxs",
                        "aspectMode": "cover",
                        "backgroundColor": "#DDDDDD",
                        "gravity": "center",
                        "flex": 1
                    },
                    {
                        "type": "button",
                        "style": "link",
                        "height": "sm",
                        "action": {
                            "type": "uri",
                            "label": "<text>",
                            "uri": "<docUrl>"
                        },
                        "flex": 7
                    }
                ]
}
```

次に、footerとして以下を追加します。

footer

```json
{
        "type": "box",
        "layout": "vertical",
        "contents": [
            {
                "type": "button",
                "style": "secondary",
                "action": {
                    "type": "uri",
                    "label": "more",
                    "uri": "https://qiita.com/"
                }
            }
        ]
}
```

![Image from iOS (4).png](https://qiita-image-store.s3.amazonaws.com/0/203817/efd518f9-0ff9-fe3d-7c6e-21cb1c9c2686.png)

## 完成
最後に、`header`と`hero`も足していきましょう。

header

```json
{
            "type": "box",
            "layout": "baseline",
            "contents": [
                {
                    "type": "text",
                    "text": "Qiita最新投稿",
                    "weight": "bold",
                    "color": "#7e7e7e",
                    "size": "xl"
                }
            ]
}
```

hero

```json
{
            "type": "image",
            "url": "<logoUrl>",
            "size": "full",
            "aspectRatio": "3:1",
            "aspectMode": "cover"
}
```

<img width="300" alt="Image from iOS (5).png" src="https://qiita-image-store.s3.amazonaws.com/0/203817/8e6dbc3d-ffb0-74b6-2cd7-91d1d2dd7f4d.png">

# 補足
LINE DevelopersにFlex MessageのJSONデータを簡単にシミュレートできるページがあるようです。
一旦ここで試してみて、完成したら実装、という方がよさそうですね。
[Flex Message Simulator](https://developers.line.me/console/fx/)

# 感想
オブジェクトの組み合わせでさくっと作れるというのが何よりの魅力でした。
あまり開発に詳しくない方でも流れさえ理解できればそんなに学習コストは高くなさそう。
何に用いるか、どんなUIで利用するかの発想次第で面白いものが作れそうです。

Flex Messageと同時期にLIFF(LINE Front-end Framework)
というものも公表されております。こちらは実際にWEBページを作成し、
それをLINEアプリ内で呼び出して直接LINE IDと紐付けができるそうな。(LINE LOGINの代替にできる？)
こちらもそのうち勉強してみようと思います。