Conversation
There was a problem hiding this comment.
Pull request overview
既存バックエンド API の OpenAPI 3.0 定義(openapi.yaml)を新規追加し、各エンドポイント/リクエスト/レスポンスのスキーマをドキュメント化する PR です。
Changes:
- OpenAPI 3.0.3 の定義ファイルを新規追加
- User / Charge / Purchase / Balance / Item / Health の各 API を paths と schemas で記述
- 共通の
ErrorResponse、パラメータ(UserId)を components に定義
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| /v1/user: | ||
| post: | ||
| tags: [user] | ||
| summary: ユーザー登録 | ||
| operationId: registerUser |
There was a problem hiding this comment.
POST のユーザー登録エンドポイントが /v1/user と定義されていますが、実装側は app/server/server.go:95-97 で /v1/user/(r.Post("/"))を登録しており、middleware.StripSlashes 等が無い限り /v1/user では 404 になる可能性があります。OpenAPI 側を /v1/user/ に合わせるか、サーバ側でスラッシュ正規化(StripSlashes/RedirectSlashes)を入れて /v1/user と /v1/user/ の両方を受けるようにしてください。
| /v1/item: | ||
| post: | ||
| tags: [item] | ||
| summary: 商品登録 | ||
| operationId: registerItem | ||
| requestBody: |
There was a problem hiding this comment.
/v1/item の POST/PATCH/GET(一覧) がスラッシュ無しで定義されていますが、実装は app/server/server.go:106-112 で /v1/item/(r.Post("/"), r.Patch("/"), r.Get("/"))として登録されています。スラッシュ正規化ミドルウェアが無い場合、ドキュメント通り /v1/item を叩くと一致しないため、OpenAPI のパスを /v1/item/ にするかサーバ側で /v1/item も受けるよう統一してください。
| /v1/health: | ||
| get: | ||
| tags: [health] | ||
| summary: ヘルスチェック | ||
| operationId: healthCheck |
There was a problem hiding this comment.
ヘルスチェックが /v1/health と定義されていますが、実装側は app/server/server.go:114-117 で /v1/health/(r.Get("/"))を登録しています。スラッシュ正規化が無い場合に実際の到達パスとズレるので、OpenAPI のパスを /v1/health/ に合わせるか、サーバ側で /v1/health と /v1/health/ を両対応にしてください。
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| r.Get("/{user_id}/history", balanceHandler.GetPurchaseHistories) | ||
| r.Post("/user", userHandler.RegisterUser) | ||
| r.Route("/user/{user_id}", func(r chi.Router) { | ||
| r.Patch("/", userHandler.UpdateUser) |
There was a problem hiding this comment.
r.Route("/user/{user_id}") 配下で r.Patch("/", ...) にしているため、実際のマッチは /v1/user/{user_id}/(末尾スラッシュ付き)になります。OpenAPI では /v1/user/{user_id} なので、現在のままだと /v1/user/{user_id} への PATCH が 404 になる可能性が高いです。r.Patch("", ...) にするか、middleware.StripSlashes/CleanPath 等で末尾スラッシュを吸収してください。
| r.Patch("/", userHandler.UpdateUser) | |
| r.Patch("", userHandler.UpdateUser) |
| r.Post("/user", userHandler.RegisterUser) | ||
| r.Route("/user/{user_id}", func(r chi.Router) { | ||
| r.Patch("/", userHandler.UpdateUser) | ||
| r.Post("/charge", chargeHandler.ChargeAmount) | ||
| r.Post("/charge/cancel", chargeHandler.ChargeCancel) | ||
| r.Post("/purchase", purchaseHandler.CreatePurchase) | ||
| r.Post("/purchase/cancel", purchaseHandler.CancelPurchase) | ||
| r.Get("/balance", balanceHandler.GetBalance) | ||
| r.Get("/history", balanceHandler.GetPurchaseHistories) | ||
| }) | ||
|
|
||
| // 商品関連 | ||
| r.Route("/item", func(r chi.Router) { | ||
| r.Post("/", itemHandler.ResisterItem) | ||
| r.Patch("/", itemHandler.UpdateItem) | ||
| r.Get("/{jan_code}", itemHandler.GetItemByJanCode) | ||
| r.Get("/", itemHandler.GetAllItems) | ||
| }) | ||
| r.Post("/item", itemHandler.ResisterItem) | ||
| r.Patch("/item", itemHandler.UpdateItem) | ||
| r.Get("/item", itemHandler.GetAllItems) | ||
| r.Get("/item/{jan_code}", itemHandler.GetItemByJanCode) | ||
|
|
||
| // ヘルスチェック | ||
| r.Route("/health", func(r chi.Router) { | ||
| r.Get("/", health.Check) | ||
| }) | ||
| r.Get("/health", health.Check) |
There was a problem hiding this comment.
今回のルーティング変更で /v1/user/ → /v1/user、/v1/item/ → /v1/item、/v1/health/ → /v1/health のように末尾スラッシュ有無が変わっています(chi はデフォルトだと別パス扱い)。既存クライアントが末尾スラッシュ付きで呼んでいる場合に互換性が壊れるので、middleware.StripSlashes/middleware.CleanPath の導入か、旧パスも同時に登録して両方受ける対応を検討してください。
There was a problem hiding this comment.
必要がないため、修正をしなかったです。
| content: | ||
| application/json: | ||
| schema: | ||
| $ref: "#/components/schemas/PostPurchaseCancelResponse" |
There was a problem hiding this comment.
/v1/user/{user_id}/purchase/cancel の 200 レスポンスが PostPurchaseCancelResponse(id/created_at あり)になっていますが、実装側では CancelPurchase が toPostPurchaseResponse を返しており(app/ui/api/purchase/purchase.go:95)、balance を含む別形式になります。OpenAPI を実挙動に合わせる(PostPurchaseResponse を返す)か、実装を toPostPurchaseCancelResponse に切り替えて id/created_at を返すか、どちらかに揃えてください。
| $ref: "#/components/schemas/PostPurchaseCancelResponse" | |
| $ref: "#/components/schemas/PostPurchaseResponse" |
| Status string `json:"status"` | ||
| Balance int `json:"balance"` | ||
| UserId string `json:"user_id"` | ||
| Items []struct { | ||
| ItemId int `json:"item_id"` | ||
| Quantity int `json:"quantity"` | ||
| } `json:"items"` |
There was a problem hiding this comment.
このファイル内や他のレスポンス型では UserID(例: app/ui/api/user/response.go:9)のように initialism を大文字化している一方、ここでは UserId/ItemId になっていて不統一です。エクスポート型なので Go 側の利用箇所で揺れが出やすく、UserID/ItemID へ統一(json tag はそのまま)した方が保守性が上がります。
OpenAPIを作成