Cloudflare Workers入門 - エッジコンピューティング実践

中級 | 30分 で読める | 2025.01.10

公式ドキュメント

Cloudflare Workersとは

Cloudflare Workersは、Cloudflareのエッジネットワーク上でコードを実行するサーバーレスプラットフォームです。200以上のロケーションでミリ秒単位の低レイテンシを実現します。

セットアップ

実践メモ: wrangler loginでブラウザ経由の認証が完了したら、すぐにプロジェクトを作成できます。

# Wranglerのインストール
npm install -g wrangler

# ログイン
wrangler login

# プロジェクト作成
wrangler init my-worker
cd my-worker

基本的なWorker

// src/index.ts
export default {
 async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
 const url = new URL(request.url);

 if (url.pathname === '/') {
 return new Response('Hello from Cloudflare Workers!');
 }

 if (url.pathname === '/api/time') {
 return Response.json({
 timestamp: new Date().toISOString(),
 timezone: 'UTC',
 });
 }

 return new Response('Not Found', { status: 404 });
 },
};

Honoフレームワーク

// src/index.ts
import { Hono } from 'hono';
import { cors } from 'hono/cors';
import { logger } from 'hono/logger';

type Bindings = {
 KV: KVNamespace;
 DB: D1Database;
};

const app = new Hono<{ Bindings: Bindings }>();

app.use('*', logger());
app.use('/api/*', cors());

app.get('/', (c) => c.text('Hello, Hono on Workers!'));

app.get('/api/users', async (c) => {
 const { results } = await c.env.DB.prepare(
 'SELECT * FROM users LIMIT 10'
 ).all();
 return c.json(results);
});

app.post('/api/users', async (c) => {
 const { name, email } = await c.req.json();
 await c.env.DB.prepare(
 'INSERT INTO users (name, email) VALUES (?, ?)'
 ).bind(name, email).run();
 return c.json({ success: true }, 201);
});

export default app;

KV Storage

ポイント: KV Storageは結果整合性モデルです。セッションやキャッシュなど、即時整合性が不要なデータに最適です。

キーバリューストレージ。セッション、キャッシュに最適。

// wrangler.toml
// [[kv_namespaces]]
// binding = "KV"
// id = "your-kv-namespace-id"

// 使用例
app.get('/api/cache/:key', async (c) => {
 const key = c.req.param('key');
 const value = await c.env.KV.get(key);

 if (!value) {
 return c.json({ error: 'Not found' }, 404);
 }

 return c.json({ key, value: JSON.parse(value) });
});

app.put('/api/cache/:key', async (c) => {
 const key = c.req.param('key');
 const body = await c.req.json();

 await c.env.KV.put(key, JSON.stringify(body), {
 expirationTtl: 3600, // 1時間で期限切れ
 });

 return c.json({ success: true });
});

D1 Database

実践メモ: D1はSQLiteベースなのでSQLの知識がそのまま活かせます。マイグレーション機能も内蔵しています。

SQLiteベースのサーバーレスデータベース。

# データベース作成
wrangler d1 create my-database

# マイグレーション作成
wrangler d1 migrations create my-database init
-- migrations/0001_init.sql
CREATE TABLE users (
 id INTEGER PRIMARY KEY AUTOINCREMENT,
 name TEXT NOT NULL,
 email TEXT UNIQUE NOT NULL,
 created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_users_email ON users(email);
// D1操作
async function getUsers(db: D1Database) {
 const { results } = await db.prepare(`
 SELECT id, name, email, created_at
 FROM users
 ORDER BY created_at DESC
 LIMIT 50
 `).all();

 return results;
}

async function createUser(db: D1Database, name: string, email: string) {
 const result = await db.prepare(`
 INSERT INTO users (name, email) VALUES (?, ?)
 `).bind(name, email).run();

 return result.meta.last_row_id;
}

R2 Storage

R2はS3互換APIを持つため、既存のS3コードを最小限の変更で移行できます。

// wrangler.toml
// [[r2_buckets]]
// binding = "BUCKET"
// bucket_name = "my-bucket"

// ファイルアップロード
app.post('/api/upload', async (c) => {
 const formData = await c.req.formData();
 const file = formData.get('file') as File;

 if (!file) {
 return c.json({ error: 'No file provided' }, 400);
 }

 const key = `uploads/${Date.now()}-${file.name}`;
 await c.env.BUCKET.put(key, file.stream(), {
 httpMetadata: {
 contentType: file.type,
 },
 });

 return c.json({
 key,
 url: `https://your-domain.com/${key}`,
 });
});

// ファイル取得
app.get('/files/:key{.+}', async (c) => {
 const key = c.req.param('key');
 const object = await c.env.BUCKET.get(key);

 if (!object) {
 return c.notFound();
 }

 return new Response(object.body, {
 headers: {
 'Content-Type': object.httpMetadata?.contentType || 'application/octet-stream',
 'Cache-Control': 'public, max-age=31536000',
 },
 });
});

注意: R2のバケット名はwrangler.tomlで正しくバインディングする必要があります。設定ミスはランタイムエラーになります

認証ミドルウェア

import { jwt } from 'hono/jwt';

// JWT認証
app.use('/api/*', jwt({
 secret: 'your-secret-key',
}));

// または カスタム認証
const authMiddleware = async (c, next) => {
 const token = c.req.header('Authorization')?.replace('Bearer ', '');

 if (!token) {
 return c.json({ error: 'Unauthorized' }, 401);
 }

 // トークン検証
 const user = await verifyToken(token, c.env);
 c.set('user', user);

 await next();
};

app.use('/api/protected/*', authMiddleware);

注意: JWTのsecretはハードコードせず、環境変数やシークレットストアから取得してください

デプロイ

ポイント: wrangler devでローカルテストし、問題なければwrangler deployで本番反映。環境別の設定はwrangler.tomlの[env]セクションで管理します。

# 開発サーバー
wrangler dev

# 本番デプロイ
wrangler deploy

# 環境別デプロイ
wrangler deploy --env production
# wrangler.toml
name = "my-worker"
main = "src/index.ts"
compatibility_date = "2024-01-01"

[env.production]
vars = { ENVIRONMENT = "production" }

[[kv_namespaces]]
binding = "KV"
id = "xxx"

[[d1_databases]]
binding = "DB"
database_name = "my-database"
database_id = "xxx"

関連記事

まとめ

Cloudflare Workersは、低レイテンシなエッジコンピューティングを実現します。KV、D1、R2と組み合わせることで、フルスタックアプリケーションを構築できます。

参考リソース

← 一覧に戻る
PR
PR
PR
PR