0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ポケカの戦績をSlackから1秒で記録!AWS LambdaとGoogle Spread Sheetsで作る戦績管理ツール

0
Last updated at Posted at 2026-01-25

概要

本記事では、子供のポケモンカード対戦記録をSlackのスラッシュコマンドからGoogle Spread Sheetsへ自動入力するシステムを構築した過程をまとめます。

単純なAPI連携の過程を記載するだけでなく、「サーバーレス特有の制約(Slack 3秒ルール)」や「セキュリティと環境変数の設計」、「暗号鍵フォーマットのトラブルシューティング」なども盛り込んでいます。

動機

日常の何かにITを使いたいと思ったのと、親子でポケカをしており、対戦記録を家族で共有、記録出来ればと思ったため。

構成

Slack → API Gateway → Lambda → Google Spread Sheets

スラックコマンドを入力すると、slackに通知が飛び、内容がスプレッドシートに記録されます

image.png

image.png

1. 受付レイヤー (Slack & API Gateway)

ユーザー: /pokeca [名前] [結果] [デッキ] と打つだけ。
インフラ: Slackからの application/x-www-form-urlencoded 形式のPOSTリクエストを、API Gatewayが受け取り、Lambdaへ橋渡し(プロキシ)します。

2. ロジックレイヤー (AWS Lambda)

使用コード

GOOGLE_SETTINGS、SPREADSHEET_ID部分はlambdaの変数設定を利用しています。

import json
import base64
import gspread
import os
from urllib.parse import parse_qs
from datetime import datetime

def lambda_handler(event, context):
    try:
        # --- 1. 環境変数から設定を読み込む ---
        # Google CloudのサービスアカウントJSON(まるごと)
        key_json_str = os.environ.get('GOOGLE_SETTINGS')
        # 対象のスプレッドシートID
        spreadsheet_id = os.environ.get('SPREADSHEET_ID')
        
        if not key_json_str or not spreadsheet_id:
            return response_to_slack("エラー:環境変数が正しく設定されていません。")
            
        service_account_info = json.loads(key_json_str)
        
        # 秘密鍵の改行コードを修正(環境変数を経由する際の必須処理)
        service_account_info['private_key'] = service_account_info['private_key'].replace('\\n', '\n')

        # --- 2. Slackからのデータ受け取り ---
        body = event.get('body', '')
        if event.get('isBase64Encoded'):
            body = base64.b64decode(body).decode('utf-8')
        
        params = parse_qs(body)
        user_text = params.get('text', [''])[0]
        words = user_text.split()
        
        if len(words) < 3:
            return response_to_slack("形式エラー!「名前 勝敗 デッキ」の順で入力してね。", ephemeral=True)

        name, result, deck = words[0], words[1], words[2]
        date_str = datetime.now().strftime('%Y/%m/%d %H:%M')

        # --- 3. Google Sheetsへの接続と書き込み ---
        gc = gspread.service_account_from_dict(service_account_info)
        sh = gc.open_by_key(spreadsheet_id)
        worksheet = sh.get_worksheet(0) # 1枚目のシートを指定

        # データの追記(日付, 対戦相手, 勝敗, デッキ)
        worksheet.append_row([date_str, name, result, deck])

        return response_to_slack(f"✅ 記録完了!\n日付: {date_str}\n対戦相手: {name}\n結果: {result}\nデッキ: {deck}")

    except Exception as e:
        # ログ出力(CloudWatch用)
        print(f"Error: {str(e)}")
        return response_to_slack(f"エラーが発生しました: {str(e)}", ephemeral=True)

def response_to_slack(message, ephemeral=False):
    """Slackへのレスポンスフォーマットを作成"""
    response_body = {
        'response_type': 'ephemeral' if ephemeral else 'in_channel',
        'text': message
    }
    return {
        'statusCode': 200,
        'headers': {'Content-Type': 'application/json'},
        'body': json.dumps(response_body, ensure_ascii=False)
    }

Runtime: Python 3.12を使用。
スプレッドシート連携するため、レイヤーにKlayers(gspread が含まれている公開レイヤー)を追加しました。

image.png

タイムアウト対応

構成を一通り作成して検証した際、Slackの3秒タイムアウト制約により operation_timeout が発生しましたが、メモリをデフォルトの128MBから512MBに変更したところ処理時間が劇的に短縮。結果として、無料枠内で安定したレスポンスを実現することが出来ました。

2025/02/04 追記
これでもたまにタイムアウトするので1024MBにしました

時刻表機ずれ対応

当初はスプレッドシートに記録される時刻がUTCでしたが、lambdaの関数設定に「TZ: Asia/Tokyo」を追加することで日本時刻で記録されるようにしました。

セキュリティへの配慮

Google Cloudの秘密鍵をコードにベタ書きせず、Lambdaの環境変数にJSONをまるごと格納して読み込む設計にしました。これにより、ソースコードの漏洩による不正アクセスのリスクを排除し、設定とロジックを分離しています。

3. データレイヤー (Google Cloud & Sheets)

1. プロジェクトの作成と API の有効化

プロジェクト作成

Google Cloud Console で新しいプロジェクトを作成。

APIの有効化

「APIとサービス」>「ライブラリ」から以下を検索し、有効化を実施しています。

  • Google Sheets API
  • Google Drive API(スプレッドシートの検索や権限確認に必要)

2. サービスアカウントの作成

プログラム専用の「身分証」を発行しています。
ロールは今回特定のシートを直接共有するため、ロール(権限)の割り当ては「なし(空)」のままで作成。

3. 秘密鍵(JSON)の発行

Lambda の環境変数GOOGLE_SETTINGSに設定した値。
作成したサービスアカウントから「新しい鍵を作成」で JSON を選択してダウンロードします。

4. スプレッドシート側の設定

書き込み先のスプレッドシートの「共有」ボタンから、サービスアカウントのメールアドレスを「編集者」として招待します。

今後の展望

この記録機能だけだいぶ味気ないので、月末などの決まったタイミングでslackに現在の勝率が通知される、溜まったデータをLambdaで集計し、勝率グラフをSlackに画像で返却する機能の追加なども出来ればと考えています。出来たらまた記事にしようと思います。

0
0
1

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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?