API’s, Models for Tag
Project address:https://github.com/EDDYCJY/go …
This major section will cover the following knowledge points:
- gin: Golang’s micro-frame with excellent performance
- beego-validation: beego’s form validation library used in this section,Chinese document
- gorm, a developer-friendly ORM framework,English document
- com, toolkit
- Writing Business Logic
We began to write business code, blog articles will haveLabelThe concept of,
Define interface
This section is the logic for writing labels. Let’s think about it. General interfaces are based on adding, deleting, modifying and checking. Then let’s define the interfaces.
- Get tag list: GET(“/tags “)
- New tag: POST(“/tags “)
- Update specified tag: PUT(“/tags/:id “)
- Delete the specified tag: DELETE(“/tags/:id “)
Writing a routing shell
Start writing routing file logic, inrouters
New belowapi
Directory, we are currently the first major API version, so inapi
New belowv1
Directory, and then create a new onetag.go
File, write content:
package v1
import (
"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) {
}
Register route
We open itrouters
inferiorrouter.go
File, modify the file content as follows:
package routers
import (
"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 was successfully registered
Go back to the command line and executego run main.go
, check whether the routing rule was successfully registered.
$ 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)
If the operation is successful, then we are happyStart writing our interface!
Download dependency package
First of all, we have to pullvalidation
The dependency package of will be used for form validation in the following interface.
go get -u github.com/astaxie/beego/validation
Models logic for writing tag lists
Createmodels
Under the directorytag.go
, write file content:
package models
type 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
}
- We created a
Tag struct{}
ForGorm
The use of. And give the subsidiary attributejson
, like this inc.JSON
It is very convenient to convert the format automatically - Some beginners may see it
return
, and not followed by variables, will not understand; In fact, you can see at the end of the function that we have already declared the return value. This variable can also be used directly in the function body because it was declared at the beginning. - Some people may wonder
db
Where did you come from? Because in the samemodels
Under the bag, thereforedb *gorm.DB
Can be directly used
Routing logic for writing label lists
Openrouters
The v1 version of thetag.go
First, let’s write it firstGets the interface for the label list
Modify file contents:
package v1
import (
"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).MustInt()
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) {
}
-
c.Query
Available for obtaining? name=test&state=1
This type of URL parameter, whilec.DefaultQuery
Setting a default value is supported -
code
Variables are usede
The error code of the module, which is the previously planned error code, is convenient to debug and identify records. -
util.GetPage
Ensure that the interface of thepage
The treatment is consistent. -
c *gin.Context
YesGin
An important component, which can be understood as context, allows us to pass variables, manage flows, validate JSON for requests, and render JSON responses between intermediates
Run locallycurl 127.0.0.1:8000/api/v1/tags
, the correct return value is{"code":200,"data":{"lists":[],"total":0},"msg":"ok"}
If there is any problem, please combine the gin results for wrong shooting.
In the interface for obtaining the tag list, we can use thename
、state
、page
To filter the query criteria, paging step size can be throughapp.ini
Configure tolists
、total
The combination of return to achieve paging effect.
Writing models Logic for Adding Labels
Next we writeAdd tagInterface of
Openmodels
The v1 version of thetag.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
}
...
Write routing logic for adding tags
Openrouters
Under the directorytag.go
, modify the file (change AddTag method):
package v1
import (
"log"
"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 AddTag(c *gin.Context) {
name := c.Query("name")
state := com.StrTo(c.DefaultQuery("state", "0")).MustInt()
createdBy := c.Query("created_by")
valid := validation.Validation{}
valid.Required(name, "name").Message("名称不能为空")
valid.MaxSize(name, 100, "name").Message("名称最长为100字符")
valid.Required(createdBy, "created_by").Message("创建人不能为空")
valid.MaxSize(createdBy, 100, "created_by").Message("创建人最长为100字符")
valid.Range(state, 0, 1, "state").Message("状态只允许0或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
}
}
c.JSON(http.StatusOK, gin.H{
"code" : code,
"msg" : e.GetMsg(code),
"data" : make(map[string]string),
})
}
...
UsePostman
POST accesshttp://127.0.0.1:8000/api/v1/tags? name=1&state=1&created_by=test
, viewcode
Do you want to return200
Andblog_tag
Whether there is a value in the table, the value is correct.
Writing models callbacks
But this time you will find that I clearly added the label, butcreated_on
There is no value at all. When modifying the labelmodified_on
Will this problem also exist?
In order to solve this problem, we need to open itmodels
Under the directorytag.go
File, modify file content (modify package reference and add 2 methods):
package models
import (
"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 use it again.Postman
POST accesshttp://127.0.0.1:8000/api/v1/tags? name=2&state=1&created_by=test
, found thatcreated_on
It’s already worth it!
In these sections of code, knowledge points are involved:
This belongs togorm
TheCallbacks
, the callback method can be defined as a pointer to the model structure and will be called when creating, updating, querying and deleting. If any callback returns an error, gorm will stop future operations and roll back all changes.
gorm
Supported callback methods:
- Create: foresave, forecreate, AfterCreate, AfterSave
- Update: foresave, foreupdate, AfterUpdate, AfterSave
- Delete: BeforeDelete, AfterDelete
- Query: AfterFind
Write routing logic for the remaining interfaces
Next, let’s finish the remaining two interfaces (EditTag, DeleteTag) at one go.
Openrouters
The v1 version of thetag.go
File, modify content:
...
//修改文章标签
func EditTag(c *gin.Context) {
id := com.StrTo(c.Param("id")).MustInt()
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).MustInt()
valid.Range(state, 0, 1, "state").Message("状态只允许0或1")
}
valid.Required(id, "id").Message("ID不能为空")
valid.Required(modifiedBy, "modified_by").Message("修改人不能为空")
valid.MaxSize(modifiedBy, 100, "modified_by").Message("修改人最长为100字符")
valid.MaxSize(name, 100, "name").Message("名称最长为100字符")
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
}
}
c.JSON(http.StatusOK, gin.H{
"code" : code,
"msg" : e.GetMsg(code),
"data" : make(map[string]string),
})
}
//删除文章标签
func DeleteTag(c *gin.Context) {
id := com.StrTo(c.Param("id")).MustInt()
valid := validation.Validation{}
valid.Min(id, 1, "id").Message("ID必须大于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
}
}
c.JSON(http.StatusOK, gin.H{
"code" : code,
"msg" : e.GetMsg(code),
"data" : make(map[string]string),
})
}
Writing models Logic for Other Interfaces
Openmodels
inferiortag.go
, modify the file content:
...
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
}
...
Verification function
Restart the service and use Postman.
- PUT accesshttp://127.0.0.1:8000/api/v1/tags/1? Name = edit1 & state = 0 & modified _ by = edit1 to see if code returns 200
- DELETE accesshttp://127.0.0.1: 8000/api/v1/tags/1 to see if code returns 200
At this point, Tag’s API’s is complete, and in the next section we will begin to write Article’s API’s!
References
This series of sample codes
This series of catalogues
- Serial One Golang Introduction and Environmental Installation
- Serialized 2 to build Blog API’s (1)
- Serial 3 to build Blog API’s (2)
- Serial 4 to build Blog API’s (3)
- Serial 5 Use JWT for Identity Verification
- Serial 6 Write a Simple File Log
- Serial Seven Golang Gracefully Restart HTTP Service
- Serial 8 Add Swagger to It
- Serial 9 Deploying Golang Applications to Docker
- Serial Ten Customized GORM Callbacks
- Serial Eleven Cron Scheduled Tasks
- Serial 12 Optimizing Configuration Structure and Realizing Picture Upload
- Serialization 13 Optimize Your Application Structure and Implement Redis Cache
- Serial 14 Realize Export and Import into Excel
- Serial 15 Generate Two-dimensional Code and Merge Posters
- Serial 16 Draw Text on Pictures
- Serial 17 Deploying Go Applications with Nginx
- Cross-compilation of safari Golang
- Please get started with Makefile