go-ginチュートリアル — Part5
GinのBlog API’s 作成 — DB周り最終章
第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 routers
の articles
のAPIs
routers
の v1
のフォルダに、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
の方が定義関数を増えました。
gorm:index
,indexの定義Tag
の部分は実際tag
のstruct
をそのまま、利用します。更にTagID
とTag
が関連する、検索時、Article
、Tag
の関連検索ができます。time.Now().Unix()
timestampを返します。
上記の部分を理解したら、一気にその他の models
を追加します。
Topic
Article
とTag
の関連方法。関連の部分は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
フォルダの v1
にarticle.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