Go の Gin と GORM で API を作る(2)
前回は repository を修正したので、今回はそれを利用して handler を修正していきたいと思います。handler/api/article.go
というファイルを新規に作成し、下記のように記述しました。
package handler_api import ( "bbs/repository" "errors" "github.com/gin-gonic/gin" "net/http" "strconv" ) // 1ページあたりいくつの記事を表示するか const perPage = 20 // ArticleRequest 記事投稿リクエストを受ける struct // バリデーションルールを binding に記述する // 最大文字数のバリデーション max を追加 type ArticleRequest struct { Name string `json:"name" binding:"max=255"` Body string `json:"body" binding:"required,max=10000"` } // GetArticles 掲示板の記事を取得する func GetArticles(c *gin.Context) { // クエリパラメータ取得 paramLimit := c.Query("limit") paramOffset := c.Query("offset") limit, _ := strconv.Atoi(paramLimit) offset, _ := strconv.Atoi(paramOffset) if limit == 0 { limit = perPage } articles, _, err := repository.GetArticles(limit, offset) if err != nil { // このエラーハンドリングは次回以降に説明 c.Error(err).SetType(gin.ErrorTypePublic) return } // レスポンスは json で返したいので下記のメソッドを利用する // レスポンスは repository.Article struct のスライス c.JSON(http.StatusOK, articles) } // CreateArticle 掲示板の記事を作成する func CreateArticle(c *gin.Context) { // バリデーション&バインド var req ArticleRequest if err := c.ShouldBindJSON(&req); err != nil { c.Error(err).SetType(gin.ErrorTypePublic) return } // DBに保存 article, _, err := repository.CreateArticle(req.Name, req.Body) if err != nil { c.Error(err).SetType(gin.ErrorTypePublic) return } // レスポンスは repository.Article struct c.JSON(http.StatusCreated, article) } // UpdateArticle 掲示板の記事を更新する func UpdateArticle(c *gin.Context) { // PathInfo のパラメータを取得 // ルーティングは下記のように設定する想定 // r.PUT("/article/:articleId", handler_api.UpdateArticle) paramArticleId := c.Param("articleId") articleId, _ := strconv.Atoi(paramArticleId) if articleId == 0 { err := errors.New("invalid ArticleId") c.Error(err).SetType(gin.ErrorTypePublic) return } // バリデーション&バインド var req ArticleRequest if err := c.ShouldBindJSON(&req); err != nil { c.Error(err).SetType(gin.ErrorTypePublic) return } // DBに保存 article, _, err := repository.UpdateArticle(articleId, req.Name, req.Body) if err != nil { c.Error(err).SetType(gin.ErrorTypePublic) return } c.JSON(http.StatusOK, article) } // DeleteArticle 掲示板の記事を更新する func DeleteArticle(c *gin.Context) { // PathInfo のパラメータを取得 paramArticleId := c.Param("articleId") articleId, _ := strconv.Atoi(paramArticleId) if articleId == 0 { err := errors.New("invalid ArticleId") c.Error(err).SetType(gin.ErrorTypePublic) return } // DBから削除 _, err := repository.DeleteArticle(articleId) if err != nil { c.Error(err).SetType(gin.ErrorTypePublic) return } c.JSON(http.StatusOK, nil) }
説明が必要そうな箇所には、ソース内にコメントを付けました。これで、正常系は問題無く動作することが確認できています。が、異常系で動かしてみると、いろいろと問題がありそうです。具体的には下記のような問題があります。
- クエリパラメータやPathInfoのパラメータが不正なパラメータのとき、期待通りの挙動にならない
- 更新・削除をするとき、対象となるレコードが存在しなくても、エラーにならない
- 更新するとき、キーの無い項目については更新しない、という仕様の方が良い?
次回は上記の問題点を解消していきます。