with one click
restful-api-design
Design restful web api for the project
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Menu
Design restful web api for the project
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Based on SOC occupation classification
Use when creating pages under src/app/(site)/(authorized)/admin/. Covers list/detail/edit/create page patterns with DataTable/DataView/DataForm, repositories under src/repositories/, request schemas under src/requests/admin/, and AdminPageHeader breadcrumbs.
Use when modifying Better Auth + Prisma authentication: src/libraries/auth.ts, src/libraries/auth-client.ts, src/proxy.ts, src/services/auth_service.ts, auth-related actions.ts, or prisma/schema.prisma auth models (User/Session/Account/Verification). Covers session helpers, URL/secret env resolution, DB TLS, and PUBLIC_PATHS.
Use when creating or modifying files under src/repositories/, src/models/, or src/requests/. Covers BaseRepository inheritance (Prisma/API/Local/Airtable/Dify), Zod schema placement, and separation between repository and schema files.
Use when changing this template's mail delivery backend, reviewing email env setup, switching between `ses` and `smtp`, or adding a new provider such as Resend, SendGrid, Postmark, or Mailgun. Covers EMAIL_PROVIDER routing, EMAIL_FROM priority, dynamic import for Node-only SDKs, and test coverage for both email.test.ts and Better Auth callback smoke.
Use when adding or changing translations in messages/ja.json or messages/en.json, using getTranslations/useTranslations, or updating next-intl configuration under src/i18n/. Covers message key hierarchy, Server/Client Component APIs, dynamic and rich-text patterns, and JSON duplicate-key pitfalls.
Use when adding or modifying pages under src/app, or components under src/components (atoms/molecules/organisms) in this Next.js App Router project. Covers Server/Client Component boundary, Atomic Design placement, Server Actions in actions.ts, URL-based state management, sidebar active-state, and shadcn-only atoms rule.
| name | restful-api-design |
| description | Design restful web api for the project |
これは、本システムでJSON over HTTP API (REST APIと呼ばれることもある) を作る際に、守るべきルールを記したものである。
このようなルールを設けた理由は、ルールの統一によってメンテナンスしやすくできるから、というだけでなく、APIデザインの際に、迷ったり、哲学の違いから揉めたりすることをなくするためである。なぜなら、世の中には100%正しいAPIのデザインルールは存在せず、開発者ごとに好みのスタイルが異なっている。
したがって、ここに書かれているルールが、自分の哲学と違っている、と感じる開発者もいるはずである。しかし、OPNのプロジェクトとして設計、開発するものに関しては、ここで示されたルールに則って設計を行うように。
APIで利用する認証/認可については2種類のパターンが考えられる。一つは、AWSと同じように、他のサービスから呼び出されるタイプのAPI、もう一つはモバイルバックエンドのようにエンドユーザーが直接呼び出すAPIである。
それぞれで利用すべき認証機構が異なる。
他のサービスから呼び出されるタイプのAPIでは、API Keyを利用した認証を行う。つまり、AWSなどの認証と同じように、Access IDとAccess Secret を発行し、それによってアクセス元の認証を行う。
これは、アクセス元のサービスが、認証情報をそのサービス内に保持する必要があるため、IDとパスワードを利用してアクセストークンを取得する、といった手間のかかるプロセスを踏む理由があまりないためである。
Access IDは1ユーザーに対して一つにしても良いし、複数発行可能にしても良い。また、Access Secretは、情報漏えいの際にすぐに対策が打てるよう、ユーザーが管理画面において任意のタイミングで変更できるようにしておくべきである。
APIを利用するサービスは、API Keyをリクエストヘッダに入れて Authorization: Bearer xxx で送るようにする。認証情報はすべてのAPIアクセスの際に送る必要がある。
エンドユーザーが直接呼び出すタイプのAPIは、ユーザーID(通常メールアドレス)とパスワードで認証を行う。
この場合は、OAuth2 の Password Grant を利用する。認証のエンドポイントは以下のようにする。
| Endpoint | Description |
|---|---|
| /auth/signin | Get access token |
| /auth/token/refresh | Refresh token の取得 |
| /auth/password/forgot | Generate token for reset password |
| /auth/password/reset | Reset password |
APIを構築する際には、必ずヘルスチェック用の API エンドポイントを用意する必要がある。これは、以下のような URL となる。
/healthz
この名称は、現在のAPI設計においては一般的なもので、一般的な名詞を使うことで他のエンドポイントと名前が衝突することを避けるため、z という接尾語をつけているもので、Google などで使われていたものが一般化したと言われている。
レスポンスは Status 型を用いる。
このAPIが正常に値を返している場合は、このAPIが正常に機能していることを意味していなければならない。したがって、このAPIでは、単にアプリケーションが立ち上がっている、というだけでなく、データベース接続があればデータベースとの接続確認、外部との通信があるならネットワーク状況や疎通確認などを行ってからステータスを返す必要がある。
APIのエンドポイントのPathはすべて小文字アルファベット、あるいは数字を用いて表す。大文字アルファベットは使ってはならない。
複数の単語を繋ぐ場合はSnake Caseを用いる。つまり、単語の間にアンダースコアを入れる。ただし、できる限り複数の単語を繋げることは避けるべきである。例えば alert-user ではなく users/alert のように、「リソース名/アクション名」のように表すべきである。
なお、エンドポイントの設計において、数字は、例えばリソースの名称に数字が入っている場合や、IDの指定などには利用して構わないが、マジックナンバーのような利用方法はしてはいけない。例えば以下のようなケースは正しくない。
/notifications/{id}
/notifications_2/{id}
なぜなら、このような書き方をしてしまうと、notifications と notifications_2 の違いがなんなのか、ということがURLからは全くわからないからである。
APIのエンドポイントは、URL(Path) を見ただけで、ある程度何をするものなのかがきちんと理解できるように、可能な限りわかりやすい単語を選ぶ必要がある。
HTTPにおけるメソッドには、GET、POST、PUT.DELETE、HEAD 等様々なものがあるが、一般的なRESTの原則のとおり、どういうアクションを行うか、で利用するメソッドを決定する。
| Method | Description |
|---|---|
| GET | データを参照する場合のみに利用する。APIへのアクセスによって、ログの記録以外の何らかのデータの生成や更新があってはならない |
| POST | データを作成する場合、あるいはデータに対して何らかのアクションを行う際に利用する |
| PUT | データを更新する場合に利用する。データの部分的な更新にはPATCHを利用するという考え方もあるが、ここではすべてのデータ更新はPUTで統一する |
| DELETE | データを削除する |
一般的なリソースのCRUD操作(作成、参照、更新、削除)に関しては、一般的なRESTの原則のとおり、リソースをURLで表し、それに対する各アクションはHTTP メソッドで指定するように設計する。
その際、リソースを表す Path では必ず複数形を利用する。すなわちユーザーを表すリソースは users であり、user ではない。
ただしリソースが必ず一つしか存在しないようなケースでは、単数形を用いることもできるが、あまりそういうケースは多くないであろう。
| Method | Path | Description | Status code on success |
|---|---|---|---|
| GET | /users | ユーザー一覧の取得 | 200 |
| POST | /users | ユーザーの新規作成 | 201 |
| GET | /users/{id} | 特定のユーザーの取得 | 200 |
| PUT | /users/{id} | 特定のユーザーの情報更新 | 200 |
| DELETE | /users/{id} | 特定のユーザーの情報削除 | 200 |
正常終了時のステータスコードは、リソース作成時は 201 Created を返すが、それ以外は 200 OK を返すようにする。DELETEの場合、204 を返すという考え方もあるが、ここでは200を返し、Status 型のレスポンスを返す。
一般的なリソースのCRUD操作以外をリソースに対して行いたい場合には、パスに対して、そのアクション名を表す動詞をつけて、エンドポイントとすることができる。
/users/{id}/activate
/notifications/{id}/resend
この場合、単なる情報の参照であることは少なく、殆どの場合はデータの変更や、何らかのアクションを行うものとなるため、HTTP メソッドとしては POST を利用することになるだろう。
リクエストの際にデータを渡す方法としては、ターゲットを一意に特定するためのIDなどの情報は Path に、その他ターゲットとするデータなどの絞り込みを行うためのパラメータについてはクエリパラメータに、情報を更新するなどの目的で渡されるデータは JSON 形式でリクエストボディに含める。
ただし、例外的に画像をアップロードする場合には、multipart/form-data を利用し、画像とその他のデータ(JSON形式)を同時に送ってもよい。
APIのレスポンスは、JSON形式を基本とする。しかし、APIの性質や用途によっては、それ以外のデータ型を追加することもできる。たとえば、CSVやMessagePack、あるいはExcelファイルなどのデータ形式を返すことが考えられる。しかしその場合も、JSON形式も同時にサポートするようにし、データ形式はリクエストヘッダにおける Accept での指定に従うようにする。
| Data Type | Content-Type |
|---|---|
| JSON | application/json |
| CSV | text/csv |
| MessagePack | application/x-msgpack |
また、API実装時には、必ずAcceptの値をチェックし、データ形式の指定がなかったり、サポートしていないデータ形式が指定された場合は、エラーを返すこと。
レスポンスのデータ構造については、ステータスなどのメタデータをレスポンスに含めるような、いわゆるエンベロープを用いた構造は禁止である。
エンベロープを用いた構造とは以下のように、実際にリクエストされたデータの他に、メタ情報などを付加し、全体を共通の構造(エンベロープ)でくるんだものを指す。
{
"meta": {
"status": "success",
"code": 200,
},
"response": {
"user": {
"name": "John Doe",
"email": "john.doe@example.com"
}
}
}
APIのレスポンスにおいて、このようにメタ情報を付加することは禁止とする。したがって、上記の場合は、以下のような設計にするべきである。
{
"name": "John Doe",
"email": "john.doe@example.com"
}
エンベロープを禁止する理由は、HTTPのレスポンスにはレスポンスヘッダとして任意の情報を付加することができ、またステータスもステータスコードとして返すことができるので、HTTPレスポンス全体がエンベロープの構造をとっているからである。その中にさらにエンベロープ構造を作ることは冗長であり、避けるべきである。
また、配列をデータとして返したい場合、JSONの配列をそのまま返すことは禁止とする。
[
{
"name": "John Doe",
"email": "john.doe@example.com"
},
{
"name": "Alice Smith",
"email": "alice.smith@example.com"
}
]
これは、JSON Injectionと呼ばれる脆弱性にたいする防御のためである。JSON Injectionは、JSON配列が、JavaScriptとして評価可能なために発生する脆弱性である。
したがって、配列を返したい場合には、外側をDictionaryで包むようにする。
{
"data": [
{
"name": "John Doe",
"email": "john.doe@example.com"
},
{
"name": "Alice Smith",
"email": "alice.smith@example.com"
}
]
}
リクエスト、レスポンスのJSONのDictionaryのキーについては、access_token や card_images のようなSnake Case を利用する。
JSONの辞書のキーについては、JavaScriptがcamelCaseを利用するのが一般的であることから、camelCase を利用するというルールもあり、好みが分かれるところであるが、ここではすべて Snake Case に統一する。
ヘルスチェックの結果や、リソースの削除、および各種エラーの際には、「Status」という共通のデータ型をレスポンスとして返すようにする。
{
"success": false,
"errors": [
{
"code": "1301",
"message": "Invalid Parameter: access_token"
}
]
}
Status型は、その処理が成功したかどうかを表す真偽値である successと、エラーが発生した際にエラーがはいる errors で構成されており、エラーは code と message で構成されている。エラーのコードは、各サービスごとに決めることができるが、4桁の数値とする。エラーコードの表は、必ずドキュメントに含めること。
また、メッセージについては、出来うる限り細かくエラーの内容を書くとともに、可能であれば、どのようにすればエラーが出なくなるのかについても、書くようにする。
日時を表すデータは、Unix Timestampを利用する。これは、UnixTimestampがparseがかんたんで、タイムゾーンによる影響を受けず、ほとんどの言語の時間を扱うライブラリで標準でサポートされているからである。
文字列で日時データをやり取りしてはいけない。
ただし、日付のみの場合は文字列で 2021-02-01 のようなデータとすることもできる。
BigInt や Decimal で扱うべきデータをAPIのレスポンスとする場合は、数値ではなく、文字列とすべきである。
これは、JavaScriptが整数型を持たず、大きな数値を扱う場合に丸め誤差によって正しく処理できない可能性があるためである。
APIの返すデータとして、マジックナンバーの利用は絶対に避ける。
たとえば orders というリソースに、注文の状況を表す status という情報があったとする。その場合、このデータ型をIntにして、1だったら注文完了、2だったら配達処理完了、のような設計をすることは絶対にしてはならない。
なぜなら、その場合、それぞれの数値が何を表しているかを知らなければ、内容を理解することができないからである。
したがって、statusは文字列型として、ordered や delivered といった「意味のわかる」文字列を返すようにする。
CRUD操作において、レスポンスとして与えられるデータ型は、以下のようにする。
GET /users )下記のように、dataとcountというキーを持つDictionaryを返す。
{
"data": [
{
"id": 1,
"name": "John Doe",
"email": "john.doe@example.com",
"permissions": [
"admin",
]
},
],
"count": 1
}
dataには、リソースのリストを配列で返す。countには、リソースの総数(フィルタでの絞り込みがある場合は、絞り込み後の総数)を返す。
クエリパラメータは以下の通り。
| パラメータ | 意味 | 例 |
|---|---|---|
| limit | 取得するリソースの数 | 10 |
| offset | 取得するリソースの開始位置 | 0 |
| order | ソートするキーの名前 | name |
| direction | ソートする方向(asc/desc) | asc |
| query | 自然文での検索 | john |
| その他 | 指定したキーでの絞り込み | email=john.doe@example.com |
GET /users/{id} )下記のように、IDで指定されたリソースのデータを返す。
{
"id": 1,
"name": "John Doe",
"email": "john.doe@example.com",
"permissions": [
"admin",
]
}
POST /users )JSONでリクエストされたデータを作成し、作成されたリソースのデータを返す。返すデータはSHOWと同じ。
PUT /users/{id} )JSONでリクエストされたデータでリソースを更新し、更新されたリソースのデータを返す。返すデータはSHOWと同じ。 リクエストでは、更新したいKeyのみを送る。キーがない場合、そのキーの情報は更新されない。例えば下記の場合は、"name"のみが更新される。
{
"name": "Alice Smith"
}
### DELETE ( 例: `DELETE /users/{id}` )
リソースを削除する。レスポンスは`Status`型となる。