Gin Practice Four Build blog API ' s (iii)

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.

Write article's API ' s, Models

Defining interfaces

This section writes the logic of the article, we define the interface!

    • Get a list of articles: Get ("/articles")
    • Get the specified article: Post ("/articles/:id")
    • New article: POST ("/articles")
    • Update specified article: PUT ("/articles/:id")
    • Delete the specified article: Delete ("/articles/:id")

Writing routing logic

routersunder the V1 version, create a new article.go file, write the content:

package v1import (    "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) {}

We open routers the following router.go file, modify the contents of the file as:

package routersimport (    "github.com/gin-gonic/gin"        "gin-blog/routers/api/v1"    "gin-blog/pkg/setting")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}

Current directory structure:

gin-blog/├── conf│   └── app.ini├── main.go├── middleware├── models│   ├── models.go│   └── tag.go├── pkg│   ├── e│   │   ├── code.go│   │   └── msg.go│   ├── setting│   │   └── setting.go│   └── util│       └── pagination.go├── routers│   ├── api│   │   └── v1│   │       ├── article.go│   │       └── tag.go│   └── router.go├── runtime

After the basic routing rule configuration is complete, let's start writing our interface !

Writing models Logic

Create models a directory article.go , write the contents of the file:

package modelsimport (    "github.com/jinzhu/gorm"    "time")type Article struct {    Model    TagID int `json:"tag_id" gorm:"index"`    Tag   Tag `json:"tag"`    Title string `json:"title"`    Desc string `json:"title"`    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())    return nil}func (article *Article) BeforeUpdate(scope *gorm.Scope) error {    scope.SetColumn("ModifiedOn", time.Now().Unix())    return nil}

We created one Article struct {} , with the Tag difference is that a Article few more

    1. gorm:index, which declares that this field is indexed, and if you use the Auto-migration feature, it will have an effect if you do not use it.
    2. Tagfield, which is actually a nested struct , it is used to TagID correlate with the model, Tag when executing the query, can reach Article , the Tag function of correlation query
    3. time.Now().Unix()Returns the current timestamp

Next, make sure that you have read through and understand the contents of the previous chapter, because the logical deviations are not too far away, we write these five interfaces directly in this section

Open models Directory article.go , modify the contents of the file:

Package Modelsimport ("Time" "Github.com/jinzhu/gorm") type article struct {Model TagID int ' json: "tag_id" Go RM: "index" ' tag tag ' json: ' Tag ' ' title string ' JSON: ' title ' ' Desc string ' json: ' title ' ' Content string ' json : "Content" ' CreatedBy string ' JSON: "created_by" ' ModifiedBy string ' JSON: "modified_by" ' state int ' JSON: "State" '} Func Existarticlebyid (id int) BOOL {var article article db. Select ("id"). Where ("id =?", id). First (&article) if article.id > 0 {return true} return False}func Getarticletotal (Maps interface {}) (count int) {db. Model (&article{}). Where (MAPS). Count (&count) return}func getarticles (pagenum int, pageSize int, maps Interface {}) (articles []article) {db]. Preload ("Tag"). Where (MAPS). Offset (Pagenum). Limit (pageSize). Find (&articles) return}func GetArticle (id int) (article article) {db. Where ("id =?", id). First (&article) db. Model (&article). Related (&article. TAG) reTurn}func editarticle (id int, data Interface {}) bool {db. Model (&article{}). Where ("id =?", id). Updates (data) return True}func addarticle (data map[string]interface {}) bool {db. Create (&article {tagid:data["tag_id"]. ( int), title:data["Title"]. (string), desc:data["Desc"]. (string), content:data["Content". (string), createdby:data["created_by"]. (string), state:data["state"]. (int),}) return true}func deletearticle (id int) BOOL {db. Where ("id =?", id). Delete (article{}) return True}func (article *article) beforecreate (Scope *gorm. Scope) Error {scope. Setcolumn ("CreatedOn", time. Now (). Unix ()) return Nil}func (article *article) BeforeUpdate (Scope *gorm. Scope) Error {scope. Setcolumn ("ModifiedOn", time. Now (). Unix ()) return nil}

Here we come up with a three-point difference in terms of

1. Article How do we relate to Tag ???

func GetArticle(id int) (article Article) {    db.Where("id = ?", id).First(&article)    db.Model(&article).Related(&article.Tag)    return }

Be able to reach the association, first of all it gorm has done a lot of conventional

    • ArticleThere is a struct member that is TagID the foreign key. The gorm association between these two classes is found through the +id of the class name.
    • ArticleThere is a struct member, which is the Tag structure we nest in Article Tag , and we can do this by Related correlating the query

2, Preload What is the thing, why the query can draw the association of each item Tag ?

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

Preloadis a preloader, it will execute two SQL, respectively SELECT * FROM blog_articles; SELECT * FROM blog_tag WHERE id IN (1,2,3,4); , and, then after querying out the structure, the gorm internal processing of the corresponding mapping logic, filling it into Article the Tag , will be particularly convenient, and avoid the circular query

So is there any other way, roughly two kinds of

    • gormOfJoin
    • CycleRelated

Integrated, or Preload better, if you have a better plan, welcome to say:)

3, v.(I) what is it?

vRepresents an interface value that I represents an interface type. This is actually the type assertion in Golang, which is used to determine whether the actual type of an interface value is a type, or whether the type of a non-interface value implements an interface type

Open routers The Directory V1 version of the article.go file, modify the contents of the file:

Package V1import ("Net/http" "Log" "Github.com/gin-gonic/gin" "Github.com/astaxie/beego/validation" "Githu B.com/unknwon/com "" Gin-blog/models "" gin-blog/pkg/e "" gin-blog/pkg/setting "" gin-blog/pkg/util ")//Get single article Func GetArticle (c *gin. Context) {id, _: = com. Strto (C.param ("id")). Int () Valid: = Validation. validation{} valid. Min (ID, 1, "id"). Message ("ID must be greater than 0") Code: = e.invalid_params var data interface {} if! Valid. HasErrors () {if models. Existarticlebyid (ID) {data = models. GetArticle (id) code = e.success} else {code = e.error_not_exist_article}} else {for _, err: = range valid. Errors {log. Println (Err. Key, Err. Message)}} c.json (http. Statusok, Gin. h{"Code": Code, "MSG": E.getmsg (Code), "Data": Data,})}//get multiple articles func Getarticles (c *gin. Context) {data: = Make (map[string]interface{}) Maps: = Make (Map[string]interface{}) Valid: = Validation. validation{} var state int. =-1 if arg: = C.query ("state"); Arg! = "" {state, _ = com. Strto (ARG). Int () maps["state"] = State valid. Range (state, 0, 1, "state"). Message ("state only allows 0 or 1")} var tagId int =-1 if arg: = C.query ("tag_id"); Arg! = "" {tagId, _ = com. Strto (ARG). Int () maps["tag_id"] = tagId valid. Min (tagId, 1, "tag_id"). Message ("tag ID must be greater than 0")} code: = E.invalid_params if! Valid. HasErrors () {code = e.success data["lists"] = models. Getarticles (util. GetPage (c), setting. PageSize, maps) data["Total" = models. Getarticletotal (MAPS)} else {for _, err: = range valid. Errors {log. Println (Err. Key, Err. Message)}} c.json (http. Statusok, Gin. h{"Code": Code, "MSG": E.getmsg (Code), "Data": Data,})}//new article Func addarticle (c *gin. Context) {TagId, _: = com. Strto (C.query ("tag_id")).   Int () Title: = C.query ("title") Desc: = c.query ("desc") Content: = C.query ("content") CreatedBy: = C.query ("created_by") state, _: = com. Strto (C.defaultquery ("state", "0")). Int () Valid: = Validation. validation{} valid. Min (tagId, 1, "tag_id"). Message ("label ID must be greater than 0") valid. Required (title, "title"). Message ("Title cannot be empty") valid. Required (DESC, "desc"). Message ("Brief description cannot be empty") valid. Required (Content, "content"). Message ("Content cannot be empty") valid. Required (CreatedBy, "created_by"). Message ("Creator cannot be empty") valid. Range (state, 0, 1, "state"). Message ("state only allows 0 or 1") Code: = E.invalid_params if! Valid. HasErrors () {if models. Existtagbyid (tagId) {data: = Make (Map[string]interface {}) data["tag_id"] = tagId data[" Title "] = title data[" desc "] = desc data[" Content "] = content data[" created_by "] = Create DBy data["state") = State models. Addarticle (data) code = e.success} else {code = E.error_not_eXist_tag}} else {for _, err: = range valid. Errors {log. Println (Err. Key, Err. Message)}} c.json (http. Statusok, Gin. h{"Code": Code, "MSG": E.getmsg (Code), "Data": Make (map[string]interface{}),}//Modify article func Edi Tarticle (c *gin. Context) {valid: = validation. validation{} ID, _: = com. Strto (C.param ("id")). Int () TagId, _: = com. Strto (C.query ("tag_id")). Int () Title: = C.query ("title") Desc: = C.query ("desc") Content: = C.query ("content") ModifiedBy: = C.query ("M Odified_by ") var state int. =-1 if arg: = C.query (" state "); Arg! = "" {state, _ = com. Strto (ARG). Int () valid. Range (state, 0, 1, "state"). Message ("state only allows 0 or 1")} valid. Min (ID, 1, "id"). Message ("ID must be greater than 0") valid. MaxSize (title, "title"). Message ("title up to 100 characters") valid. MaxSize (DESC, 255, "desc"). Message ("A description of the maximum of 255 characters") valid. MaxSize (content, 65535, "content"). Message ("Maximum content of 65535 characters") valid. Required (ModifiedBy, "MOdified_by "). Message ("Modifier cannot be empty") valid. MaxSize (ModifiedBy, "modified_by"). Message ("modifier maximum of 100 characters") Code: = E.invalid_params if! Valid. HasErrors () {if models. Existarticlebyid (ID) {if models.                      Existtagbyid (tagId) {data: = Make (Map[string]interface {}) if TagId > 0 { data["tag_id"] = tagId} if title! = "" {data["title"]                  = Title} If desc = "" {data["desc"] = desc} If content! = "" {data["content"] = content} data[ "modified_by"] = ModifiedBy models. Editarticle (ID, data) code = e.success} else {code = E.error_not_exist_ta G}} else {code = E.error_not_exist_article}} else {for_, Err: = range valid. Errors {log. Println (Err. Key, Err. Message)}} c.json (http. Statusok, Gin. h{"Code": Code, "MSG": E.getmsg (Code), "Data": Make (Map[string]string),})}//Delete article func deletear Ticle (c *gin. Context) {id, _: = com. Strto (C.param ("id")). Int () Valid: = Validation. validation{} valid. Min (ID, 1, "id"). Message ("ID must be greater than 0") Code: = E.invalid_params if! Valid. HasErrors () {if models. Existarticlebyid (ID) {models. Deletearticle (id) code = e.success} else {code = e.error_not_exist_article}} el Se {for _, err: = range valid. Errors {log. Println (Err. Key, Err. Message)}} c.json (http. Statusok, Gin. h{"Code": Code, "MSG": E.getmsg (Code), "Data": Make (Map[string]string),})}

Current directory structure:

gin-blog/├── conf│   └── app.ini├── main.go├── middleware├── models│   ├── article.go│   ├── models.go│   └── tag.go├── pkg│   ├── e│   │   ├── code.go│   │   └── msg.go│   ├── setting│   │   └── setting.go│   └── util│       └── pagination.go├── routers│   ├── api│   │   └── v1│   │       ├── article.go│   │       └── tag.go│   └── router.go├── runtime

Validation features

We restart the service, execute go run main.go , check the console output results

$ go Run Main.go [gin-debug] [WARNING] Running in "Debug" mode. Switch to "release" mode in production. -Using Env:export gin_mode=release-using code:gin. SetMode (gin. Releasemode) [Gin-debug] Get/api/v1/tags---gin-blog/routers/api/v1. GetTags (3 handlers) [Gin-debug] post/api/v1/tags--gin-blog/routers/api/v1. Addtag (3 handlers) [Gin-debug] Put/api/v1/tags/:id--gin-blog/routers/api/v1. Edittag (3 handlers) [Gin-debug] Delete/api/v1/tags/:id--gin-blog/routers/api/v1. Deletetag (3 handlers) [Gin-debug] get/api/v1/articles--gin-blog/routers/api/v1. Getarticles (3 handlers) [Gin-debug] Get/api/v1/articles/:id--gin-blog/routers/api/v1. GetArticle (3 handlers) [Gin-debug] post/api/v1/articles--gin-blog/routers/api/v1. Addarticle (3 handlers) [Gin-debug] Put/api/v1/articles/:id--gin-blog/routers/api/v1. Editarticle (3 handlers) [Gin-debug] delete/api/v1/aRticles/:id--Gin-blog/routers/api/v1. Deletearticle (3 handlers)

The use Postman of test interface is normal (we can choose the appropriate parameter transfer method, here in order to facilitate the display I chose the URL parameter),

    • Post:http://127.0.0.1:8000/api/v1/articles?tag_id=1&title=test1&desc=test-desc&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/1
    • Put:http://127.0.0.1:8000/api/v1/articles/1?tag_id=1&title=test-edit1&desc=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

So far, our API's writing is here, and the next section we'll cover some other tricks!

Reference

Sample code for this series

    • Go-gin-example
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.