概要
Go言語とGinフレームワークを活用して、RESTful APIを効率的に構築する方法を解説します。この記事では、新聞を管理するAPIを例に、コントローラー層の設計・実装を学びます。
この記事を読めば以下のことがわかります:
- Ginフレームワークの基本的な使い方
- RESTfulなエンドポイントの実装方法
- HTTPステータスコードやリクエスト/レスポンスの正しい扱い方
- ハンドラーにおけるエラー処理のポイント
コントローラーの役割とは?
コントローラーは、クライアントからのリクエストを受け取り、適切なレスポンスを返すためのロジックを記述する層です。以下の役割を果たします:
-
リクエストの検証
リクエストボディやURLパラメータの内容が正しいかをチェックします。 -
ビジネスロジックの呼び出し
モデル層やサービス層を呼び出して、データベース操作などの処理を委譲します。 -
レスポンスの整形
クライアントが期待する形式でデータを返します。
新聞管理APIのコントローラー実装
以下のコードは、新聞を管理するコントローラー層の実装例です。
全体の構造
package controllers
import (
"net/http"
"github.com/gin-gonic/gin"
"go-api-newspaper/api"
"go-api-newspaper/app/models"
"go-api-newspaper/pkg/logger"
)
// メソッドを関連付けることで、各エンドポイントの処理を実装。
type NewspaperHandler struct{}
NewspaperHandler
は新聞に関連するエンドポイントの処理を集約した構造体です。この構造体にメソッドを定義し、各APIエンドポイントと紐付けます。
各エンドポイントの実装
新聞の作成(Create)
func (a *NewspaperHandler) CreateNewspaper(c *gin.Context) {
var requestBody api.CreateNewspaperJSONRequestBody // JSONリクエストボディを受け取る構造体
if err := c.ShouldBindJSON(&requestBody); err != nil {
logger.Warn(err.Error())
c.JSON(http.StatusBadRequest, api.ErrorResponse{Message: err.Error()})
return
}
createdNewspaper, err := models.CreateNewspaper(
requestBody.Title,
requestBody.ColumnName)
if err != nil {
logger.Error(err.Error())
c.JSON(http.StatusInternalServerError, api.ErrorResponse{Message: err.Error()})
return
}
c.JSON(http.StatusCreated, createdNewspaper) // 201ステータスで作成結果を返す
}
解説:
-
c.ShouldBindJSON
を使って、リクエストボディを構造体にマッピングします。 - モデル層の
CreateNewspaper
メソッドを呼び出してデータを保存します。 - 成功時は
http.StatusCreated
(201ステータス)を返します。
新聞の取得(Read)
func (a *NewspaperHandler) GetNewspaperById(c *gin.Context, ID int) {
newspaper, err := models.GetNewspaper(ID)
if err != nil {
logger.Error(err.Error())
c.JSON(http.StatusInternalServerError, api.ErrorResponse{Message: err.Error()})
return
}
c.JSON(http.StatusOK, newspaper) // 200ステータスでデータを返す
}
解説:
-
models.GetNewspaper
を呼び出し、指定されたIDの新聞データを取得します。 - データが正常に取得できた場合は、
http.StatusOK
(200ステータス)を返します。 - エラーが発生した場合は、
http.StatusInternalServerError
を返してエラー内容をレスポンスします。
新聞の更新(Update)
func (a *NewspaperHandler) UpdateNewspaperById(c *gin.Context, ID int) {
var requestBody api.UpdateNewspaperByIdJSONRequestBody
if err := c.ShouldBindJSON(&requestBody); err != nil {
logger.Warn(err.Error())
c.JSON(http.StatusBadRequest, api.ErrorResponse{Message: err.Error()})
return
}
newspaper, err := models.GetNewspaper(ID)
if err != nil {
logger.Error(err.Error())
c.JSON(http.StatusInternalServerError, api.ErrorResponse{Message: err.Error()})
return
}
if requestBody.Title != nil {
newspaper.Title = *requestBody.Title
}
if requestBody.ColumnName != nil {
newspaper.ColumnName = *requestBody.ColumnName
}
if err := newspaper.Save(); err != nil {
logger.Error(err.Error())
c.JSON(http.StatusInternalServerError, api.ErrorResponse{Message: err.Error()})
return
}
c.JSON(http.StatusOK, newspaper) // 200ステータスで更新結果を返す
}
解説:
-
c.ShouldBindJSON
でリクエストボディをパースし、必要に応じてモデルのプロパティを更新します。 - モデルの
Save
メソッドを利用して変更を保存します。
新聞の削除(Delete)
func (a *NewspaperHandler) DeleteNewspaperById(c *gin.Context, ID int) {
newspaper := models.Newspaper{ID: ID}
if err := newspaper.Delete(); err != nil {
logger.Error(err.Error())
c.JSON(http.StatusInternalServerError, api.ErrorResponse{Message: err.Error()})
return
}
c.JSON(http.StatusNoContent, nil) // 204ステータスで成功を通知
}
解説:
- モデルの
Delete
メソッドを呼び出して対象データを削除します。 - 削除が成功した場合は、
http.StatusNoContent
(204ステータス)を返します。
まとめ
この記事では、Ginを使ったRESTful APIのコントローラー実装について学びました。以下のポイントを押さえましょう:
- Ginの
Context
を使ったリクエスト・レスポンスの管理 - HTTPステータスコードを適切に使用してクライアントに状態を通知
- モデル層と連携し、ビジネスロジックをシンプルに実装
この記事のコードを活用して、あなたのプロジェクトで効率的なAPI設計を実現してください!