bun-http-server について
bun-http-serverは、BunでHTTPサーバーを構築する開発者向けのスキルです。リクエスト処理、ルーティング、レスポンス形式、静的ファイル、CORS、サーバー設定を扱います。
主な機能
- 01Bun.serve()によるサーバー作成
- 02リクエストメソッドとボディの処理
- 03ルートと動的パラメーターの定義
- 04JSONなどのレスポンス返却
- 05静的ファイルの配信
- 06TLSとCORSの設定
活用シーン
- 01小規模なHTTP APIの構築
- 02JSONやフォーム送信の解析
- 03静的アセットの配信
- 04HTTPSまたはストリーミングレスポンスの設定
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ secondsky/ claude-skills --skill bun-http-serverインストール後、Claude Code で/bun-http-serverを入力して読み込まれたか確認します。
詳細
Bun HTTP サーバー
Bun には、Bun.serve() による高性能な HTTP サーバーが組み込まれています。
クイックスタート
const server = Bun.serve({
port: 3000,
fetch(req) {
return new Response("Hello World!");
},
});
console.log(`Server running at http://localhost:${server.port}`);
リクエストの処理
Bun.serve({
fetch(req) {
const url = new URL(req.url);
// Method
console.log(req.method); // GET, POST, etc.
// Path
console.log(url.pathname); // /api/users
// Query params
console.log(url.searchParams.get("id")); // ?id=123
// Headers
console.log(req.headers.get("Content-Type"));
return new Response("OK");
},
});
ボディの解析
Bun.serve({
async fetch(req) {
// JSON
const json = await req.json();
// Form data
const form = await req.formData();
// Text
const text = await req.text();
// ArrayBuffer
const buffer = await req.arrayBuffer();
// Blob
const blob = await req.blob();
return new Response("Received");
},
});
レスポンスの種類
Bun.serve({
fetch(req) {
const url = new URL(req.url);
switch (url.pathname) {
case "/json":
return Response.json({ message: "Hello" });
case "/html":
return new Response("<h1>Hello</h1>", {
headers: { "Content-Type": "text/html" },
});
case "/redirect":
return Response.redirect("/new-location", 302);
case "/file":
return new Response(Bun.file("./image.png"));
case "/stream":
return new Response(
new ReadableStream({
start(controller) {
controller.enqueue("chunk1");
controller.enqueue("chunk2");
controller.close();
},
})
);
default:
return new Response("Not Found", { status: 404 });
}
},
});
シンプルなルーティング
Bun.serve({
fetch(req) {
const url = new URL(req.url);
const path = url.pathname;
const method = req.method;
// Static routes
if (method === "GET" && path === "/") {
return new Response("Home");
}
if (method === "GET" && path === "/api/users") {
return Response.json([{ id: 1, name: "Alice" }]);
}
// Dynamic routes
const userMatch = path.match(/^\/api\/users\/(\d+)$/);
if (method === "GET" && userMatch) {
const userId = userMatch[1];
return Response.json({ id: userId });
}
// 404
return new Response("Not Found", { status: 404 });
},
});
エラー処理
Bun.serve({
fetch(req) {
try {
// Handle request
throw new Error("Something went wrong");
} catch (error) {
return new Response(
JSON.stringify({ error: error.message }),
{
status: 500,
headers: { "Content-Type": "application/json" }
}
);
}
},
error(error) {
// Global error handler
return new Response(`Error: ${error.message}`, { status: 500 });
},
});
サーバーオプション
const server = Bun.serve({
port: 3000, // Default: 3000
hostname: "0.0.0.0", // Default: "0.0.0.0"
development: true, // Pretty errors in browser
// TLS/HTTPS
tls: {
key: Bun.file("./key.pem"),
cert: Bun.file("./cert.pem"),
},
// Unix socket
unix: "/tmp/my-socket.sock",
// Max request body size (default 128MB)
maxRequestBodySize: 1024 * 1024 * 10, // 10MB
fetch(req) {
return new Response("OK");
},
});
サーバーメソッド
const server = Bun.serve({ ... });
// Server info
console.log(server.port); // 3000
console.log(server.hostname); // "0.0.0.0"
console.log(server.url); // URL object
// Stop server (Bun 1.2+: returns a Promise — await it to flush in-flight
// requests; calling it without await may not drain connections).
await server.stop();
// Reload with new config
server.reload({
fetch(req) {
return new Response("Updated!");
},
});
// Pending requests count
console.log(server.pendingRequests);
routes によるルーティング(Bun 1.2 以降)
上記の例では、手動で URL を解析する従来の fetch(req) ハンドラーを使用しています。この方法も引き続き動作します。Bun 1.2 以降、ルートマップを宣言する標準的な方法は routes オプションであり、動的パラメーターは req.params から利用できます。
Bun.serve({
routes: {
"/api/users": {
GET: () => Response.json([{ id: 1, name: "Alice" }]),
POST: async (req) => Response.json(await req.json(), { status: 201 }),
},
"/api/users/:id": (req) => {
const { id } = req.params;
return Response.json({ id });
},
},
fetch(req) {
return new Response("Not Found", { status: 404 });
},
});
新しいコードでは routes を使用し、一致しないパスに対するフォールバックとして fetch を残してください。
静的ファイル
Bun.serve({
fetch(req) {
const url = new URL(req.url);
// Serve static files from public/
if (url.pathname.startsWith("/static/")) {
const filePath = `./public${url.pathname.replace("/static", "")}`;
const file = Bun.file(filePath);
if (await file.exists()) {
return new Response(file);
}
return new Response("Not Found", { status: 404 });
}
return new Response("API");
},
});
CORS
function corsHeaders() {
return {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization",
};
}
Bun.serve({
fetch(req) {
// Handle preflight
if (req.method === "OPTIONS") {
return new Response(null, { headers: corsHeaders() });
}
// Add CORS headers to response
return new Response("OK", { headers: corsHeaders() });
},
});
よくあるエラー
| エラー | 原因 | 解決方法 |
|---|---|---|
EADDRINUSE | ポートが使用中 | 別のポートを使うか、プロセスを終了する |
Cannot read body | ボディがすでに消費されている | ボディを読み取るのは 1 回だけにする |
CORS error | ヘッダーがない | CORS ヘッダーを追加する |
413 Payload Too Large | ボディが上限を超えている | maxRequestBodySize を増やす |
参照資料を読み込むタイミング
次の場合は references/tls-config.md を読み込んでください。
- HTTPS/TLS のセットアップ
- 証明書の設定
- mTLS 認証
次の場合は references/streaming.md を読み込んでください。
- サーバー送信イベント
- ストリーミングレスポンス
- チャンク転送エンコーディング
コメント
Markdown 対応