# 機能設計書 72-NextRequest

## 概要

本ドキュメントは、Next.jsのNextRequestクラスの設計について記述する。NextRequestはWeb標準のRequest APIを拡張し、Middleware内でリクエスト情報にアクセスするための追加プロパティ（cookies, nextUrl等）を提供するクラスである。

### 本機能の処理概要

NextRequestクラスは、Web標準の`Request`クラスを継承し、Next.js固有の追加機能を提供する拡張リクエストオブジェクトである。Middlewareの第一引数として渡され、Cookie操作、URL解析、i18n対応などの便利メソッドを備える。

**業務上の目的・背景**：Web標準のRequest APIはCookie操作やURL解析を直接サポートしておらず、Next.jsのルーティング（basePath、i18n、trailingSlash等）に対応した高度なURL操作が必要になる。NextRequestはこれらの機能をラップし、Middleware開発者が複雑なURL操作やCookie管理を簡潔に行えるようにする。

**機能の利用シーン**：Middlewareでのリクエスト情報の読み取り、Cookieの解析、URLのパスやクエリパラメータの取得、ロケール情報の取得、リクエストボディの読み取りなど。

**主要な処理内容**：
1. Web標準Requestの全プロパティ・メソッドを継承（method, headers, body, bodyUsed等）
2. `cookies`プロパティによるRequestCookiesオブジェクトの提供
3. `nextUrl`プロパティによるNextURLオブジェクト（basePath, locale, buildId対応URL）の提供
4. `url`プロパティによる正規化済みURL文字列の提供
5. Node.js環境での`duplex: 'half'`オプションの自動設定

**関連システム・外部連携**：Middleware、NextURL（URL拡張）、RequestCookies（@edge-runtime/cookies）、Edge Runtime

**権限による制御**：NextRequestは読み取り専用のリクエスト情報アクセスを提供する。リクエストヘッダーの変更はNextResponse側で行う。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | NextRequestは画面に直接関連しない。Middlewareのリクエスト情報アクセスに使用される |

## 機能種別

データ参照 / リクエスト情報アクセス

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| input | URL \| RequestInfo | Yes | リクエストURL又はRequestオブジェクト | validateURL()によるURL検証 |
| init | RequestInit | No | リクエスト初期化オプション（headers, method, body, nextConfig等） | bodyが存在する場合、Node.js環境ではduplex: 'half'が自動設定 |

### 入力データソース

- HTTPリクエスト（adapter関数経由で渡されるリクエストデータ）
- next.config.jsの設定（basePath, i18n, trailingSlash）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| cookies | RequestCookies | リクエストCookieへのアクセスオブジェクト |
| nextUrl | NextURL | Next.js拡張URLオブジェクト（basePath, locale, buildId等を解析済み） |
| url | string | 正規化済みのリクエストURL文字列 |
| method | string | HTTPメソッド（GET, POST等）（Requestから継承） |
| headers | Headers | リクエストヘッダー（Requestから継承） |
| body | ReadableStream \| null | リクエストボディ（Requestから継承） |

### 出力先

Middlewareハンドラ関数内での参照用。NextRequestインスタンスはMiddlewareの第一引数として渡される。

## 処理フロー

### 処理シーケンス

```
1. コンストラクタ呼び出し
   └─ input引数からURL文字列を抽出
2. URL検証
   └─ validateURL()でURL文字列を検証
3. duplex設定（Node.js環境のみ）
   └─ bodyが存在しduplexが未設定の場合、'half'を設定
4. 親クラス(Request)のコンストラクタ呼び出し
   └─ inputがRequestインスタンスの場合はそのまま、それ以外はURLとinitで初期化
5. NextURLの生成
   └─ headers, nextConfig（basePath, i18n, trailingSlash）を渡してNextURLインスタンスを生成
6. INTERNALSの初期化
   └─ cookies（RequestCookies）、nextUrl、url文字列を格納
```

### フローチャート

```mermaid
flowchart TD
    A[new NextRequest] --> B[URL文字列の抽出]
    B --> C[validateURL による検証]
    C --> D{Node.js環境?}
    D -->|Yes| E{bodyあり & duplexなし?}
    E -->|Yes| F[duplex = 'half' 設定]
    E -->|No| G[super 呼び出し]
    D -->|No| G
    F --> G
    G --> H[NextURL生成]
    H --> I[INTERNALS初期化]
    I --> J[cookies: RequestCookies]
    I --> K[nextUrl: NextURL]
    I --> L[url: string]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-72-01 | URL正規化 | `__NEXT_NO_MIDDLEWARE_URL_NORMALIZE`環境変数がtrueの場合、URL正規化をスキップし元のURLをそのまま使用 | 環境変数設定時 |
| BR-72-02 | pageプロパティ非推奨 | `page`プロパティへのアクセスは`RemovedPageError`をスローする。URLPatternの使用を推奨 | pageアクセス時 |
| BR-72-03 | uaプロパティ非推奨 | `ua`プロパティへのアクセスは`RemovedUAError`をスローする。userAgent関数の使用を推奨 | uaアクセス時 |
| BR-72-04 | duplex自動設定 | Node.js環境でbodyが存在する場合、RequestInitにduplex: 'half'を自動設定（エラー防止） | Node.js環境 & body存在時 |

### 計算ロジック

特になし。

## データベース操作仕様

### 操作別データベース影響一覧

NextRequestクラスはデータベース操作を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| Error | URL不正エラー | 不正なURL文字列がinputに渡された場合 | 絶対URLを使用する |
| RemovedPageError | 非推奨API | pageプロパティにアクセスした場合 | URLPatternを使用する |
| RemovedUAError | 非推奨API | uaプロパティにアクセスした場合 | userAgent関数を使用する |

### リトライ仕様

該当なし。

## トランザクション仕様

該当なし。

## パフォーマンス要件

- NextURLの生成はコンストラクタ内で同期的に実行される
- RequestCookiesはヘッダーからの遅延パースを行う

## セキュリティ考慮事項

- INTERNALSプロパティはSymbolを使用して外部からの直接アクセスを防止
- Cookieデータはリクエストヘッダーから取得され、改竄されたCookie値のバリデーションはアプリケーション側の責務

## 備考

- NextRequestHintクラス（adapter.ts内）はNextRequestを継承し、開発時のエラーメッセージ改善のためにsourcePageプロパティを追加する
- RequestInitインターフェースはglobalThis.RequestInitを拡張し、nextConfig, signal, duplexプロパティを追加する

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | request.ts | `packages/next/src/server/web/spec-extension/request.ts` | INTERNALS Symbolの構造（cookies, url, nextUrl）、RequestInitの拡張内容を確認 |
| 1-2 | cookies.ts | `packages/next/src/server/web/spec-extension/cookies.ts` | RequestCookiesの再エクスポート元（@edge-runtime/cookies）を確認 |

**読解のコツ**: `[INTERNALS]`はComputed Property Nameで、Symbolをキーとしたプロパティ。`this[INTERNALS].cookies`のようにブラケット記法でアクセスする。外部モジュールからはSymbol参照がないとアクセスできないため、事実上のprivateプロパティとして機能する。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | request.ts | `packages/next/src/server/web/spec-extension/request.ts` | コンストラクタ（22-52行目）の処理フロー：URL抽出 -> validateURL -> duplex設定 -> super呼び出し -> NextURL生成 -> INTERNALS初期化 |

**主要処理フロー**:
1. **22-26行目**: input引数からURL文字列を抽出。Requestインスタンスの場合はurl、それ以外はString()で変換
2. **26行目**: validateURL()でURL文字列を検証
3. **32-36行目**: Node.js環境（NEXT_RUNTIME !== 'edge'）でbody存在時にduplex: 'half'を設定
4. **38-39行目**: 親クラスRequestのコンストラクタ呼び出し
5. **41-51行目**: NextURL生成とINTERNALS初期化

#### Step 3: プロパティアクセスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | request.ts | `packages/next/src/server/web/spec-extension/request.ts` | getterプロパティ（cookies: 76-78, nextUrl: 80-82, url: 102-104）と非推奨プロパティ（page: 89-91, ua: 98-100）の実装を確認 |

#### Step 4: 利用箇所を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | adapter.ts | `packages/next/src/server/web/adapter.ts` | NextRequestHintクラス（40-64行目）がNextRequestを継承。178-189行目でインスタンス化される箇所を確認 |

### プログラム呼び出し階層図

```
NextRequest (constructor)
    |
    +-- validateURL() [utils.ts]
    |
    +-- super(Request) [Web API]
    |
    +-- new NextURL() [next-url.ts]
    |       +-- parseURL() [next-url.ts:25]
    |       +-- analyze() [next-url.ts:76]
    |           +-- getNextPathnameInfo() [router/utils]
    |           +-- detectDomainLocale() [i18n]
    |
    +-- new RequestCookies() [@edge-runtime/cookies]
```

### データフロー図

```
[入力]                    [処理]                      [出力]

URL / Request -------> NextRequest                NextRequestインスタンス
   input              constructor                    |
                          |                          +-- .cookies -> RequestCookies
RequestInit -------->     |                          +-- .nextUrl -> NextURL
   (headers,              +-> validateURL()          +-- .url     -> string
    method,               +-> super(Request)         +-- .method  -> string (継承)
    body,                 +-> NextURL生成            +-- .headers -> Headers (継承)
    nextConfig)           +-> RequestCookies生成     +-- .body    -> ReadableStream (継承)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| request.ts | `packages/next/src/server/web/spec-extension/request.ts` | ソース | NextRequestクラス本体 |
| cookies.ts | `packages/next/src/server/web/spec-extension/cookies.ts` | ソース | RequestCookies/ResponseCookiesの再エクスポート |
| next-url.ts | `packages/next/src/server/web/next-url.ts` | ソース | NextURLクラス |
| utils.ts | `packages/next/src/server/web/utils.ts` | ソース | validateURL、toNodeOutgoingHttpHeaders等 |
| error.ts | `packages/next/src/server/web/error.ts` | ソース | RemovedPageError, RemovedUAError |
| adapter.ts | `packages/next/src/server/web/adapter.ts` | ソース | NextRequestHintクラス（NextRequest継承） |
