LoginSignup
7
1

More than 1 year has passed since last update.

【LINE API】Messaging APIのメッセージオブジェクトを検証するAPIを試してみた

Posted at

もう2ヶ月前になりますが、LINE DevelopersからMessaging APIのメッセージオブジェクトを検証するAPIが追加されたと発表がありました。
ニュース:Messaging APIのメッセージオブジェクトを検証するエンドポイントを追加しました | LINE Developers

私としては結構待ち望んでいた機能でもあり、今まで自前でバリデーションを行っていたところを早くこちらに置き換えたいなと思っています。

今回は、こちらのAPIを実際に試してみます。

準備

  • 以下の記事を参考にMessaging APIのチャンネルを作成してください。

  • Messaging APIタブの最下部にあるチャネルアクセストークンで発行ボタンをおして、チャネルアクセストークンを発行しておきます。
    スクリーンショット 2022-12-17 22.12.02.png

  • 環境変数にChannel Access Tokenをセットしておきます。

export CHANNEL_ACCESS_TOKEN={channel access token}

実際に試す

まずは応答メッセージで試してみます。

% curl -v -X POST https://api.line.me/v2/bot/message/validate/reply \
-H "Authorization: Bearer ${CHANNEL_ACCESS_TOKEN}" \
-H 'Content-Type: application/json' \
-d \
'{
  "messages": [
    {
      "type": "text",
      "text": "Hello, world"
    }
  ]
}'

# 結果) 一部マスキングしています

Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying 147.92.144.180:443...
* Connected to api.line.me (147.92.144.180) port 443 (#0)
* ALPN: offers h2
* ALPN: offers http/1.1
*  CAfile: /etc/ssl/cert.pem
*  CApath: none
* (304) (OUT), TLS handshake, Client hello (1):
* (304) (IN), TLS handshake, Server hello (2):
* (304) (IN), TLS handshake, Unknown (8):
* (304) (IN), TLS handshake, Certificate (11):
* (304) (IN), TLS handshake, CERT verify (15):
* (304) (IN), TLS handshake, Finished (20):
* (304) (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / AEAD-AES256-GCM-SHA384
* ALPN: server accepted h2
* Server certificate:
*  subject: C=JP; ST=Tokyo-to; L=Shinjuku-ku; O=LINE Corporation; CN=*.line.me
*  start date: Aug  8 08:36:05 2022 GMT
*  expire date: Sep  9 08:36:04 2023 GMT
*  subjectAltName: host "api.line.me" matched cert's "*.line.me"
*  issuer: C=BE; O=GlobalSign nv-sa; CN=GlobalSign RSA OV SSL CA 2018
*  SSL certificate verify ok.
* Using HTTP2, server supports multiplexing
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* h2h3 [:method: POST]
* h2h3 [:path: /v2/bot/message/validate/reply]
* h2h3 [:scheme: https]
* h2h3 [:authority: api.line.me]
* h2h3 [user-agent: curl/7.84.0]
* h2h3 [accept: */*]
* h2h3 [authorization: Bearer XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX]
* h2h3 [content-type: application/json]
* h2h3 [content-length: 86]
* Using Stream ID: 1 (easy handle 0x7f7982011a00)
> POST /v2/bot/message/validate/reply HTTP/2
> Host: api.line.me
> user-agent: curl/7.84.0
> accept: */*
> authorization: Bearer XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
> content-type: application/json
> content-length: 86
>
* We are completely uploaded and fine
* Connection state changed (MAX_CONCURRENT_STREAMS == 20)!
< HTTP/2 200
< x-xss-protection: 1; mode=block
< x-line-request-id: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
< x-frame-options: DENY
< x-content-type-options: nosniff
< server: envoy
< pragma: no-cache
< expires: 0
< date: Sat, 17 Dec 2022 13:00:37 GMT
< content-type: application/json
< content-length: 2
< cache-control: no-cache, no-store, max-age=0, must-revalidate
<
* Connection #0 to host api.line.me left intact
{}%

無事ステータスコードが200で返ってきました。

次にtypetext1にしてみます。(結果はjqで整形しています。)

% curl -X POST https://api.line.me/v2/bot/message/validate/reply \
-H "Authorization: Bearer ${CHANNEL_ACCESS_TOKEN}" \
-H 'Content-Type: application/json' \
-d \
'{
  "messages": [
    {
      "type": "text1",
      "text": "Hello, world"
    }
  ]
}' | jq

# 結果)
{
  "message": "The request body has 1 error(s)",
  "details": [
    {
      "message": "Must be one of the following values: [text, image, video, audio, location, sticker, template, imagemap, flex]",
      "property": "messages[0].type"
    }
  ]
}

ちゃんとdetailsmessageの中で理由を返してくれています。

試しに存在しないemoji idを送ってみます。

% curl -X POST https://api.line.me/v2/bot/message/validate/reply \
-H "Authorization: Bearer ${CHANNEL_ACCESS_TOKEN}" \
-H 'Content-Type: application/json' \
-d \
'{
  "messages": [
    {
      "type": "text",
      "text": "$ LINE emoji $",
      "emojis": [
        {
          "index": 0,
          "productId": "5ac1bfd5040ab15980c9b435",
          "emojiId": "001"
        },
        {
          "index": 13,
          "productId": "5ac1bfd5040ab15980c9b435",
          "emojiId": "999"
        }
      ]
    }
  ]
}' | jq

# 結果
{
  "message": "A message (messages[0]) in the request body is invalid",
  "details": [
    {
      "message": "Invalid product id or emoji id",
      "property": "emojis"
    }
  ]
}

product idemoji id が間違ってるよ」とちゃんと教えてくれました:tada: 便利!

他には一応以下のメッセージの検証に対応しているようですが、すべてmessagesプロパティ以外のプロパティの値は検証してくれないようなので、あまり使い分けるイメージがわきませんでした。:thinking:
(※どのメッセージ種別もリクエストに含めることができるmessagesオブジェクトの最大件数は5件で、メッセージオブジェクト自体は共通仕様のため。)

種別 エンドポイント
応答メッセージ POST https://api.line.me/v2/bot/message/validate/reply
プッシュメッセージ POST https://api.line.me/v2/bot/message/validate/push
マルチキャストメッセージ POST https://api.line.me/v2/bot/message/validate/multicast
ナローキャストメッセージ POST https://api.line.me/v2/bot/message/validate/narrowcast
ブロードキャストメッセージ POST https://api.line.me/v2/bot/message/validate/broadcast

TypeScriptでの利用例

せっかくなので、TypeScriptで利用する例を書いてみました。
ts-nodeで動くようにしているので、実際に使うときは必要な部分だけパクっていただければと思います。

src/main.ts
import axios from "axios";

// 予め`CHANNEL_ACCESS_TOKEN`という環境変数にチャネルアクセストークンをセットしておく
const CHANNEL_ACCESS_TOKEN = process.env.CHANNEL_ACCESS_TOKEN || "";

// エラーのときの型(detailsの中身)
interface ValidateErrorDetail {
  message: string;
  property: string;
}
// エラーのときの型
interface ValidateError {
  message: string;
  details: ValidateErrorDetail[];
}

const validater = async (body: string) => {
  const headers = {
    "Content-Type": "application/json",
    Authorization: `Bearer ${CHANNEL_ACCESS_TOKEN}`,
  };
  await axios
    .post("https://api.line.me/v2/bot/message/validate/reply", body, {
      headers: headers,
    })
    .then((_) => {
      // 成功した場合は何もしない
    })
    .catch((reason) => {
      const validateError: ValidateError = reason.response.data;
      console.error(validateError);
      throw new Error(validateError.message);
    });
  console.info("Success Validate!");
};

const body = {
  messages: [
    {
      type: "text",
      text: "Hello, world",
    },
  ],
};

validater(JSON.stringify(body));

実際にts-nodeで動かしてみます。

まずはそのまま

% npx ts-node src/main.ts
Success Validate!

次はtypetext1にして実行

% npx ts-node src/main.ts
{
  message: 'The request body has 1 error(s)',
  details: [
    {
      message: 'Must be one of the following values: [text, image, video, audio, location, sticker, template, imagemap, flex]',
      property: 'messages[0].type'
    }
  ]
}
Error: The request body has 1 error(s)
    at /path/to/src/main.ts:28:13
    at processTicksAndRejections (node:internal/process/task_queues:96:5)

こちらも無事使えそうです :tada:

まとめ

使い分け方は思いつかないものの、単純に各メッセージ送信前にこちらで予めバリデーションしておくと良さそうだなと思いました:eyes:

7
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
1