# 画面設計書 4-ドキュメント作成

## 概要

OpenSearchインデックスに新しいドキュメントを作成するREST APIエンドポイント（PUT/POST /{index}/_create/{id}）の設計書である。指定したIDのドキュメントが既に存在する場合は409エラーを返す。

### 本画面の処理概要

本APIは、OpenSearchインデックスに対して新規ドキュメントの作成のみを実行する機能を提供する。既存ドキュメントの上書きを防止するためのAPIである。

**業務上の目的・背景**：データの重複登録を防止し、一意なドキュメントの作成を保証する必要がある場面で使用する。op_typeが強制的に "create" に設定されるため、既存ドキュメントとIDが重複した場合は必ずエラーとなり、意図しない上書きを防止できる。イベントソーシングやログ投入など、既存データの上書きが許容されないユースケースに適している。

**画面へのアクセス方法**：HTTPクライアントからPUTまたはPOSTメソッドで `/{index}/_create/{id}` にリクエストを送信する。

**主要な操作・処理内容**：
1. クライアントからPUT/POSTリクエストとJSONドキュメントを受信する
2. op_typeを "create" に強制設定する
3. インデックス名、ドキュメントID、各種パラメータを解析する
4. ドキュメントをインデックスに新規作成する
5. 既存IDと重複する場合は409 Conflictエラーを返す

**画面遷移**：作成後のドキュメントはドキュメント取得API（GET /{index}/_doc/{id}）で取得可能。リフレッシュ後は検索API（GET /{index}/_search）で検索可能になる。

**権限による表示制御**：インデックスへの書き込み権限が必要。セキュリティプラグイン使用時はインデックス単位のアクセス制御が適用される。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 10 | ドキュメントインデックス（登録） | 主機能 | 新規ドキュメントを作成する処理（既存ID時は409エラー） |
| 36 | インジェストパイプライン | 補助機能 | ドキュメント作成前のインジェストパイプライン適用処理 |

## 画面種別

登録（更新系API）

## URL/ルーティング

| メソッド | パス | 説明 |
|---------|------|------|
| PUT | `/{index}/_create/{id}` | 指定IDで新規ドキュメントを作成する |
| POST | `/{index}/_create/{id}` | 指定IDで新規ドキュメントを作成する |

## 入出力項目

### パスパラメータ

| パラメータ名 | 型 | 必須 | 説明 |
|-------------|-----|------|------|
| index | string | はい | インデックス名 |
| id | string | はい | ドキュメントID |

### クエリパラメータ

| パラメータ名 | 型 | 必須 | デフォルト | 説明 |
|-------------|-----|------|----------|------|
| wait_for_active_shards | string | いいえ | 1 | 処理前にアクティブである必要があるシャードコピー数 |
| refresh | enum (true, false, wait_for) | いいえ | false | trueでリフレッシュ実行、wait_forでリフレッシュ待機 |
| routing | string | いいえ | - | ルーティング値 |
| timeout | time | いいえ | 1m | 操作タイムアウト |
| version | number | いいえ | - | 楽観的排他制御用バージョン番号 |
| version_type | enum (internal, external, external_gte) | いいえ | internal | バージョンタイプ |
| pipeline | string | いいえ | - | 前処理パイプラインID |

### リクエストボディ

| フィールド | 型 | 必須 | 説明 |
|-----------|-----|------|------|
| (ドキュメント本体) | object | はい | JSON形式のドキュメント |

### レスポンスボディ

| フィールド名 | 型 | 説明 |
|-------------|-----|------|
| _index | string | インデックス名 |
| _id | string | ドキュメントID |
| _version | number | ドキュメントバージョン（1） |
| result | string | 操作結果（"created"） |
| _shards | object | シャード情報 |
| _shards.total | number | 総シャード数 |
| _shards.successful | number | 成功シャード数 |
| _shards.failed | number | 失敗シャード数 |
| _seq_no | number | シーケンス番号 |
| _primary_term | number | プライマリターム |

## 表示項目

レスポンスのJSON全フィールドが表示項目となる（上記レスポンスボディの項目を参照）。

## イベント仕様

### 1-ドキュメント作成

1. PUT/POST `/{index}/_create/{id}` リクエストを受信する
2. `RestIndexAction.CreateHandler.prepareRequest()` がリクエストを処理する
3. op_typeパラメータのバリデーションを実施する（97-101行目）。null以外でcreate以外が指定されている場合はIllegalArgumentExceptionをスローする
4. op_typeを "create" に強制設定する（93行目）
5. 親クラス `RestIndexAction.prepareRequest()` に処理を委譲する
6. `IndexRequest` を構築し、`client.index()` で実行する
7. 成功時は201 Createdを返却する

## データベース更新仕様

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| ドキュメント作成 | 指定インデックス | INSERT | 新しいドキュメントをインデックスに追加する（既存IDは拒否） |

### テーブル別更新項目詳細

#### 指定インデックス

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | _source | リクエストボディのJSONドキュメント | ドキュメント本体 |
| INSERT | _id | パスパラメータのid | ドキュメント識別子 |
| INSERT | _version | 1 | 初回バージョン |
| INSERT | _seq_no | シーケンス番号 | 操作の順序管理 |
| INSERT | _primary_term | プライマリターム | プライマリシャードの世代管理 |

## メッセージ仕様

| メッセージ種別 | HTTPステータス | 条件 | メッセージ内容 |
|--------------|--------------|------|-------------|
| 成功 | 201 Created | ドキュメント作成成功時 | result: "created" |
| バージョン競合 | 409 Conflict | 既にIDが存在する場合 | VersionConflictEngineException: document already exists |
| バリデーションエラー | 400 Bad Request | op_typeにcreate以外が指定された場合 | opType must be 'create', found: [xxx] |
| インデックス未存在 | 404 Not Found | 存在しないインデックスへの登録（auto_create_index無効時） | index_not_found_exception |

## 例外処理

| 例外 | HTTPステータス | 条件 | レスポンス |
|------|--------------|------|----------|
| VersionConflictEngineException | 409 | 同一IDのドキュメントが既に存在する場合 | [index][_doc][id]: version conflict, document already exists |
| IllegalArgumentException | 400 | op_typeにcreate以外を指定した場合 | opType must be 'create' |
| MapperParsingException | 400 | フィールドがマッピングに合致しない場合 | マッピングエラーの詳細 |

## 備考

- 本APIはRestIndexAction.CreateHandlerとして実装されており、RestIndexActionの内部クラスである。
- op_typeは常に "create" に強制されるため、ドキュメント登録・更新API（/{index}/_doc/{id}）でop_type=createを指定した場合と同等の動作となる。
- if_seq_noとif_primary_termはcreate API仕様には定義されていないが、内部的にはRestIndexActionの処理を共有するため利用可能な場合がある。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | IndexRequest.java | `server/src/main/java/org/opensearch/action/index/IndexRequest.java` | リクエストのフィールドとopType設定を理解する |
| 1-2 | IndexResponse.java | `server/src/main/java/org/opensearch/action/index/IndexResponse.java` | 結果がCREATEDのみとなることを確認する（68-69行目） |

**読解のコツ**: IndexResponseの `assertCreatedOrUpdated()` メソッド（76-78行目）で、resultがCREATEDまたはUPDATEDのいずれかに制限されていることがわかる。create操作の場合、resultは必ずCREATEDとなる。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | RestIndexAction.CreateHandler | `server/src/main/java/org/opensearch/rest/action/document/RestIndexAction.java` (78-102行目) | CreateHandlerの固有処理を確認する |

**主要処理フロー**:
1. **87行目**: `routes()` で `/{index}/_create/{id}` をPOSTとPUTで登録
2. **92行目**: `validateOpType()` でop_typeパラメータのバリデーション
3. **93行目**: op_typeを "create" に強制設定
4. **94行目**: 親クラスの `prepareRequest()` に処理を委譲

#### Step 3: 親クラスの処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | RestIndexAction.prepareRequest() | `server/src/main/java/org/opensearch/rest/action/document/RestIndexAction.java` (139-165行目) | パラメータ解析と実行の共通処理 |

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

```
RestIndexAction.CreateHandler.prepareRequest()
    |
    +-- validateOpType()  [op_typeのバリデーション]
    +-- request.params().put("op_type", "create")
    +-- super.prepareRequest()  [RestIndexAction]
            |
            +-- IndexRequest 構築
            +-- indexRequest.opType("create")
            +-- client.index(indexRequest, listener)
                    |
                    +-- TransportIndexAction
                            |
                            +-- TransportBulkAction
                                    |
                                    +-- InternalEngine.index()
                                            |
                                            +-- [既存ID検出時] VersionConflictEngineException
                                            +-- [新規] Lucene IndexWriter.addDocument()
```

### データフロー図

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

PUT /{index}/_create/{id}  --> CreateHandler               --> HTTP 201
+ JSON Body                      |                              JSON Response:
                                 v                              {
                           validateOpType()                       "_index": "...",
                                 |                                "_id": "...",
                                 v                                "_version": 1,
                           op_type="create"強制                    "result": "created",
                                 |                                ...
                                 v                              }
                           RestIndexAction共通処理
                                 |                         --> HTTP 409
                                 v                              (既存ID検出時)
                           Lucene Engine
                           (重複チェック+書込)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| RestIndexAction.java | `server/src/main/java/org/opensearch/rest/action/document/RestIndexAction.java` | ソース | RESTハンドラ（CreateHandlerが内部クラス） |
| IndexRequest.java | `server/src/main/java/org/opensearch/action/index/IndexRequest.java` | ソース | リクエストオブジェクト |
| IndexResponse.java | `server/src/main/java/org/opensearch/action/index/IndexResponse.java` | ソース | レスポンスオブジェクト |
| TransportIndexAction.java | `server/src/main/java/org/opensearch/action/index/TransportIndexAction.java` | ソース | トランスポートアクション |
| create.json | `rest-api-spec/src/main/resources/rest-api-spec/api/create.json` | 設定 | REST API仕様定義 |
