# API設計書

## 概要

本ドキュメントは、BunランタイムがJavaScriptアプリケーションに提供するHTTP関連APIの設計仕様を記述する。BunはuWebSocketsベースの高性能HTTPサーバー機能（Bun.serve）を中核として、Fetch API、WebSocket、Node.js互換のhttp/httpsモジュールを提供する。

本プロジェクトは従来のWebフレームワーク（Laravel、Express等）のようなRESTful APIエンドポイントを持つアプリケーションではなく、JavaScriptランタイムとして他のアプリケーションがHTTPサーバー/クライアント機能を構築するためのAPIを提供する。

## 共通仕様

### ベースURL

```
該当なし（ランタイムAPIのため、アプリケーション開発者が設定）
```

### 認証方式

該当なし（ランタイムAPIのため、認証はアプリケーション層で実装）

### 共通ヘッダー

BunのHTTPサーバーは標準的なHTTPヘッダーをサポートする。

| ヘッダー名 | 必須 | 説明 |
| --- | --- | --- |
| Content-Type | - | リクエスト/レスポンスのメディアタイプ |
| Content-Length | - | ボディのバイト数 |
| Transfer-Encoding | - | チャンク転送エンコーディング |
| Connection | - | 接続の維持/切断 |

### 共通エラーレスポンス

| ステータスコード | 説明 |
| --- | --- |
| 400 | Bad Request - リクエストパラメータ不正 |
| 404 | Not Found - ルート未定義 |
| 500 | Internal Server Error - サーバーエラー |
| 503 | Service Unavailable - サービス利用不可 |

## API一覧

### Bun.serve API

| カテゴリ | メソッド/プロパティ | 説明 |
| --- | --- | --- |
| Server | Bun.serve(options) | HTTPサーバーを作成・起動 |
| Server | server.stop() | サーバーを停止 |
| Server | server.fetch(request) | 内部fetchリクエストを実行 |
| Server | server.upgrade(req, options) | WebSocketにアップグレード |
| Server | server.publish(topic, message) | WebSocketメッセージをパブリッシュ |
| Server | server.reload(options) | サーバー設定をリロード |
| Server | server.timeout(request, seconds) | リクエストタイムアウトを設定 |
| Server | server.port | リッスンポート番号 |
| Server | server.hostname | ホスト名 |
| Server | server.url | サーバーURL |
| Server | server.pendingRequests | 処理中リクエスト数 |

### WebSocket API

| カテゴリ | メソッド/プロパティ | 説明 |
| --- | --- | --- |
| ServerWebSocket | ws.send(data, compress?) | メッセージ送信 |
| ServerWebSocket | ws.sendText(data, compress?) | テキストメッセージ送信 |
| ServerWebSocket | ws.sendBinary(data, compress?) | バイナリメッセージ送信 |
| ServerWebSocket | ws.publish(topic, data, compress?) | トピックにパブリッシュ |
| ServerWebSocket | ws.subscribe(topic) | トピックを購読 |
| ServerWebSocket | ws.unsubscribe(topic) | トピック購読解除 |
| ServerWebSocket | ws.close(code?, reason?) | 接続を閉じる |
| ServerWebSocket | ws.terminate() | 接続を強制終了 |
| ServerWebSocket | ws.ping(data?) | Pingフレーム送信 |
| ServerWebSocket | ws.pong(data?) | Pongフレーム送信 |
| ServerWebSocket | ws.data | ユーザーデータ |
| ServerWebSocket | ws.readyState | 接続状態 |
| ServerWebSocket | ws.remoteAddress | クライアントIPアドレス |
| ServerWebSocket | ws.binaryType | バイナリデータ型 |

### Node.js互換 HTTP API

| カテゴリ | メソッド/プロパティ | 説明 |
| --- | --- | --- |
| http | http.createServer(options, callback) | HTTPサーバー作成 |
| http | http.request(url, options, cb) | HTTPリクエスト送信 |
| http | http.get(url, options, cb) | HTTP GETリクエスト |
| https | https.createServer(options, callback) | HTTPSサーバー作成 |
| https | https.request(url, options, cb) | HTTPSリクエスト送信 |
| https | https.get(url, options, cb) | HTTPS GETリクエスト |

## 各APIエンドポイント定義

### Bun.serve

#### 1. Bun.serve(options)

HTTPサーバーを作成し、指定されたポートでリッスンを開始する。

**基本情報**

| 項目 | 内容 |
| --- | --- |
| 関数シグネチャ | `Bun.serve(options: ServeOptions): Server` |
| 戻り値 | Server インスタンス |
| 非同期 | No（即座にサーバーが起動） |

**パラメータ（ServeOptions）**

| パラメータ名 | 型 | 必須 | デフォルト | 説明 |
| --- | --- | --- | --- | --- |
| fetch | (req: Request, server: Server) => Response \| Promise<Response> | Yes | - | リクエストハンドラー関数 |
| port | number | No | 3000 | リッスンポート番号（0-65535） |
| hostname | string | No | "0.0.0.0" | バインドするホスト名/IPアドレス |
| unix | string | No | - | Unixドメインソケットパス |
| development | boolean \| object | No | true | 開発モード設定 |
| tls | TLSOptions | No | - | TLS/SSL設定 |
| websocket | WebSocketHandler | No | - | WebSocketハンドラー設定 |
| idleTimeout | number | No | 10 | アイドルタイムアウト（秒、0-255） |
| maxRequestBodySize | number | No | 128MB | 最大リクエストボディサイズ |
| reusePort | boolean | No | false | SO_REUSEPORTオプション |
| ipv6Only | boolean | No | false | IPv6のみ |
| routes | object | No | - | ルーティング定義オブジェクト |

**リクエスト例**

```javascript
const server = Bun.serve({
  port: 3000,
  fetch(req) {
    return new Response("Hello World");
  },
});

console.log(`Server running at ${server.url}`);
```

**レスポンス（成功時）**

Serverインスタンスが返される。

```javascript
{
  port: 3000,
  hostname: "0.0.0.0",
  development: true,
  pendingRequests: 0,
  url: URL { href: "http://localhost:3000/" }
}
```

**エラーケース**

| エラー | 発生条件 | メッセージ |
| --- | --- | --- |
| TypeError | fetchオプションが未指定 | "Bun.serve expects an object" |
| Error | ポートが使用中 | "EADDRINUSE" |
| Error | 権限不足 | "EACCES" |

---

#### 2. server.stop(closeActiveConnections?)

サーバーを停止し、新しい接続の受け入れを終了する。

**基本情報**

| 項目 | 内容 |
| --- | --- |
| 関数シグネチャ | `server.stop(closeActiveConnections?: boolean): void` |
| 戻り値 | void |
| 非同期 | No |

**パラメータ**

| パラメータ名 | 型 | 必須 | デフォルト | 説明 |
| --- | --- | --- | --- | --- |
| closeActiveConnections | boolean | No | false | アクティブな接続を強制終了するか |

**使用例**

```javascript
// 新規接続のみ停止（既存接続は維持）
server.stop();

// すべての接続を強制終了
server.stop(true);
```

---

#### 3. server.fetch(request)

サーバー内部でfetchリクエストを実行する。サーバー間通信やテストに使用。

**基本情報**

| 項目 | 内容 |
| --- | --- |
| 関数シグネチャ | `server.fetch(request: Request \| string): Promise<Response>` |
| 戻り値 | Promise<Response> |
| 非同期 | Yes |

**パラメータ**

| パラメータ名 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| request | Request \| string | Yes | リクエストオブジェクトまたはURL文字列 |

**使用例**

```javascript
const response = await server.fetch(new Request("/api/users"));
const data = await response.json();
```

---

#### 4. server.upgrade(request, options?)

HTTP接続をWebSocketにアップグレードする。

**基本情報**

| 項目 | 内容 |
| --- | --- |
| 関数シグネチャ | `server.upgrade(request: Request, options?: UpgradeOptions): boolean` |
| 戻り値 | boolean（成功時true） |
| 非同期 | No |

**パラメータ**

| パラメータ名 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| request | Request | Yes | アップグレード対象のリクエスト |
| options | UpgradeOptions | No | アップグレードオプション |

**UpgradeOptions**

| フィールド名 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| data | any | No | WebSocketに関連付けるユーザーデータ |
| headers | Headers \| object | No | アップグレードレスポンスのヘッダー |

**使用例**

```javascript
const server = Bun.serve({
  fetch(req, server) {
    if (server.upgrade(req, { data: { userId: 123 } })) {
      return; // アップグレード成功
    }
    return new Response("Upgrade failed", { status: 400 });
  },
  websocket: {
    open(ws) {
      console.log("WebSocket opened", ws.data);
    },
    message(ws, message) {
      ws.send(`Echo: ${message}`);
    },
  },
});
```

**エラーケース**

| エラー | 発生条件 |
| --- | --- |
| Error | websocketオプションが未設定 |
| false | アップグレード失敗（既にレスポンス送信済み等） |

---

#### 5. server.publish(topic, message, compress?)

指定トピックを購読しているすべてのWebSocketクライアントにメッセージをブロードキャストする。

**基本情報**

| 項目 | 内容 |
| --- | --- |
| 関数シグネチャ | `server.publish(topic: string, message: string \| ArrayBuffer, compress?: boolean): number` |
| 戻り値 | number（送信バイト数） |
| 非同期 | No |

**パラメータ**

| パラメータ名 | 型 | 必須 | デフォルト | 説明 |
| --- | --- | --- | --- | --- |
| topic | string | Yes | - | パブリッシュ先トピック名 |
| message | string \| ArrayBuffer | Yes | - | 送信メッセージ |
| compress | boolean | No | true | 圧縮を有効にするか |

**使用例**

```javascript
// テキストメッセージをブロードキャスト
const bytesSent = server.publish("chat", JSON.stringify({ message: "Hello" }));

// バイナリデータをブロードキャスト
server.publish("binary-channel", new Uint8Array([1, 2, 3]).buffer);
```

---

#### 6. server.reload(options)

サーバーの設定を動的にリロードする。

**基本情報**

| 項目 | 内容 |
| --- | --- |
| 関数シグネチャ | `server.reload(options: ServeOptions): void` |
| 戻り値 | void |
| 非同期 | No |

**使用例**

```javascript
// fetchハンドラーを動的に変更
server.reload({
  fetch(req) {
    return new Response("Updated handler");
  },
});
```

---

#### 7. server.timeout(request, seconds)

特定のリクエストのタイムアウトを設定する。

**基本情報**

| 項目 | 内容 |
| --- | --- |
| 関数シグネチャ | `server.timeout(request: Request, seconds: number): void` |
| 戻り値 | void |
| 非同期 | No |

**パラメータ**

| パラメータ名 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| request | Request | Yes | タイムアウトを設定するリクエスト |
| seconds | number | Yes | タイムアウト秒数（0で無効化） |

---

### ServerWebSocket

#### 8. ws.send(data, compress?)

WebSocketクライアントにメッセージを送信する。

**基本情報**

| 項目 | 内容 |
| --- | --- |
| 関数シグネチャ | `ws.send(data: string \| ArrayBuffer \| Uint8Array, compress?: boolean): number` |
| 戻り値 | number（送信バイト数、-1でバックプレッシャー） |
| 非同期 | No |

**パラメータ**

| パラメータ名 | 型 | 必須 | デフォルト | 説明 |
| --- | --- | --- | --- | --- |
| data | string \| ArrayBuffer \| Uint8Array | Yes | - | 送信データ |
| compress | boolean | No | false | 圧縮を有効にするか |

**使用例**

```javascript
websocket: {
  message(ws, message) {
    const sent = ws.send("Response message");
    if (sent === -1) {
      console.log("Backpressure detected");
    }
  }
}
```

---

#### 9. ws.subscribe(topic)

指定トピックを購読する。

**基本情報**

| 項目 | 内容 |
| --- | --- |
| 関数シグネチャ | `ws.subscribe(topic: string): void` |
| 戻り値 | void |
| 非同期 | No |

**使用例**

```javascript
websocket: {
  open(ws) {
    ws.subscribe("chat-room-1");
    ws.subscribe("notifications");
  }
}
```

---

#### 10. ws.unsubscribe(topic)

指定トピックの購読を解除する。

**基本情報**

| 項目 | 内容 |
| --- | --- |
| 関数シグネチャ | `ws.unsubscribe(topic: string): void` |
| 戻り値 | void |
| 非同期 | No |

---

#### 11. ws.close(code?, reason?)

WebSocket接続を正常に閉じる。

**基本情報**

| 項目 | 内容 |
| --- | --- |
| 関数シグネチャ | `ws.close(code?: number, reason?: string): void` |
| 戻り値 | void |
| 非同期 | No |

**パラメータ**

| パラメータ名 | 型 | 必須 | デフォルト | 説明 |
| --- | --- | --- | --- | --- |
| code | number | No | 1000 | クローズコード（1000-4999） |
| reason | string | No | "" | クローズ理由（最大123バイト） |

---

#### 12. ws.terminate()

WebSocket接続を強制終了する（クローズフレームなし）。

**基本情報**

| 項目 | 内容 |
| --- | --- |
| 関数シグネチャ | `ws.terminate(): void` |
| 戻り値 | void |
| 非同期 | No |

---

### routes オブジェクト（ルーティング定義）

#### 13. ルートベースルーティング

Bun.serveのroutesオプションでHTTPメソッドごとのハンドラーを定義できる。

**基本情報**

| 項目 | 内容 |
| --- | --- |
| オプション名 | routes |
| 型 | object |
| 必須 | No |

**ルート定義形式**

```javascript
const server = Bun.serve({
  routes: {
    // シンプルなレスポンス
    "/": new Response("Home"),

    // 関数ハンドラー（全HTTPメソッド）
    "/api/users": (req) => {
      return Response.json({ users: [] });
    },

    // HTTPメソッド別ハンドラー
    "/api/posts": {
      GET: (req) => Response.json({ posts: [] }),
      POST: async (req) => {
        const body = await req.json();
        return Response.json({ created: body }, { status: 201 });
      },
      DELETE: (req) => new Response(null, { status: 204 }),
    },

    // パスパラメータ
    "/api/users/:id": (req) => {
      const { id } = req.params;
      return Response.json({ id });
    },

    // ワイルドカード
    "/static/*": (req) => {
      return new Response("Static file");
    },
  },
});
```

**サポートされるHTTPメソッド**

| メソッド | 説明 |
| --- | --- |
| GET | リソース取得 |
| POST | リソース作成 |
| PUT | リソース更新（全体） |
| PATCH | リソース更新（部分） |
| DELETE | リソース削除 |
| HEAD | ヘッダーのみ取得 |
| OPTIONS | 対応メソッド確認 |
| CONNECT | トンネル確立 |
| TRACE | ループバックテスト |

**パスパラメータ**

| 記法 | 説明 | 例 |
| --- | --- | --- |
| :param | 名前付きパラメータ | /users/:id |
| * | ワイルドカード | /static/* |

---

### TLS設定

#### 14. TLSOptions

HTTPS接続のためのTLS設定オプション。

**基本情報**

| 項目 | 内容 |
| --- | --- |
| オプション名 | tls |
| 型 | TLSOptions |
| 必須 | No |

**TLSOptions フィールド**

| フィールド名 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| key | string \| Buffer \| BunFile | Yes | 秘密鍵（PEM形式） |
| cert | string \| Buffer \| BunFile | Yes | 証明書（PEM形式） |
| ca | string \| Buffer \| BunFile | No | CA証明書 |
| passphrase | string | No | 秘密鍵のパスフレーズ |
| serverName | string | No | SNIサーバー名 |
| requestCert | boolean | No | クライアント証明書を要求 |
| rejectUnauthorized | boolean | No | 未認証接続を拒否 |

**使用例**

```javascript
const server = Bun.serve({
  port: 443,
  tls: {
    key: Bun.file("./key.pem"),
    cert: Bun.file("./cert.pem"),
  },
  fetch(req) {
    return new Response("Secure");
  },
});
```

---

### WebSocketハンドラー

#### 15. WebSocketHandler

WebSocket接続のイベントハンドラー設定。

**基本情報**

| 項目 | 内容 |
| --- | --- |
| オプション名 | websocket |
| 型 | WebSocketHandler |
| 必須 | WebSocket使用時は必須 |

**WebSocketHandler フィールド**

| フィールド名 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| open | (ws: ServerWebSocket) => void | No | 接続確立時 |
| message | (ws: ServerWebSocket, message: string \| ArrayBuffer) => void | No | メッセージ受信時 |
| close | (ws: ServerWebSocket, code: number, reason: string) => void | No | 接続終了時 |
| error | (ws: ServerWebSocket, error: Error) => void | No | エラー発生時 |
| drain | (ws: ServerWebSocket) => void | No | バックプレッシャー解消時 |
| ping | (ws: ServerWebSocket, data: ArrayBuffer) => void | No | Ping受信時 |
| pong | (ws: ServerWebSocket, data: ArrayBuffer) => void | No | Pong受信時 |
| maxPayloadLength | number | No | 最大ペイロードサイズ |
| idleTimeout | number | No | アイドルタイムアウト（秒） |
| backpressureLimit | number | No | バックプレッシャー制限 |
| closeOnBackpressureLimit | boolean | No | 制限超過時に接続を閉じるか |
| perMessageDeflate | boolean \| object | No | 圧縮設定 |
| sendPingsAutomatically | boolean | No | 自動Ping送信 |

**使用例**

```javascript
const server = Bun.serve({
  fetch(req, server) {
    if (req.url.endsWith("/ws")) {
      if (server.upgrade(req)) return;
    }
    return new Response("Not Found", { status: 404 });
  },
  websocket: {
    open(ws) {
      console.log("Client connected");
      ws.subscribe("broadcast");
    },
    message(ws, message) {
      // エコー
      ws.send(message);
      // ブロードキャスト
      ws.publish("broadcast", message);
    },
    close(ws, code, reason) {
      console.log(`Client disconnected: ${code} ${reason}`);
    },
    error(ws, error) {
      console.error("WebSocket error:", error);
    },
    maxPayloadLength: 16 * 1024 * 1024, // 16MB
    idleTimeout: 120, // 2分
    perMessageDeflate: true,
  },
});
```

---

### Node.js互換 HTTP API

#### 16. http.createServer(options?, callback?)

Node.js互換のHTTPサーバーを作成する。

**基本情報**

| 項目 | 内容 |
| --- | --- |
| 関数シグネチャ | `http.createServer(options?: object, callback?: Function): Server` |
| 戻り値 | http.Server インスタンス |
| 非同期 | No |

**使用例**

```javascript
import http from "node:http";

const server = http.createServer((req, res) => {
  res.writeHead(200, { "Content-Type": "text/plain" });
  res.end("Hello World\n");
});

server.listen(3000, () => {
  console.log("Server running on port 3000");
});
```

---

#### 17. http.request(url, options?, callback?)

HTTPリクエストを送信する。

**基本情報**

| 項目 | 内容 |
| --- | --- |
| 関数シグネチャ | `http.request(url: string \| URL, options?: object, callback?: Function): ClientRequest` |
| 戻り値 | ClientRequest インスタンス |
| 非同期 | Yes（イベントベース） |

**オプション**

| パラメータ名 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| method | string | No | HTTPメソッド（デフォルト: GET） |
| headers | object | No | リクエストヘッダー |
| timeout | number | No | タイムアウト（ミリ秒） |
| agent | http.Agent | No | HTTPエージェント |

---

## 備考

### パフォーマンス特性

- Bunは内部でuWebSocketsを使用しており、Node.jsのhttpモジュールと比較して大幅に高速
- リクエストコンテキストはプールで再利用され、メモリ効率が高い
- 最大2,048のRequestContextを事前割り当て（約655KBのメモリ使用）

### 開発モードと本番モード

| 設定 | development: true | development: false |
| --- | --- | --- |
| エラー詳細 | 詳細なスタックトレース | 最小限のエラー情報 |
| HMR | 有効 | 無効 |
| ログ出力 | 詳細 | 最小限 |
| デフォルトreusePort | false | true |

### 環境変数

| 変数名 | 説明 |
| --- | --- |
| BUN_PORT | サーバーポート番号 |
| PORT | サーバーポート番号（フォールバック） |
| NODE_PORT | サーバーポート番号（フォールバック） |
| NODE_ENV | "production"で本番モード |
| NODE_UNIQUE_ID | クラスタモード識別子 |

### 制限事項

- ルートパラメータ名は数字で始められない
- 重複するルートパラメータ名は未サポート
- Unixソケット使用時はport/hostnameは無視される
- WebSocket使用にはwebsocketオプションの設定が必須
