API 定義
backend が公開する REST API の共通仕様。個別のエンドポイント定義は左メニューのリソース別ページを参照してください。
メソッド
REST メソッドを採用しています。
HTTP メソッド
| メソッド | 用途 |
|---|---|
| GET | 取得 |
| POST | 作成、および状態を変える操作(保存・複製・アーカイブ・出力・取り込み) |
| PATCH | 部分更新 |
| PUT | 全置換(権限の一括更新、お気に入りの設定) |
| DELETE | 削除 |
命名規則
リクエスト時の URI・パスパラメータ・JSON 内のノードには camelCase を使用します。DB のカラム名は snake_case ですが、API の表現とは切り離しています。
すべてのエンドポイントは /api 配下に置きます(ヘルスチェックの / と /openapi.json / /swagger を除く)。
リクエストとレスポンス
ヘッダー
リクエストヘッダー
Content-Type:application/jsonx-user-email: ログインユーザーのメールアドレス(必須)x-user-name: ログインユーザーの表示名(必須)x-user-image: ログインユーザーのアイコン URL(任意)x-api-key: 取り込み API のみ。API キー認証を使う場合
レスポンスヘッダー
Content-Type:application/json
レスポンスボディ
レスポンスは JSON で、必ず次の形に統一されています。
エラー時は次の形です。
| フィールド | データ型 | 備考 |
|---|---|---|
| ok | boolean | 成功なら true、失敗なら false |
| data | object | array | 成功時のみ。リソースまたはリソースの配列 |
| error | string | 失敗時のみ。エラーメッセージ |
認証要件
frontend が next-auth のセッションから取得したユーザー情報を、HTTP ヘッダで backend に渡す方式です。
| 方式 | 条件 | 対象 |
|---|---|---|
| ユーザーヘッダ | x-user-email + x-user-name が揃っている |
/api/* すべて |
| API キー | SURVEY_IMPORT_API_KEY が設定され、x-api-key が一致する |
/api/imports/* のみ |
ユーザーの自動作成
該当メールアドレスのユーザーが存在しない場合、リクエスト受信時に自動作成されます。
x-user-email/x-user-nameを読む(いずれかが欠けていれば 401)- 値に
%が含まれる場合はencodeURIComponentされているとみなしてデコードを試みる - メールアドレスを小文字に正規化する
SURVEY_ADMIN_EMAILS(カンマ区切り)に含まれていれば管理者と判定する- ユーザーが存在すれば、表示名と管理者フラグに変更があった場合のみ更新する
- 存在しなければ新規作成する
HTTP ヘッダの文字コード制限
HTTP ヘッダは ISO-8859-1 しか扱えないため、日本語の表示名は frontend 側で encodeURIComponent して送られます。
なりすましが可能
現状の認証はヘッダを信頼する方式のため、ヘッダを詐称すれば任意のユーザーとして操作できます。本番展開前の対応課題です(インフラストラクチャ)。
権限
案件への操作は view / edit 権限で制御されます。管理者は権限レコードの有無に関わらず全案件にアクセスできます。
例外処理
例外時のステータスコードは次のとおりです。
| 説明 | ステータスコード | ステータス名 |
|---|---|---|
| リクエストボディ・パラメータが不正 | 400 | Bad Request |
| ビジネスルール違反(分岐条件に使えない設問の指定など) | 400 | Bad Request |
| 認証ヘッダが欠落、または API キーが不一致 | 401 | Unauthorized |
| 削除権限がない(案件・過去質問データの削除) | 403 | Forbidden |
| 対象が存在しない、または権限がない | 404 | Not Found |
| サーバ内部エラー | 500 | Internal Server Error |
権限不足は 404 に丸める
案件の存在自体を秘匿するため、権限がない場合も原則 404 を返します。削除操作のみ、意図を明示するため 403 を返します。
エンドポイント一覧
案件
| メソッド | URI | 概要 |
|---|---|---|
| GET | /api/surveys |
案件一覧取得 |
| POST | /api/surveys |
案件新規作成と初期案生成 |
| GET | /api/surveys/{surveyId} |
案件詳細取得 |
| PATCH | /api/surveys/{surveyId} |
案件基本情報更新 |
| DELETE | /api/surveys/{surveyId} |
案件削除(論理削除) |
| GET | /api/surveys/{surveyId}/theme |
案件テーマ取得 |
| PATCH | /api/surveys/{surveyId}/theme |
案件テーマ更新 |
| POST | /api/theme-assists |
テーマ設定候補取得 |
| POST | /api/surveys/{surveyId}/save |
保存して新しい版を作成 |
| POST | /api/surveys/{surveyId}/versions |
同上(エイリアス) |
| POST | /api/surveys/{surveyId}/duplicate |
案件複製 |
| POST | /api/survey-copies |
案件または指定版から複製 |
| POST | /api/surveys/{surveyId}/questions/renumber |
設問コードの振り直し |
| POST | /api/surveys/{surveyId}/archive |
案件アーカイブ |
| POST | /api/surveys/{surveyId}/export |
JSON 出力と過去質問データへの登録 |
| POST | /api/surveys/{surveyId}/exports |
同上(エイリアス) |
| PUT | /api/surveys/{surveyId}/favorite |
お気に入り設定・解除 |
セクション
| メソッド | URI | 概要 |
|---|---|---|
| POST | /api/surveys/{surveyId}/sections |
セクション追加と初期案生成 |
| PATCH | /api/sections/{sectionId} |
セクション更新 |
| DELETE | /api/sections/{sectionId} |
セクション削除 |
| POST | /api/sections/{sectionId}/duplicate |
セクション複製 |
| POST | /api/sections/import |
セクション流用 |
| POST | /api/sections/import-from-external |
外部由来から 1 セクション一括挿入 |
設問
| メソッド | URI | 概要 |
|---|---|---|
| POST | /api/sections/{sectionId}/questions |
設問追加 |
| PATCH | /api/questions/{questionId} |
設問更新 |
| DELETE | /api/questions/{questionId} |
設問削除 |
| POST | /api/questions/{questionId}/duplicate |
設問複製 |
| POST | /api/questions/import |
設問流用 |
版
| メソッド | URI | 概要 |
|---|---|---|
| GET | /api/surveys/{surveyId}/versions |
版一覧取得 |
| POST | /api/surveys/{surveyId}/versions/{versionNo}/rollback |
指定版からロールバック |
| POST | /api/surveys/{surveyId}/versions/{versionNo}/duplicate |
指定版から複製 |
権限・ユーザー
| メソッド | URI | 概要 |
|---|---|---|
| GET | /api/surveys/{surveyId}/permissions |
権限一覧取得 |
| PUT | /api/surveys/{surveyId}/permissions |
権限一括更新 |
| GET | /api/users |
ユーザー一覧取得 |
過去質問データ
| メソッド | URI | 概要 |
|---|---|---|
| GET | /api/question-library |
過去質問データ一覧取得 |
| DELETE | /api/question-library/{itemId} |
過去質問データ削除 |
取り込み
| メソッド | URI | 概要 |
|---|---|---|
| POST | /api/imports/creative-survey/bundle |
Creative Survey bundle インポート |
| GET | /api/imports/creative-survey/existing-ids |
取込済み externalId 一覧 |
| GET | /api/imports/creative-survey/section-previews |
セクション候補プレビュー(全件) |
| GET | /api/imports/creative-survey/section-previews/{externalSurveyId} |
セクション候補プレビュー(単一) |
その他
| メソッド | URI | 概要 |
|---|---|---|
| GET | / |
ヘルスチェック |
| GET | /openapi.json |
OpenAPI ドキュメント |
| GET | /swagger |
Swagger UI |
OpenAPI ドキュメント
API 定義は @hono/zod-openapi で記述され、Zod スキーマから OpenAPI ドキュメントが生成されます。
flowchart LR
Zod[Zod スキーマ<br/>openapi-schemas.ts] --> Doc[openapi.json]
Doc --> Yaml[openapi.yaml<br/>3.1 → 3.0 正規化]
Yaml --> Orval[orval]
Orval --> Client[lib/api/generated.ts<br/>react-query クライアント]
API を変更したら次の順で反映します。
cd heineken-survey-design-backend && bun run export:openapi
cd ../heineken-survey-design-frontend && bun run generate:api
ローカル起動中は http://localhost:8787/swagger で Swagger UI を確認できます。