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

中級 | 30分 read | 2025.01.10

Cloudflare Workersとは

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

セットアップ

# 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

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

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

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

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',
    },
  });
});

認証ミドルウェア

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);

デプロイ

# 開発サーバー
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と組み合わせることで、フルスタックアプリケーションを構築できます。

← Back to list