Gin Practice three Build blog API ' s (ii)

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

Write tag's API ' s, Models

This large sections will involve the following knowledge points:

    1. Gin:golang a micro-frame, excellent performance
    2. Beego-validation: The Beego Form validation library used in this section, Chinese documents
    3. Gorm, developer-friendly ORM framework, English documentation
    4. COM, toolkit
    5. The writing of business logic

We started writing business code, and the blog post would have a label concept,

Defining interfaces

This section is to write the logic of the label, we think about, the general interface for adding and deleting is the basis of the change, then we define the interface bar!

    • Get a list of tags: get ("/tags")
    • New label: POST ("/tags")
    • Update the specified label: PUT ("/tags/:id")
    • Delete the specified tag: delete ("/tags/:id")

To write a routed empty shell

Start to write the routing file logic, routers under the new api directory, we are currently the first API large version, so api under the new v1 directory, create new tag.go files, write content:

package v1import (    "github.com/gin-gonic/gin")//获取多个文章标签func GetTags(c *gin.Context) {}//新增文章标签func AddTag(c *gin.Context) {}//修改文章标签func EditTag(c *gin.Context) {}//删除文章标签func DeleteTag(c *gin.Context) {}

Registering routes

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 {    r := gin.New()    r.Use(gin.Logger())    r.Use(gin.Recovery())    gin.SetMode(setting.RunMode)    apiv1 := r.Group("/api/v1")    {        //获取标签列表        apiv1.GET("/tags", v1.GetTags)        //新建标签        apiv1.POST("/tags", v1.AddTag)        //更新指定标签        apiv1.PUT("/tags/:id", v1.EditTag)        //删除指定标签        apiv1.DELETE("/tags/:id", v1.DeleteTag)    }    return r}

Current directory structure:

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

Verify that the route is registered successfully

Go back to the command line, execute go run main.go , check whether the routing rule is registered successfully.

$ 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)

Run successfully, then we happily begin to write our interface !

Download Dependent packages

First of all we want to pull validation the dependency package, in the back of the interface will use to form validation

go get -u github.com/astaxie/beego/validation

Models logic for writing tag lists

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

package modelstype Tag struct {    Model    Name string `json:"name"`    CreatedBy string `json:"created_by"`    ModifiedBy string `json:"modified_by"`    State int `json:"state"`}func GetTags(pageNum int, pageSize int, maps interface {}) (tags []Tag) {    db.Where(maps).Offset(pageNum).Limit(pageSize).Find(&tags)        return}func GetTagTotal(maps interface {}) (count int){    db.Model(&Tag{}).Where(maps).Count(&count)    return}
    1. We created one Tag struct{} that was used for Gorm the use. and gives a subordinate attribute json , so that c.JSON when the child will automatically convert the format, very convenient
    2. There may be some beginners see return , and the latter does not follow the variable, will not understand; in fact, you can see at the end of the function, we have shown that the return value is declared, this variable can be used directly in the body of the function, because he was declared at the outset
    3. Some people will wonder db where it comes from, because under the same models package, so it db *gorm.DB can be used directly

Routing logic for writing label lists

Open routers The directory under the V1 version tag.go , first we write the interface to get the label list

To modify the contents of a file:

package v1import (    "net/http"    "github.com/gin-gonic/gin"    //"github.com/astaxie/beego/validation"    "github.com/Unknwon/com"    "gin-blog/pkg/e"    "gin-blog/models"    "gin-blog/pkg/util"    "gin-blog/pkg/setting")//获取多个文章标签func GetTags(c *gin.Context) {    name := c.Query("name")    maps := make(map[string]interface{})    data := make(map[string]interface{})    if name != "" {        maps["name"] = name    }    var state int = -1    if arg := c.Query("state"); arg != "" {        state, _ = com.StrTo(arg).Int()        maps["state"] = state    }    code := e.SUCCESS    data["lists"] = models.GetTags(util.GetPage(c), setting.PageSize, maps)    data["total"] = models.GetTagTotal(maps)    c.JSON(http.StatusOK, gin.H{        "code" : code,        "msg" : e.GetMsg(code),        "data" : data,    })}//新增文章标签func AddTag(c *gin.Context) {}//修改文章标签func EditTag(c *gin.Context) {}//删除文章标签func DeleteTag(c *gin.Context) {}
    1. c.QueryCan be used to get such ?name=test&state=1 URL parameters, while c.DefaultQuery setting a default value is supported
    2. codeThe variable uses the e module's error code, which is the previously planned error code to facilitate troubleshooting and identification of records
    3. util.GetPageEnsures that the processing of each interface page is consistent
    4. c *gin.ContextIs Gin an important component that can be understood as context, which allows us to pass variables between middleware, manage flows, validate JSON of requests, and render JSON responses

In the local execution curl 127.0.0.1:8000/api/v1/tags , the correct return value is {"code":200,"data":{"lists":[],"total":0},"msg":"ok"} , if there is a problem, please combine the gin result to make a mistake.

In the Get tag list interface, we can filter the query criteria according to,,, the step of name state page paging can be app.ini configured, in lists combination, to total return to achieve the paging effect.

Models logic to write new tags

Next we write the interface for adding tags

Open models the directory under V1 version tag.go , modify the file (add 2 methods):

...func ExistTagByName(name string) bool {    var tag Tag    db.Select("id").Where("name = ?", name).First(&tag)    if tag.ID > 0 {        return true    }    return false}func AddTag(name string, state int, createdBy string) bool{    db.Create(&Tag {        Name : name,        State : state,        CreatedBy : createdBy,    })    return true}...

Routing logic to write new tags

Open routers directory tag.go , modify file (change Addtag method):

Package V1import ("Log" "Net/http" "Github.com/gin-gonic/gin" "Github.com/astaxie/beego/validation" "Githu B.com/unknwon/com "gin-blog/pkg/e" "Gin-blog/models" "Gin-blog/pkg/util" "gin-blog/pkg/setting") ...//Add article label Fu NC addtag (c *gin. Context) {Name: = C.query ("name") state, _: = com. Strto (C.defaultquery ("state", "0")). Int () CreatedBy: = C.query ("created_by") Valid: = Validation. validation{} valid. Required (name, "name"). Message ("Name cannot be empty") valid. Required (name, "Created_by"). Message ("Creator cannot be empty") valid. MaxSize (name, +, "created_by"). Message ("creator maximum of 100 characters") valid. MaxSize (name, +, "name"). Message ("Maximum name is 100 characters") valid. Range (state, 0, 1, "state"). Message ("state only allows 0 or 1") Code: = E.invalid_params if! Valid. HasErrors () {if! models. Existtagbyname (name) {code = E.success models. Addtag (name, State, CreatedBy)} else {code = E.error_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]string),})} ...

Use Postman post access http://127.0.0.1:8000/api/v1/tags?name=1&state=1&created_by=test to see code if the return 200 and the blog_tag table have values, and the values are correct.

Write Models Callbacks

But this time people will find, I clearly added a tag, but created_on actually no value, then do change the label when modified_on there is this problem?

To solve this problem, we need to open the models file in the directory tag.go , modify the contents of the file (modify the package reference and add 2 methods):

package modelsimport (    "time"    "github.com/jinzhu/gorm")...func (tag *Tag) BeforeCreate(scope *gorm.Scope) error {    scope.SetColumn("CreatedOn", time.Now().Unix())    return nil}func (tag *Tag) BeforeUpdate(scope *gorm.Scope) error {    scope.SetColumn("ModifiedOn", time.Now().Unix())    return nil}

Restart the service, and then use the Postman post access http://127.0.0.1:8000/api/v1/tags?name=2&state=1&created_by=test , found that created_on already has the value!

In these pieces of code, the knowledge points are involved:

This belongs to gorm a Callbacks callback method that can be defined as a pointer to a model structure that will be called when created, updated, queried, deleted, and if any callbacks return an error, Gorm will stop future operations and roll back all changes.

gormSupported Callback methods:

    • Created: BeforeSave, Beforecreate, Aftercreate, Aftersave
    • Updated: BeforeSave, BeforeUpdate, AfterUpdate, Aftersave
    • Delete: BeforeDelete, AfterDelete
    • Enquiry: Afterfind

Write routing logic for the rest of the interfaces

Next, let's take the remaining two interfaces (Edittag, Deletetag) in one gulp.

Open routers The directory under the V1 version of the tag.go file, modify the content:

...//modify article label Func Edittag (C *gin. Context) {id, _: = com. Strto (C.param ("id")). Int () Name: = C.query ("name") ModifiedBy: = C.query ("modified_by") Valid: = Validation. validation{} 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. Required (ID, "id"). Message ("ID cannot be empty") valid. Required (ModifiedBy, "modified_by"). Message ("Modifier cannot be empty") valid. MaxSize (ModifiedBy, "modified_by"). Message ("modifier maximum is 100 characters") valid. MaxSize (name, +, "name"). Message ("Maximum name is 100 characters") Code: = E.invalid_params if! Valid. HasErrors () {code = E.success if models.            Existtagbyid (ID) {Data: = Make (map[string]interface{}) data["modified_by"] = ModifiedBy  If name! = "" {data["name"] = name} if state! =-1 {data["state"] = State} models.      Edittag (ID, data)  } 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]string),})}//delete Article tag func Dele Tetag (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 () {code = E.success if models. Existtagbyid (ID) {models. Deletetag (ID)} else {code = E.error_not_exist_tag}} else {for _, err: = Range Vali d.errors {log. Println (Err. Key, Err. Message)}} c.json (http. Statusok, Gin. h{"Code": Code, "MSG": E.getmsg (Code), "Data": Make (Map[string]string),})}

Write models logic for the rest of the interfaces

Open models tag.go , modify the contents of the file:

...func ExistTagByID(id int) bool {    var tag Tag    db.Select("id").Where("id = ?", id).First(&tag)    if tag.ID > 0 {        return true    }    return false}func DeleteTag(id int) bool {    db.Where("id = ?", id).Delete(&Tag{})    return true}func EditTag(id int, data interface {}) bool {    db.Model(&Tag{}).Where("id = ?", id).Updates(data)    return true}...

Validation features

Restart the service with postman

    • Put access http://127.0.0.1:8000/api/v1/tags/1?name=edit1&state=0&modified_by=edit1 to see if code returns 200
    • Delete Access HTTP://127.0.0.1:8000/API/V1/TAGS/1 to see if code returns 200

At this point, the tag API's is complete, and the next section we will start article API's writing!

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.