go-ginチュートリアル — Part5

GinのBlog API’s 作成 — DB周り最終章

gavin.zhou
8 min readNov 25, 2018

第4回の続き、DB周りその他のモジュールを作りましょう。サンプルコードはこちらでご参照ください。githubのtagは part05 となります。

Create ArticleのAPI’s、Models

Tag を作るのと同じで、コードを書く前に、一度整理します。下記の APIs が必要です。

  • 記事リスト一覧: GET("articles")
  • 指定記事取得: POST("/articles/:id")
  • 新規記事: POST("/articles")
  • 指定記事更新: PUT("/articles/:id")
  • 指定記事削除: DELETE("/articles/:id")

Create routersarticles のAPIs

routersv1のフォルダに、article.goフィアルを作ります。下記の内容となります。

package v1

import (
"github.com/gin-gonic/gin"
)

func GetArticle(c *gin.Context) {
}

func GetArticles(c *gin.Context) {
}

func AddArticle(c *gin.Context) {
}

func EditArticle(c *gin.Context) {
}

func DeleteArticle(c *gin.Context) {
}

次、routersフォルダでrouter.goフィアルを修正します。

package routers

import (
...
)

func InitRouter() *gin.Engine {
...
apiv1 := r.Group("/api/v1")
{
...

apiv1.GET("/articles", v1.GetArticles)
apiv1.GET("/articles/:id", v1.GetArticle)
apiv1.POST("/articles", v1.AddArticle)
apiv1.PUT("/articles/:id", v1.EditArticle)
apiv1.DELETE("/articles/:id", v1.DeleteArticle)
}

return r
}

プロジェクトのフォルダ構成は下記となります。

hello-gin
├── README.md
├── main.go
├── middleware
├── models
│ ├── article.go
│ ├── models.go
│ └── tag.go
├── pkg
│ ├── e
│ │ ├── code.go
│ │ └── msg.go
│ ├── setting
│ │ └── setting.go
│ └── util
│ └── pageination.go
├── routers
│ ├── api
│ │ └── v1
│ │ ├── article.go
│ │ └── tag.go
│ └── routers.go
└── runtime

基本的なルーティングルールの構成が終わったら、各 modeles実装の部分を作りましょう。

Created models article

modelsフォルダにarticle.goファイルを作ります。下記の内容通りです。

package models

import (
"github.com/jinzhu/gorm"

"time"
)

type Article struct {
Model

TagID int `json:"tag_id" gorm:"index"`
Tag Tag `json:"tag"`

Title string `json:"title"`
Description string `json:"description"`
Content string `json:"content"`
CreatedBy string `json:"created_by"`
ModifiedBy string `json:"modified_by"`
State int `json:"state"`
}


func (article *Article) BeforeCreate(scope *gorm.Scope) error {
scope.SetColumn("CreatedOn", time.Now().Unix())
scope.SetColumn("ModifiedOn", time.Now().Unix())
return nil
}

func (article *Article) BeforeUpdate(scope *gorm.Scope) error {
scope.SetColumn("ModifiedOn", time.Now().Unix())

return nil
}

以前 models tag を作った時にも説明しましたが、異なってる部分だけ、説明します。

Article struct {}Tagより,Articleの方が定義関数を増えました。

  1. gorm:index,indexの定義
  2. Tagの部分は実際 tagstructをそのまま、利用します。更にTagIDTagが関連する、検索時、ArticleTagの関連検索ができます。
  3. time.Now().Unix() timestampを返します。

上記の部分を理解したら、一気にその他の models を追加します。

Topic

  1. ArticleTag の関連方法。関連の部分は gorm 側が実装してます。
func GetArticle(id int) (article Article) {
db.Where("id = ?", id).First(&article)
db.Model(&article).Related(&article.Tag)

return
}
  • Articleには、 TagID 構造の部分があり、これは Tagのキーです。 gorm は、クラス名 + id の形式でこれら2つのクラス間の関連付けを見つけます。
  • Relateは記事とタグ関連クエリができます。

2. Preloadとは?,なぜ記事の検索で、 Tag関連が出てくるのでしょうか。

func GetArticles(pageNum int, pageSize int, maps interface {}) (articles []Article) {
db.Preload("Tag").Where(maps).Offset(pageNum).Limit(pageSize).Find(&articles)

return
}

Preloadは、2つの SQL を実行する方法です。SELECT * FROM blog_articles;SELECT * FROM blog_tag WHERE id IN (1,2,3,4);。そのマッピングした結果は gorm側が対応してます。結構便利機能です。

※確かに、 go-pg を使うと gorm より、クエリが早いですが、実装なら gorm がオススメです。

良い方法があれば、 issue をお願い致します。

スピードアップします。

routersフォルダの v1article.goファイルを修正します。

プロジェクトのフォルダ構成は下記となります。

hello-gin
├── README.md
├── main.go
├── middleware
├── models
│ ├── article.go
│ ├── models.go
│ └── tag.go
├── pkg
│ ├── e
│ │ ├── code.go
│ │ └── msg.go
│ ├── setting
│ │ └── setting.go
│ └── util
│ └── pageination.go
├── routers
│ ├── api
│ │ └── v1
│ │ ├── article.go
│ │ └── tag.go
│ └── routers.go
└── runtime

サーバを再起動し、確認しましょう。

insomnia を使い、下記のアクセスをしてみましょう。

  • POST:http://127.0.0.1:8000/api/v1/articles?tag_id=1&title=test1&description=test-description&content=test-content&created_by=test-created&state=1
  • GET:http://127.0.0.1:8000/api/v1/articles
  • GET:http://127.0.0.1:8000/api/v1/articles/2
  • PUT:http://127.0.0.1:8000/api/v1/articles/1?tag_id=1&title=test-edit1&description=test-desc-edit&content=test-content-edit&modified_by=test-created-edit&state=0
  • DELETE:http://127.0.0.1:8000/api/v1/articles/1

では、ここまでAPI’sの機能実装が終わりました。次回、別の機能を紹介します。

参考サイト

※問題があった場合は、githubの issue をお願いします。

--

--

No responses yet