ReactとNextJSを使用してChatworkのチャットにメッセージを投稿する

Posted at 2023 年 10 月 13 日

Chatworkとの連携に関するプログラム開発については、Chatwork APIのドキュメンテーションを学ぶことで、様々な機能を活用できます。

この記事では、ReactとNextJSを利用してChatworkグループにメッセージを送信する方法に焦点を当てています。

必要な前提条件

  1. Chatworkアカウント: Chatwork Group Chatにメッセージを送信するには、まずChatworkのアカウントが必要です。

    アカウントをお持ちでない場合は、こちらでアカウントを作成してください。

  2. Chatworkグループチャット: 通知を送るためには、Chatworkグループを作成します。

    グループの作成方法が不明な場合は、こちらを参考にしてください。

  3. ChatworkAPIの理解:ChatworkAPIの使い方については、こちらを参照してください。

Chatwork APIについて

Chatwork APIは外部のプログラムから容易に使用でき、Chatworkで発生したイベントを外部のプログラムに提供できます。

Chatwork APIを活用したプログラムの開発、またはIFTTTZapierなどのiPaaSを使用することで、以下のような連携が可能になります。

  • 自分宛てにメールが届いたらChatworkにメッセージとして転送する
  • サーバーエラーを検知し関係者にタスクを振る
  • カレンダーに予定が追加されたら、Chatworkでタスクを振る

※エンドポイント、メッセージ記法、OAuth 2.0、Webhookなどの詳細については、Chatwork公式ページをご参照ください。

実装方法

  1. APIトークンの取得
    • chatworkの画面右上のプロフィールをクリックし、「サービス連携」をクリックします。
    • 左のメニューバーから「API Token」をクリックしてください。
    • 「API Token」をコピーします。
  2. ルームIDを取得する。
    • ルームIDを取得したいグループチャットに移動します。

      グループチャットの歯車をクリックして、「グループチャットの設定」を選択してください。

    • グループチャットの詳細情報が表示されます。

      画面下部の「ルームID」をコピーします。

  3. プログラムで実装
    • Next.js Appを作成
      npx create-next-app my-next-app -e with-typescript
      
    • layout.tsxにnavを追加
      import React, { ReactNode } from "react";
      import Link from "next/link";
      import Head from "next/head";
      
      type Props = {
        children?: ReactNode;
        title?: string;
      };
      
      const Layout = ({ children, title = "This is the default title" }: Props) => (
        <div>
          <Head>
            <title>{title}</title>
            <meta charSet="utf-8" />
            <meta name="viewport" content="initial-scale=1.0, width=device-width" />
          </Head>
          <header>
            <nav>
              <Link href="/">Home</Link> |{" "}
              <Link href="/chatwork">Chatwork</Link>
            </nav>
          </header>
          {children}
        </div>
      );
      
      export default Layout;
      
    • フロント画面を作成(chatwork.tsx)

      pages/chatwork.tsx

      import Link from "next/link";
      import Layout from "../components/Layout";
      import styled from "styled-components";
      import React, { useState, ChangeEvent } from "react";
      
      const MessageContainer = styled.div`
        margin: 10px 10px 10px 40px;
        height: auto;
        width: auto;
      `;
      
      const Label = styled.label`
        font-size: 16px;
        font-weight: 500;
      `;
      
      const MessageBox = styled.textarea`
        width: 50%;
        margin: 15px 15px 15px 0px;
      `;
      
      const SendButton = styled.button`
        width: 150px;
        height: 30px;
        color: #ffffff;
        background-color: #52be80;
        border-radius: 5px;
        border: 1px solid green;
      `;
      
      const ErrorMessage = styled.div`
        margin: 15px 0px 0px 0px;
      `;
      
      const BackLink = styled.p`
        margin-left: 38px;
      `;
      
      function ChatworkPage() {
        const [message, setMessage] = useState("");
        const [statusMessage, setStatusMessage] = useState<string | null>();
      
        const handleMessageChange = (event: ChangeEvent<HTMLTextAreaElement>) => {
          setMessage(event.target.value);
        };
      
        const handleSendMessage = () => {
          if (message !== null) {
            sendMessageToChatwork(message);
          }
        };
      
        const sendMessageToChatwork = async (content: string) => {
          console.log(`content: ${content}`);
        };
      
        return (
          <Layout title="Chatwork | Next.js + TypeScript Example">
            <MessageContainer>
              <h3>Send Message to Chatwork Group</h3>
              <Label>Message:</Label>
              <br />
              <MessageBox
                rows={5}
                value={message}
                onChange={handleMessageChange}
              ></MessageBox>
              <br />
              <SendButton onClick={handleSendMessage}>Send Message</SendButton>
              {statusMessage && (
                <ErrorMessage className="error-top flash flash-error errmessage">
                  {statusMessage}
                </ErrorMessage>
              )}
            </MessageContainer>
            <BackLink>
              <Link href="/">Go home</Link>
            </BackLink>
          </Layout>
        );
      }
      
      export default ChatworkPage;
      

      シンプルな下記の画面が表示される。

    • Chatworkにメッセージを送信するバックエンドの処理を作成(sendtoChatwork.ts)

      pages/api/sendtoChatwork.ts

      import type { NextApiRequest, NextApiResponse } from "next";
      import axios, { AxiosResponse } from "axios";
      import qs from "qs";
      import resultInfo from "../../entity/result.json";
      type ResultInfo = typeof resultInfo;
      
      export default async function sendtoChatwork(
        req: NextApiRequest,
        res: NextApiResponse
      ) {
        //POSTデータ取得  
        const content:any = req.body.content;
      
        //set post fields
        const params = qs.stringify({
          body: content,
          self_unread: "1",
        });
      
        //API token
        const token = '********************************';
        //ルームID
        const room_id = '*********';
        //Chatwork URL
        const url = `https://api.chatwork.com/v2/rooms/${room_id}/messages`;
      
        try {
          const ret: AxiosResponse<ResultInfo> = await axios.post(
            url,
            params,
              {
                headers: {
                  Accept: "application/json",
                  "Content-Type": "application/x-www-form-urlencoded",
                  'x-chatworktoken': token,
               },
               withCredentials: true,
              }
          );
          //if message is sent successfully,chatwork returns message-id
          if(ret.data != null){
            res.status(200).json({status:200,message: "Chatworkグループにメセッジを送信しました!"});
          }else{
            res.status(299).json({status:299,message: "Chatworkグループにメセッジ送信が失敗しました!"});
          }
        } catch (error) {  
          console.log("res.status");
          if ((error as Error).message == "Request failed with status code 400") {
            res
            .status(400)
            .json({ status:400,message: "リクエストパラメーターが不足している、および不正な値が指定されています!" });
          }
          else if ((error as Error).message == "Request failed with status code 401"){
            res
            .status(401)
            .json({ status:401,message: "API認証失敗しました!" });
          }
          else if ((error as Error).message == "Request failed with status code 403"){
            res
            .status(403)
            .json({ status:403,message: "チャットにメッセージを投稿する権限がありません!" });
          }
          else if ((error as Error).message == "Request failed with status code 404"){
            res
            .status(404)
            .json({ status:404,message: "ページが見つかりません!" });
          }else if ((error as Error).message == "Request failed with status code 429"){
            res
            .status(429)
            .json({ status:429,message: "APIの利用回数制限およびチャット単位のメッセージ・タスク投稿回数制限を超過した!" });
          }else{
            res
            .status(500)
            .json({ status:500,message: "内部サーバーエラーが発生しました!" });
          }
        }
      }
      
    • レスポンスの型の為、result.jsonを追加

      /entity/result.json

      {
          "status" : 0,
          "message" :"string",
          "error":"string"
      }
      
    • フロント側のメッセージ送信機能を編集

      pages/chatwork.tsx

      /* other imports */
      import { FetchError } from "../lib/fetchError"
      
      /* other functions */
      
      const sendMessageToChatwork = async (content: string) => {
          const body = {
            content: content,
          };
          try {
            const response: Response = await fetch("/api/sendtoChatwork", {
              method: "POST",
              headers: { "Content-Type": "application/json" },
              body: JSON.stringify(body),
            });
            const result: ResultInfo = await response.json();
            setStatusMessage(result.message);
          } catch (error) {
            if (error instanceof FetchError) {
              setStatusMessage(error.data.message);
            } else {
              console.error("An unexpected error happened:", error);
            }
          }
        };
      

      lib/fetchError.ts

      export class FetchError extends Error {
          response: Response;
          data: {
            message: string;
          };
          constructor({
            message,
            response,
            data,
          }: {
            message: string;
            response: Response;
            data: {
              message: string;
            };
          }) {
            // Pass remaining arguments (including vendor specific ones) to parent constructor
            super(message);
        
            // Maintains proper stack trace for where our error was thrown (only available on V8)
            if (Error.captureStackTrace) {
              Error.captureStackTrace(this, FetchError);
            }
        
            this.name = "FetchError";
            this.response = response;
            this.data = data ?? { message: message };
          }
        }
      
    • 画面からグループチャットにメッセージを送信します。

      メッセージを入力して「Send Message」ボタンをクリックします。

    • グループチャットにメッセージを確認します。

      メッセージ正常に送信されたことが確認できます。

      画面上にも送信成功/失敗の確認ができるように「ステータスメッセージ」を出力しています。

      • 成功時
      • 失敗時

      失敗した場合、Errorの内容が表示されます。

    • メッセージにタイトルを付ける

      タイトルを付ける為、contentに「title」を追加し、メッセージは「info」内に入れて送ります。

      const sendMessageToChatwork = async (content: string) => {
          const currentDate = new Date();
          const formattedDate = currentDate.toLocaleDateString();
          content = `[info][title]日報[${formattedDate}][/title]${content}[/info]`;
          const body = {
            content: content,
          };
          try{
      	//existing code here
          }catch{
      	//existing code here
          }
      }

      普通に画面からメッセージを送信し、グループチャットを確認します。

      下記の通りにタイトル付きメッセージが表示されます。

参考ドキュメント

DevpediaCode編集部

DevpediaCodeはWeb、AI、Iot、ローコードなどプログラムに関する最新ITテーマの情報を発信するメディアです。

お問合せ下記のURLからお願いします。

https://devpediacode.com/contact