Zenn
🔖

HRMOS勤怠の打刻をDiscordに投稿するBotをCloudflare Workerで作ってみた

2025/03/06に公開

HRMOS勤怠の打刻をDiscordに投稿するBotをCloudflare Workerで作ってみた

はじめに

私の会社ではHRMOS勤怠という勤怠管理システムで打刻を行っています。このシステムの打刻履歴を全員の見えるところに配信したい、でも工数はかけたくない!という問題をCloudflare Workerで簡単に解決できたのでそれについて紹介します。

https://github.com/nakanoasaservice/hrmos-kintai-to-discord-bot

システム概要

開発したシステムは以下のような流れで動作します:

  1. 指定時間ごとにCloudflare Workerが起動
  2. HRMOSのAPIから最新の打刻情報を取得
  3. 取得した情報をフォーマットしてDiscordに投稿

まず、システム全体の構成図は以下のようになります:

そして、処理のフロー図は以下のとおりです:

工夫したポイント

HRMOS APIクライアントの生成

HRMOS勤怠はOpenAPI(Swagger)の定義ファイルを公開しています。この定義ファイルを利用して、TypeScriptの型定義と使いやすいAPIクライアントを自動生成しました:

// package.jsonに定義したnpmスクリプト
"typegen": "openapi-typescript 'https://ieyasu.co/docs/openapi.json' -o src/lib/api/v1.d.ts"

これにより、以下のようなメリットが得られます:

  1. 型安全性: APIのリクエスト・レスポンスの型が自動生成されるため、型エラーを防げます
  2. 自動補完: IDEで自動補完が効くため、開発効率が向上します
  3. ドキュメント参照の手間削減: API仕様を確認するためにドキュメントを参照する頻度が減ります

HRMOS APIの認証

HRMOS勤怠のAPI認証は以下のステップで行われます:

  1. Basic認証でトークン取得: API_KEYを使ってBasic認証を行い、アクセストークンを取得します
  2. トークンの保存と管理: 取得したトークンはCloudflare KVに保存し再利用します
  3. トークンの延長処理: 有効期限が近づいたトークンは延長リクエストを送信します
  4. APIリクエストへの適用: すべてのリクエストにトークンを付与します

特に苦労したのは、トークンの有効期限管理です。HRMOS勤怠のトークンは一定時間(約24時間)で期限切れになりますが、期限切れ前に延長リクエストを送ることで継続利用できます。そこで、トークンの有効期限が1時間以内に迫った場合に自動的に延長する仕組みをopenapi-fetchのミドルウェア機能として実装し、すべてのAPIリクエストに自動的にトークンを付与するようにしました:

const middleware: Middleware = {
  async onRequest({ request }) {
    if (!token || needsPostponeToken(token)) {
      token = await resolveToken(client, kv, secretKey);
    }

    request.headers.set("Authorization", `Token ${token.token}`);
  },
};

このミドルウェアの仕組みにより、個々のAPIリクエストで毎回認証処理を書く必要がなくなり、コードの重複を避けることができました。実際のAPIリクエストは以下のように非常にシンプルに書けます:

// 認証は自動的に処理されるため、認証に関するコードを書く必要がない
const stampLogs = await client.GET("/stamp_logs/daily/{day}", {
  params: {
    path: { day: "2023-12-01" },
    query: { from: new Date().toISOString() },
  },
});

認証トークンはKVに保存し、有効期限が近づいたら自動的に更新する仕組みを実装しました:

async function resolveToken(
  client: IeyasuClient,
  kv: KVNamespace,
  secretKey: SecretKey,
): Promise<TokenResponse> {
  const token = await getTokenFromCache(kv);
  if (!token) {
    // 新規トークン取得
    const newToken = await client.GET("/authentication/token", {
      headers: {
        Authorization: `Basic ${secretKey}`,
      },
    });
    // ...省略
  }

  if (needsPostponeToken(token)) {
    // トークン更新処理
    // ...省略
  }

  return token;
}

Cloudflare Workerを選んだ理由

今回のプロジェクトでCloudflare Workerを選択した主な理由は以下の通りです:

1. コストパフォーマンスの高さ

Cloudflare Workersは非常にコスト効率が良いプラットフォームです。以下の特徴があります:

  • 寛大な無料枠: 1日あたり10万リクエストまで無料で利用可能
  • KVストレージも無料枠あり: 小規模なデータ保存に十分な容量が無料で提供される
  • 従量課金制: 使った分だけ支払う仕組みで、小規模プロジェクトでは実質無料で運用可能

勤怠情報の取得は1日に数回程度で十分なため、無料枠の範囲内で十分に運用できます。

2. デプロイの簡便さ

Cloudflare Workersのデプロイフローは非常にシンプルです:

# たった1コマンドでデプロイ完了
wrangler deploy

CI/CDとの連携も容易で、GitHubリポジトリと連携すれば、pushするだけで自動的にデプロイされるようにも設定できます。インフラ管理の手間がほとんどかからないため、開発に集中できました。

まとめ

Cloudflare WorkerとHRMOS APIを活用して、シンプルながらも実用的な勤怠通知Botを作成しました。サーバーレスで運用できるため、コスト効率も良く、小規模なチームでも導入しやすいシステムになっています。

ソースコードはGitHubで公開していますので、興味のある方はぜひ参考にしてみてください。


YOSHINANI

Discussion

ログインするとコメントできます