【LINE WORKS】Flexible Template API をいじり倒してみた

提供されてからずいぶんと経ってしまいましたが、ようやくいじり倒す機会がやってきましたよ！ヾ(*´∀｀*)ﾉ

[LINE WORKS Developers - Flexible Template](https://developers.worksmobile.com/jp/document/100500820?lang=ja)

![525.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363367/41db960f-93bc-47da-3946-f613f8990d8d.png)


CSS 要素が満載のデザイン性バリ高な機能。
馬を描いたら友人に「４本脚で立っているのが奇跡だな」と言われた私には荷が重いかもしれませんが頑張ります（　＾ω＾）

# Flexible Template の使い方

Flexible Template と言えどメッセージ送信 API の一部なので、認証方法や Request URL はメッセージ送信 API と同じ。
慣れ親しんだやつらなので安心ですね(^_-)-☆
[LINE WORKS Developers - メッセージ送信](https://developers.worksmobile.com/jp/document/1005008?lang=ja)

`content` パラメータの中身を Flexible Template の構成で書いてあげれば良いわけです。
なーんだ、簡単じゃん！(*‘∀‘)

…フラグですよ( ﾟДﾟ)

## メッセージ送信（Flexible Template）のコード

まずはサンプルコードを見てみましょう。 

```js
{
  "accountId": "admin@example.com",
  "content": {
    "type": "flex",
    "altText": "this is a flexible template",
    "contents": {
      "type": "bubble",
      "body": {
        "type": "box",
        "layout": "vertical",
        "contents": [
          {
            "type": "text",
            "text": "hello"
          },
          {
            "type": "text",
            "text": "world"
          }
        ]
      }
    }
  }
}
```

お、なんだなんだ。大したことないじゃないですか！(*´Д｀)

`"type": "flex"` を指定して Flexible Template を使うぞーと宣言。
`"altText": "this is a flexible template"` はポップアップ通知で表示する内容みたいですね。
![1620809442.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363367/c84fa489-22e6-be74-5a12-b186f795991d.png)

`"contents": {}` 最後に contents を Flexible に指定してあげれば良いわけですよ！

なんだ、やっぱりかんたーんじゃないですか♪

……フラグですよ( ﾟДﾟ)

## Flexible Template の構成

[LINE WORKS Developers - Flexible Template の要素](https://developers.worksmobile.com/jp/document/100500821?lang=ja)

公式ドキュメントを読むと詳しく書いてありますが、ざっくり図にするとこんな感じ。

![contener.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363367/327a2a49-199a-77a5-5453-2aa1771b9bca.png)

コンテナの中にブロックがあって、それぞれのブロックの中にコンポーネントが入る、と。
なんだかネストが激しくなりそうですが、まぁ、それは仕方ないですね。

では、コンテナの書き方を見ていきましょーヾ(*´∀｀*)ﾉ

### コンテナ

[LINE WORKS Developers - コンテナ](https://developers.worksmobile.com/jp/document/100500831?lang=ja) 

コンテナは **バブル (bubble)** と **カルーセル (carousel)** の２種類があるようです。

どうやら **カルーセル (carousel)** はバブルの集合体のようなので、バブルを攻略できれば良いわけですね！
ふふふ、見えたぞ、天王山！(｀・ω・´)

それでは、バブルのサンプルコードを見ていきましょう。

```json
{
  "type": "bubble",
  "header": {
    "type": "box",
    "layout": "vertical",
    "contents": [
      {
        "type": "text",
        "text": "Text Component",
        "weight": "bold"
      }
    ],
    "paddingAll": "10px",
    "paddingStart": "15px"
  },
  "hero": {
    "type": "image",
    "url": "https://i.ibb.co/RbvxLhg/Image-Component.png",
    "size": "full",
    "aspectMode": "cover",
    "aspectRatio": "2:1"
  },
  "body": {
    "type": "box",
    "layout": "vertical",
    "contents": [
      {
        "type": "box",
        "layout": "horizontal",
        "contents": [
          {
            "type": "box",
            "layout": "vertical",
            "contents": [
              {
                "type": "image",
                "url": "https://i.ibb.co/4dTjScT/Image.png",
                "size": "lg"
              }
            ],
            "borderWidth": "2px",
            "borderColor": "#90909050",
            "width": "93px",
            "height": "93px"
          },
          {
            "type": "box",
            "layout": "vertical",
            "contents": [
              {
                "type": "separator",
                "color": "#909090"
              },
              {
                "type": "text",
                "text": "Text Component 01"
              },
              {
                "type": "separator",
                "color": "#909090"
              },
              {
                "type": "text",
                "text": "Text Component 02"
              },
              {
                "type": "separator",
                "color": "#909090"
              }
            ],
            "height": "100px",
            "margin": "md",
            "spacing": "lg"
          }
        ]
      },
      {
        "type": "box",
        "layout": "horizontal",
        "contents": [
          {
            "type": "box",
            "layout": "vertical",
            "contents": [
              {
                "type": "image",
                "url": "https://i.ibb.co/4dTjScT/Image.png",
                "size": "lg"
              }
            ],
            "borderWidth": "2px",
            "borderColor": "#90909050",
            "width": "93px",
            "height": "93px"
          },
          {
            "type": "box",
            "layout": "vertical",
            "contents": [
              {
                "type": "separator",
                "color": "#909090"
              },
              {
                "type": "text",
                "text": "Text Component 03"
              },
              {
                "type": "separator",
                "color": "#909090"
              },
              {
                "type": "text",
                "text": "Text Component 04"
              },
              {
                "type": "separator",
                "color": "#909090"
              }
            ],
            "height": "100px",
            "margin": "md",
            "spacing": "lg"
          }
        ],
        "margin": "md"
      }
    ]
  },
  "footer": {
    "type": "box",
    "layout": "vertical",
    "contents": [
      {
        "type": "button",
        "action": {
          "type": "uri",
          "label": "Button Component",
          "uri": "http://linecorp.com/"
        },
        "height": "sm",
        "style": "link"
      }
    ]
  }
}
```

Σ(ﾟДﾟ)

ななな、なんじゃこりゃー！(ﾟДﾟ)

はい！フラグ回収きましたー♪(^_-)-☆

長すぎ！スクロールするの大変！わけわからんですよもう！(; ･`д･´)

心が折れかけたあなた！私も同感です。
そこで、少し見方を変えてみましょう。

### コンテナはブロックの集合体

いっぺんに全部見るからいけないのです。
ブロックの集まりがコンテナなんだから、まずはブロックを攻略すればいいんですよ！(｀･ω･´)ｷﾘｯ

ブロックは全部で４種類。

- header
- hero
- body
- footer

header とかはなんとなくわかるんですが **hero** ってなんだろう。
傷だらけのやつだろうか。誰でもそうなんだよってやつだろうか。

とかなんとか考えながらググってみたところ、HTML 界隈では**ヒーローイメージ**とかいう当たり前の言葉だったんですね。恥ずかしい(*ﾉωﾉ)
恥をかいた分、しっかり覚えました。

脱線したので話を戻します。

ブロックは１つでも指定すればいいので、最初は簡単に body だけでも良さそうですね。
そして body の中に何を入れるかと言うと、ボックスというコンポーネントを入れるようです。

### ブロックの中にはコンポーネントを入れる

[LINE WORKS Developers - ボックス](https://developers.worksmobile.com/jp/document/100500841?lang=ja)

ブロックの中にはコンポーネントを入れるんですが、ボックスでレイアウトとかを定義して細かいボタンやらテキストやらのコンテンツを入れるので、それはつまり

**ブロック ＝ ボックス**

って考えても良いかと。
いや、厳密に言うと違うんですけど、イメージ的に自分がわかりやすそうだったので。

何はともあれ、このボックスちゃんを攻略すれば Flexible Template を攻略したも同然ですよ！( ﾟДﾟ)

### ボックスの中に入れるコンテンツは７種類

- ボックス
- ボタン
- 画像
- テキスト
- セパレータ
- フィラー
- スペーサー(未推奨)

よく使うのは、ボタン、画像、テキスト、セパレータあたりでしょうか。

ボックスの中にボックスを入れるのは、もう延々とマトリョーシカのごとく面倒そうなので、最初はやらなくてもいいですね！( ﾟДﾟ)

### コンテンツを組み合わせてボックスを作る！

じゃー、実際に作ってみましょうかね！

なるべく最小限な感じで、**ボタン、画像、テキスト、セパレータ**を使って作ってみました。(*‘∀‘)

```json:messageBody.json
{
    "accountId": "xxx@yyy-zzz",
    "content": {
        "type": "flex",
        "altText": "This is a Flex Message from the Demon King",
        "contents": {
            "type": "bubble",
            "body": {
                "type": "box",
                "layout": "vertical",
                "backgroundColor": "#000000",
                "spacing": "md",
                "contents": [{
                    "type": "image",
                    "url": "https://xxxx.com/xxxx.png"
                },{
                    "type": "text",
                    "text": "お前に世界の半分をやろう...",
                    "color": "#dc143c",
                    "weight": "bold"
                },{
                    "type": "separator"
                },{
                    "type": "button",
                    "style": "secondary",
                    "color": "#c0c0c0",
                    "action": {
                        "type": "message",
                        "label": "全部よこせ。",
                        "text": "Yes!"
                    }
                },{
                    "type": "button",
                    "style": "secondary",
                    "color": "#c0c0c0",
                    "action": {
                        "type": "message",
                        "label": "元から全てオレの物だ。",
                        "text": "No!"
                    }
                }]
            }
        }
    }
}
```

![1620896732.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363367/e9de3d8e-b5e6-5ffc-f93f-7cc33fda73ab.png)

あ、これ、割と作るの楽しいですね。(*´Д｀)

えっと、今回は簡単に Body ひとつで納めましたが、本当は hero とか使い分けた方がいいのかな？

軽く解説しますね。

#### 画像コンポーネント

body の一番上が画像になっています。

```json
{
  "type": "image",
  "url": "https://xxxx.com/xxxx.png"
}
```

画像は透過PNGなのですがこのコンポーネントでは背景色は設定できないみたいです。
[LINE WORKS Developers - 画像](https://developers.worksmobile.com/jp/document/100500843?lang=ja)

なので、body の設定で背景を黒にしました。

#### テキスト コンポーネント

次に魔王のセリフですね。
文字色は血染めのクリムゾンにしてみました（何

```json
{
  "type": "text",
  "text": "お前に世界の半分をやろう...",
  "color": "#dc143c",
  "weight": "bold"
}
```

これ、デフォルトだと文字数多すぎると省略されちゃうみたいです。
いっぱい書きたい方は `wrap` または `maxLines` パラメータを使用すると全文字表示できるようです。
[LINE WORKS Developers - テキスト](https://developers.worksmobile.com/jp/document/100500845?lang=ja)

#### セパレータ コンポーネント

境界線ですね。ボーダー。
特になくてもいいんですが、明確にセリフを分けるときにはあった方がわかりやすいですよね！

```js
{
  "type": "separator"
}
```

あ、今回特に指定しませんでしたが、色は変えられるみたいですよ( ﾟДﾟ)
[LINE WORKS Developers - セパレーター](https://developers.worksmobile.com/jp/document/100500847?lang=ja)

#### ボタン コンポーネント

ボタンですね。押すと色々と起きるやつ。
ボタンを押したあとどんな動きをするかは [Action Objects](https://developers.worksmobile.com/jp/document/1005050?lang=ja) で設定します。

```json
{
  "type": "button",
  "style": "secondary",
  "color": "#c0c0c0",
  "action": {
      "type": "message",
      "label": "全部よこせ。",
      "text": "Yes!"
  }
}
```

`style` パラメータでボタンの形を変えられます。
と、言ってもまだ３パターンしかないようです。
これからバリエーション増えるのかな？

primary
![primary.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363367/45f97f42-5b43-a8ff-7a51-99665469260e.png)
secondry
![secondry.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363367/c471973e-b9f7-b490-78ed-5790c3c246a7.png)
link
![link.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363367/1276275f-bd85-2ce9-947d-0241ed631431.png)


link はボタンっぽくはしてくれないみたいですね。
[LINE WORKS Developers - ボタン](https://developers.worksmobile.com/jp/document/100500842?lang=ja)

## ボックスの中にボックスを入れてさらにボックスを…

最期に、マトリョーシカ状態にチャレンジしてみましょう！ヾ(*´∀｀*)ﾉ
<details><summary>あ、今回もコード長いので見たい方はクリックして広げてみてくださいね。</summary><div>

```json
{
    "accountId": "xxxx@xxxxxx",
    "content": {
        "type": "flex",
        "altText": "This is a Flex Message",
        "contents": {
            "type": "bubble",
            "body": {
                "type": "box",
                "layout": "vertical",
                "spacing": "md",
                "contents": [{
                    "type": "image",
                    "url": "https://1.bp.blogspot.com/-DXwO_MFUgkM/UZ2VFQc90MI/AAAAAAAATuQ/Q0Qk05Ut9JE/s800/matryoshkas.png"
                },{
                    "type": "text",
                    "text": "マトリョーシカ 1",
                    "color": "#008000",
                    "weight": "bold"
                },{
                    "type": "separator"
                },{
                    "type": "box",
                    "layout": "horizontal",
                    "spacing": "md",
                    "contents": [{
                        "type": "image",
                        "url": "https://1.bp.blogspot.com/-DXwO_MFUgkM/UZ2VFQc90MI/AAAAAAAATuQ/Q0Qk05Ut9JE/s800/matryoshkas.png"
                    },{
                        "type": "text",
                        "text": "マトリョーシカ 2",
                        "wrap": true,
                        "color": "#008000",
                        "weight": "bold"
                    },{
                        "type": "separator"
                    },{
                        "type": "box",
                        "layout": "vertical",
                        "spacing": "md",
                        "contents": [{
                            "type": "image",
                            "url": "https://1.bp.blogspot.com/-DXwO_MFUgkM/UZ2VFQc90MI/AAAAAAAATuQ/Q0Qk05Ut9JE/s800/matryoshkas.png"
                        },{
                            "type": "text",
                            "text": "マトリョーシカ 3",
                            "wrap": true,
                            "color": "#008000",
                            "weight": "bold"
                        },{
                            "type": "separator"
                        },{
                            "type": "box",
                            "layout": "horizontal",
                            "contents": [{
                                "type": "image",
                                "url": "https://1.bp.blogspot.com/-DXwO_MFUgkM/UZ2VFQc90MI/AAAAAAAATuQ/Q0Qk05Ut9JE/s800/matryoshkas.png"
                            },{
                                "type": "text",
                                "text": "マト 4",
                                "wrap": true,
                                "color": "#008000",
                                "weight": "bold"
                            },{
                                "type": "separator"
                            }]
                        }]
                    }]
                }]
            }
        }
    }
}
```

</div></details>

![1621394362.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363367/ba04b4cd-86f9-ff0e-14ee-9219007466a1.png)

これ、延々とできますね。

![1621394764.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363367/bf50953e-ef79-83ac-feaf-0e03dd79702f.png)

と、思いましたが８マトリョーシカ目で画面からはみ出てしまいましたね。
まぁ、何事にも節度と言うものがありますからね！( ﾟДﾟ)

# おわりに

ここまでお付き合いいただきありがとうございました。

さぁ、最下層についたぞ！と、思いきやさらに下層があるなんて。。。
こだわり始めたら底なし沼クラス。
しかしその分、細部までこだわれる玄人志向。(●з●)

将来性の高い、デザイン性に富んだ機能だと思いました！
少しはデザインの勉強もしようかな？

最期に、私の描いた馬を貼っておきます。
ではまた！(^^)/

![uma.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363367/714ffe75-8dc6-46cc-639d-d4951e4ea799.png)

# 参考にさせていただきましたm(_ _)m

[LINE WORKS Developers](https://developers.worksmobile.com/jp/?lang=ja)

[かわいいフリー素材集 いらすとや](https://www.irasutoya.com/)