Contents
1. Trello API の全体像と公式ドキュメント
| 項目 | 内容 |
|---|---|
| ベース URL | https://api.trello.com/1 |
| 認証方式 | ・API キー + トークン(シンプル) ・OAuth 2.0 認可コードフロー(推奨) |
| 主要リソース | Boards、Lists、Cards、Members、Actions など |
| 公式ドキュメント | https://developer.atlassian.com/cloud/trello/rest/ |
ポイント
まずは「エンドポイント構造」と「認証方式」を把握し、公式リファレンスでパラメータやレスポンス例を確認しましょう。
2. 認証・認可
2‑1. API キー & トークン取得手順(個人利用向け)
- 開発者ページ (https://trello.com/app-key) にアクセスし、
API Keyをコピー。 - 同ページの「Token を生成」ボタンをクリックし、必要な権限(read, write 等)を選択 →
Tokenが表示されるのでコピー。 - 取得した Key と Token はローカル環境では
.envファイル、CI 環境ではシークレット変数に保存する。
|
1 2 3 4 |
# .env の例 TRELLO_KEY=xxxxxxxxxxxxxxxxxxxxxx TRELLO_TOKEN=yyyyyyyyyyyyyyyyyyyyyy |
2‑2. OAuth 2.0 認可コードフロー(チーム利用・高度な権限管理向け)
フローチャート
|
1 2 3 4 5 6 7 8 9 10 |
+-----------+ +-----------------+ +--------------------+ | ユーザー | ----> | Trello 認可サーバー | <---> | アプリケーション (バックエンド) | +-----------+ +-----------------+ +--------------------+ ^ | ① 認可リクエスト | | v | ブラウザ (ユーザー同意画面) | | ^ | | | ② 認可コード (code) | +---------------------+-------------------------------+ |
実装ステップ(Node.js/Express)
※ 前提
client_idとclient_secretは Trello の開発者コンソールで取得。
リダイレクト URI は Trello コンソールに登録済みのものを使用。
- 認可リクエスト URL を生成し、ユーザーへ誘導
js
// routes/auth.js
import express from 'express';
const router = express.Router();
const CLIENT_ID = process.env.TRELLO_CLIENT_ID;
const REDIRECT_URI = encodeURIComponent(process.env.TRELLO_REDIRECT_URI);
const SCOPES = encodeURIComponent('read,write');
router.get('/login', (req, res) => {
const authUrl = https://trello.com/1/OAuthAuthorizeToken?response_type=code&client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&scope=${SCOPES};
res.redirect(authUrl);
});
export default router;
- コールバックエンドで認可コードをアクセストークンに交換
js
// routes/callback.js
import express from 'express';
import axios from 'axios';
const router = express.Router();
const CLIENT_ID = process.env.TRELLO_CLIENT_ID;
const CLIENT_SECRET = process.env.TRELLO_CLIENT_SECRET;
const REDIRECT_URI = process.env.TRELLO_REDIRECT_URI;
router.get('/oauth-callback', async (req, res) => {
const { code } = req.query;
if (!code) return res.status(400).send('Missing authorization code');
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
try { const tokenRes = await axios.post( 'https://trello.com/1/OAuthToken', new URLSearchParams({ grant_type: 'authorization_code', client_id: CLIENT_ID, client_secret: CLIENT_SECRET, redirect_uri: REDIRECT_URI, code, }).toString(), { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } } ); const { access_token, expires_in, refresh_token } = tokenRes.data; // 例: データベースに保存、または JWT に埋め込んでクライアントへ返す res.json({ access_token, expires_in, refresh_token }); } catch (err) { console.error('Token exchange error:', err.response?.data || err.message); res.status(500).send('Failed to obtain access token'); } |
});
export default router;
- 取得したアクセストークンを API 呼び出しに付与
js
// utils/trelloClient.js
import axios from 'axios';
const BASE_URL = 'https://api.trello.com/1';
export function trelloRequest(method, path, token, params = {}, data = null) {
return axios({
method,
url: ${BASE_URL}${path},
headers: { Authorization: Bearer ${token} },
params: { ...params },
data,
});
}
参考リンク(公式情報)
- レートリミット – Trello API の「Rate Limiting」セクション
https://developer.atlassian.com/cloud/trello/guides/rest-api/rate-limiting/ (2024年12月時点で 100 リクエスト / 10 秒 が上限と明記)
3. エラーハンドリング & 再試行ロジック(指数バックオフ実装例)
3‑1. なぜ指数バックオフが必要か
| 状況 | 推奨対策 |
|---|---|
| 429 Too Many Requests | Retry-After ヘッダーを確認し、最小待機時間以上の遅延を入れる。 |
| 5xx 系サーバエラー | ネットワーク障害や一時的なサービス不安定を想定し、指数バックオフでリトライする。 |
| タイムアウト (≥ 5 s) | 同上。 |
3‑2. Node.js(axios)での実装例
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
// utils/retryAxios.js import axios from 'axios'; function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } /** * @param {Object} config axios リクエスト設定 * @param {number} maxAttempts 最大リトライ回数(デフォルト 5) */ export async function requestWithRetry(config, maxAttempts = 5) { let attempt = 0; let delay = 1000; // 初回待機 1 秒 while (true) { try { return await axios(config); } catch (err) { const status = err.response?.status; // 429: Rate limit if (status === 429) { const retryAfter = parseInt(err.response.headers['retry-after'] || '1', 10) * 1000; console.warn(`Rate limited. Waiting ${retryAfter} ms before retry...`); await sleep(retryAfter); } // 5xx 系エラー、ネットワーク障害 else if (status >= 500 || err.code === 'ECONNABORTED') { attempt++; if (attempt > maxAttempts) throw err; console.warn(`Transient error (${status}). Retry #${attempt} after ${delay} ms`); await sleep(delay); delay = Math.min(delay * 2, 30000); // 最大 30 秒までバックオフ } else { // その他は即時スロー throw err; } } } } |
使用例(自動アーカイブ)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
import { requestWithRetry } from './utils/retryAxios.js'; import dotenv from 'dotenv'; dotenv.config(); const key = process.env.TRELLO_KEY; const token = process.env.TRELLO_TOKEN; async function archiveStaleCards(boardId) { const query = `board:${boardId} is:open lastActivity:5d`; const url = `https://api.trello.com/1/search`; const { data } = await requestWithRetry({ method: 'get', url, params: { key, token, query, modelTypes: 'cards', cards_limit: 1000 }, timeout: 8000, }); for (const card of data.cards) { await requestWithRetry({ method: 'put', url: `https://api.trello.com/1/cards/${card.id}/closed`, params: { key, token, value: true }, timeout: 5000, }); console.log(`Archived ${card.name}`); } } // 実行例 archiveStaleCards('YOUR_BOARD_ID').catch(console.error); |
4. シークレット管理と CI/CD 環境別設定例
4‑1. 基本方針
| 項目 | 推奨方法 |
|---|---|
| ローカル開発 | .env → dotenv パッケージでロード |
| ステージング/本番 | CI/CD のシークレット機能に格納し、環境変数として注入 |
| 最小権限 | 必要なスコープだけ付与(例: read,write) |
| ローテーション | 6か月ごとに新トークンを発行し、旧トークンは即削除 |
4‑2. GitHub Actions(既存)
|
1 2 3 4 5 |
# .github/workflows/archive.yml (抜粋) env: TRELLO_KEY: ${{ secrets.TRELLO_KEY }} TRELLO_TOKEN: ${{ secrets.TRELLO_TOKEN }} |
4‑3. GitLab CI/CD
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# .gitlab-ci.yml stages: - archive archive_stale_cards: stage: archive image: node:20-alpine script: - npm ci - node scripts/auto-archive.js variables: TRELLO_KEY: $TRELLO_KEY # GitLab の Settings > CI/CD > Variables に登録 TRELLO_TOKEN: $TRELLO_TOKEN |
4‑4. Azure Pipelines
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# azure-pipelines.yml trigger: none schedules: - cron: "0 3 * * *" # UTC 03:00 毎日実行 displayName: Daily archive branches: include: - main jobs: - job: Archive pool: vmImage: 'ubuntu-latest' steps: - task: NodeTool@0 inputs: versionSpec: '20.x' - script: | npm ci node scripts/auto-archive.js env: TRELLO_KEY: $(TRELLO_KEY) # Azure Pipelines の Library > Variable group に設定 TRELLO_TOKEN: $(TRELLO_TOKEN) |
4‑5. Bitbucket Pipelines
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# bitbucket-pipelines.yml pipelines: schedules: - cron: "0 3 * * *" name: Daily Archive script: - npm ci - node scripts/auto-archive.js services: - docker variables: TRELLO_KEY: $TRELLO_KEY # Repository Settings > Pipelines > Repository Variables TRELLO_TOKEN: $TRELLO_TOKEN |
5. 言語別サンプルコード(認証・エラーハンドリング含む)
5‑1. Node.js (axios + exponential backoff)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
// src/trelloClient.js import axios from 'axios'; import { requestWithRetry } from '../utils/retryAxios.js'; import dotenv from 'dotenv'; dotenv.config(); const BASE = 'https://api.trello.com/1'; const KEY = process.env.TRELLO_KEY; const TOKEN = process.env.TRELLO_TOKEN; /** * GET /members/me/boards */ export async function listMyBoards() { const res = await requestWithRetry({ method: 'get', url: `${BASE}/members/me/boards`, params: { key: KEY, token: TOKEN }, timeout: 8000, }); return res.data; } |
5‑2. Python (requests + backoff library)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# trello_client.py import os, time, requests from dotenv import load_dotenv load_dotenv() KEY = os.getenv('TRELLO_KEY') TOKEN = os.getenv('TRELLO_TOKEN') BASE_URL = 'https://api.trello.com/1' def _request(method: str, path: str, **kwargs): url = f'{BASE_URL}{path}' params = kwargs.pop('params', {}) params.update({'key': KEY, 'token': TOKEN}) for attempt in range(5): try: resp = requests.request(method, url, params=params, timeout=8, **kwargs) if resp.status_code == 429: retry_after = int(resp.headers.get('Retry-After', '1')) time.sleep(retry_after) continue resp.raise_for_status() return resp.json() except (requests.HTTPError, requests.ConnectionError) as e: if attempt == 4: raise backoff = min(2 ** attempt, 30) print(f'Transient error ({e}). retry in {backoff}s') time.sleep(backoff) def list_my_boards(): return _request('GET', '/members/me/boards') |
5‑3. PowerShell (Invoke-RestMethod + exponential backoff)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# TrelloClient.ps1 $Key = $env:TRELLO_KEY $Token = $env:TRELLO_TOKEN $Base = "https://api.trello.com/1" function Invoke-TrelloRequest { param( [ValidateSet('GET','POST','PUT','DELETE')]$Method, [string]$Path, [hashtable]$Query = @{} ) $uri = "$Base$Path" $query += @{ key=$Key; token=$Token } $attempt = 0 while ($true) { try { return Invoke-RestMethod -Uri $uri -Method $Method -Body $null -Headers @{} -ContentType 'application/json' -TimeoutSec 8 -ErrorAction Stop -SkipHttpErrorCheck -MaximumRetryCount 0 -Query $query } catch { $status = $_.Exception.Response.StatusCode.Value__ if ($status -eq 429) { $retryAfter = [int]($_.Exception.Response.Headers["Retry-After"] ?? 1) Start-Sleep -Seconds $retryAfter continue } if ($attempt -ge 4) { throw $_ } $delay = [math]::Min([math]::Pow(2, $attempt), 30) Write-Warning "Transient error $status. Retry #$($attempt+1) after $delay sec" Start-Sleep -Seconds $delay $attempt++ } } } # 使用例: 自分のボード一覧取得 Invoke-TrelloRequest -Method GET -Path "/members/me/boards" |
6. 実務で役立つスクリプト集
6‑1. 【自動アーカイブ】5 日以上更新がないカードを一括クローズ
ポイント
lastActivity:5dクエリは「最終更新から 5 日以上経過」したカードだけを取得。
取得件数上限は 1000 件/リクエスト。必要に応じてページング(page=2)で続行。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
// scripts/auto-archive.js import { requestWithRetry } from '../utils/retryAxios.js'; import dotenv from 'dotenv'; dotenv.config(); const KEY = process.env.TRELLO_KEY; const TOKEN = process.env.TRELLO_TOKEN; async function archive(boardId) { const query = `board:${boardId} is:open lastActivity:5d`; const url = `https://api.trello.com/1/search`; const { data } = await requestWithRetry({ method: 'get', url, params: { key: KEY, token: TOKEN, query, modelTypes: 'cards', cards_limit: 1000 }, timeout: 8000, }); for (const card of data.cards) { await requestWithRetry({ method: 'put', url: `https://api.trello.com/1/cards/${card.id}/closed`, params: { key: KEY, token: TOKEN, value: true }, timeout: 5000, }); console.log(`📦 Archived "${card.name}"`); } } // 実行(環境変数か CLI 引数でボード ID を渡すのがベスト) archive(process.argv[2] ?? 'YOUR_BOARD_ID').catch(console.error); |
定期実行例(GitHub Actions)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# .github/workflows/auto-archive.yml name: Auto Archive Stale Cards on: schedule: - cron: '0 3 * * *' # 毎日 UTC 03:00 jobs: archive: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Setup Node uses: actions/setup-node@v3 with: node-version: '20' - run: npm ci - env: TRELLO_KEY: ${{ secrets.TRELLO_KEY }} TRELLO_TOKEN: ${{ secrets.TRELLO_TOKEN }} run: node scripts/auto-archive.js YOUR_BOARD_ID |
6‑2. 【Webhook 連携】外部サービスからカード作成・ステータス別自動移動(Flask)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# app.py import os, requests from flask import Flask, request, abort from dotenv import load_dotenv load_dotenv() app = Flask(__name__) KEY = os.getenv('TRELLO_KEY') TOKEN = os.getenv('TRELLO_TOKEN') BOARD_ID = os.getenv('TRELLO_BOARD_ID') LIST_TODO = os.getenv('TRELLO_LIST_TODO') # カード作成先 LIST_DONE = os.getenv('TRELLO_LIST_DONE') # 完了時に移動 def _post(url, params): r = requests.post(url, params=params, timeout=5) r.raise_for_status() return r.json() def create_card(name, desc=''): url = f'https://api.trello.com/1/cards' return _post(url, { 'key': KEY, 'token': TOKEN, 'idList': LIST_TODO, 'name': name, 'desc': desc })['id'] def move_card(card_id): url = f'https://api.trello.com/1/cards/{card_id}' _post(url, { 'key': KEY, 'token': TOKEN, 'idList': LIST_DONE }) @app.route('/trello-webhook', methods=['POST']) def webhook(): if not request.is_json: abort(400) payload = request.get_json() title = payload.get('title') description = payload.get('description', '') status = payload.get('status') if not title: abort(400, 'Missing title') card_id = create_card(title, description) if status == 'done': move_card(card_id) return '', 204 if __name__ == '__main__': app.run(host='0.0.0.0', port=5000) |
デプロイ例(Docker + GitLab CI)
|
1 2 3 4 5 6 7 8 |
# Dockerfile FROM python:3.12-slim WORKDIR /app COPY requirements.txt . RUN pip install -r requirements.txt COPY . . CMD ["gunicorn", "-b", "0.0.0.0:5000", "app:app"] |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# .gitlab-ci.yml stages: - build - deploy build_image: stage: build image: docker:latest services: - docker:dind script: - docker build -t registry.example.com/trello-webhook:$CI_COMMIT_SHORT_SHA . - docker push registry.example.com/trello-webhook:$CI_COMMIT_SHORT_SHA deploy_prod: stage: deploy image: alpine/kubectl:latest script: - kubectl set image deployment/trello-webhook trello-webhook=registry.example.com/trello-webhook:$CI_COMMIT_SHORT_SHA --record only: - main |
7. 運用ベストプラクティスまとめ
| 項目 | 推奨アクション |
|---|---|
| 認証方式 | チーム利用は必ず OAuth 2.0、個人ツールはキー+トークンで可。 |
| レートリミット | 公式: 100 リクエスト / 10 秒(https://developer.atlassian.com/cloud/trello/guides/rest-api/rate-limiting/) 429 を受けたら Retry-After 待機+指数バックオフ。 |
| エラーハンドリング | ネットワーク障害・5xx は最大 5 回リトライ、バックオフ上限 30 秒。 |
| シークレット管理 | 環境変数 + CI の Secrets 機能(GitHub, GitLab, Azure Pipelines, Bitbucket)で保管し、最低権限だけ付与。 |
| トークンローテーション | 6 か月ごとに新しいアクセストークンを発行し、古いものは即削除。自動化スクリプトで定期的にチェックすると便利。 |
| テスト・モニタリング | curl -I や Postman でエンドポイントの健康状態を確認し、失敗時は Slack / Teams にアラート送信。 |
| デプロイ戦略 | Docker コンテナ化 → CI/CD パイプラインでビルド・デプロイ。環境ごとにシークレットストア(AWS Secrets Manager, Azure Key Vault 等)を利用すると更に安全。 |
8. 参考リンク集
| カテゴリ | URL |
|---|---|
| 公式 API リファレンス | https://developer.atlassian.com/cloud/trello/rest/ |
| レートリミット解説 | https://developer.atlassian.com/cloud/trello/guides/rest-api/rate-limiting/ |
| OAuth 2.0 ガイド | https://developer.atlassian.com/cloud/trello/guides/rest-api/oauth-2/ |
| 環境変数管理(dotenv) | https://github.com/motdotla/dotenv |
| 指数バックオフ実装例(Node.js) | https://github.com/axios/axios#handling-errors |
| CI/CD シークレットベストプラクティス | https://learn.microsoft.com/en-us/azure/devops/pipelines/process/library?view=azure-devops |
9. 最後に
- まずは手元でキーとトークンを取得し、サンプルコード(Node.js / Python)を走らせてみましょう。
- チーム開発や本番運用を考えるなら、OAuth と CI/CD のシークレット管理へ段階的に移行するのが安全です。
- 本稿で示した「レートリミット対策」「指数バックオフ」「CI/CD 各種」などの実装は、予期せぬエラーやスパイク時でも安定稼働させるための必須要素です。
これらを踏まえて 自分だけの Trello 自動化 を構築し、業務効率化に活かしてください。 🎯