引言
- 一个完整的api服务包括哪些?
- 路由、控制器层、model层、统一返回格式
- 接下来我们一一实现这些
- github代码地址
1、首先路由配置
config/api.go
package routes
import (
"go-api/app/controller"
"github.com/gin-gonic/gin"
)
func apiRoute(r *gin.Engine){
apiv1 := r.Group("/api/v1")
{
//获取用户列表
apiv1.GET("/users", controller.GetUsers)
//获取指定用户
apiv1.GET("/user/:id", controller.GetUser)
//新增用户
apiv1.POST("/users", controller.AddUser)
//更新指定用户
apiv1.PUT("/users/:id", controller.EditUser)
//删除指定用户
apiv1.DELETE("/users/:id", controller.DeleteUser)
}
}
2、在tool目录下
新增convent.go
package tool
import (
"encoding/json"
"reflect"
"strconv"
//"fmt"
)
func JsonToStruct(data []byte, s interface{}) error {
err := json.Unmarshal(data, s)
if err != nil {
//err = fmt.Sprintf("Json marshaling failed:%s", err)
return err
}
return nil
}
func StringToInt(str string) int {
variable, _ := strconv.Atoi(str)
return variable
}
func StructToMap(obj interface{}) map[string]interface{} {
t := reflect.TypeOf(obj)
v := reflect.ValueOf(obj)
var data = make(map[string]interface{})
for i := 0; i < t.NumField(); i++ {
data[t.Field(i).Name] = v.Field(i).Interface()
}
return data
}
新增pagination.go (处理全局获取page分页 起始偏移量)
package tool
import (
"github.com/gin-gonic/gin"
"go-api/config"
)
//get Offset limit Optional
func GetOffset(c *gin.Context, limit int) int {
page := StringToInt(c.DefaultQuery("page", "0"))
return getOffset(page, limit)
}
//get Offset limit default
func DefaultGetOffset(c *gin.Context) int {
page := StringToInt(c.DefaultQuery("page", "0"))
return getOffset(page, config.AppSetting.PageSize)
}
func getOffset(page int, limit int) int {
result := 0
if page > 0 {
result = (page - 1) * limit
}
return result
}
新增apiMsg.go (API返回错误码对应错误信息)
package tool
import "fmt"
const (
SUCCESS = 0
ERROR = 500
INVALID_PARAMS = 400
CUSTOM_ERROR = 40001
ERROR_AUTH_CHECK_TOKEN_FAIL = 20001
ERROR_AUTH_CHECK_TOKEN_TIMEOUT = 20002
ERROR_AUTH_TOKEN = 20003
ERROR_AUTH = 20004
ERROR_AUTH_CHECK_TOKEN_EMPTY = 20005
)
var MsgFlags = map[int]string{
SUCCESS: "%s",
ERROR: "%s",
INVALID_PARAMS: "参数%s错误",
CUSTOM_ERROR: "%s",
ERROR_AUTH_CHECK_TOKEN_FAIL: "Token鉴权失败",
ERROR_AUTH_CHECK_TOKEN_TIMEOUT: "Token已超时",
ERROR_AUTH_TOKEN: "Token生成失败",
ERROR_AUTH: "Token错误",
ERROR_AUTH_CHECK_TOKEN_EMPTY: "Token参数不能为空",
}
func GetMsg(code int, Msg ...interface{}) string {
msg, ok := MsgFlags[code]
if ok {
return fmt.Sprintf(msg, Msg...)
}
return MsgFlags[ERROR]
}
3、完善models
完善models/user.go
package models
type User struct {
Model
Name string `json:"name"`
CreatedBy string `json:"created_by"`
ModifiedBy string `json:"modified_by"`
}
func GetUsers(pageNum int, pageSize int, maps interface{}) (users []User) {
db.Where(maps).Offset(pageNum).Limit(pageSize).Find(&users)
return
}
func GetUser(id int) (user User, err error) {
if err := db.First(&user, id).Error; err != nil {
return user, err
}
return user, nil
}
func GetUserTotal(maps interface{}) (count int) {
db.Model(&User{}).Where(maps).Count(&count)
return
}
func ExistUserByMaps(maps interface{}) bool {
var user User
db.Select("id").Where(maps).First(&user)
if user.ID > 0 {
return true
}
return false
}
func AddUser(Users map[string]interface{}) bool {
user := User{
Name: Users["Name"].(string),
CreatedBy: Users["CreatedBy"].(string),
}
db.Create(&user)
return !db.NewRecord(user)
}
func ExistTagByID(id int) bool {
var user User
db.Select("id").Where("id = ?", id).First(&user)
if user.ID > 0 {
return true
}
return false
}
func DeleteUser(maps interface{}) (bool, error) {
if err := db.Where(maps).Delete(&User{}).Error; err != nil {
return false, err
}
return true, nil
}
func EditUser(id int, data interface{}) (bool, error) {
if err := db.Model(&User{}).Where("id = ?", id).Updates(data).Error; err != nil {
return false, err
}
return true, nil
}
4、完善控制器
完善controller/user.go
package controller
import (
"github.com/gin-gonic/gin"
"fmt"
"go-api/app/models"
"go-api/tool"
)
func GetUsers(c *gin.Context) {
maps := make(map[string]interface{})
data := make(map[string]interface{})
data["total"] = models.GetUserTotal(maps)
data["list"] = models.GetUsers(tool.DefaultGetOffset(c), 10, maps)
c.JSONP(200, gin.H{"error_code": 0, "msg": tool.GetMsg(0, "查询成功"), "data": data})
}
func GetUser(c *gin.Context) {
id := c.Param("id")
res, err := models.GetUser(tool.StringToInt(id))
if err != nil {
c.JSONP(200, gin.H{"error_code": 40001, "msg": tool.GetMsg(40001, "暂无数据"), "err": fmt.Sprint(err)})
} else {
c.JSONP(200, gin.H{"error_code": 0, "msg": tool.GetMsg(0, "查询成功"), "data": res})
}
}
func AddUser(c *gin.Context) {
name := c.PostForm("name")
created_by := c.PostForm("created_by")
data := make(map[string]interface{})
maps := make(map[string]interface{})
if name == "" {
c.JSONP(200, gin.H{"error_code": 40001, "msg": tool.GetMsg(40001, "名称不能为空")})
} else {
data["Name"] = name
maps["Name"] = name
data["CreatedBy"] = created_by
if !models.ExistUserByMaps(maps) {
res := models.AddUser(data)
if res {
c.JSONP(200, gin.H{"error_code": 0, "msg": tool.GetMsg(0, "创建成功"), "data": data})
} else {
c.JSONP(200, gin.H{"error_code": 40001, "msg": tool.GetMsg(40001, "创建失败")})
}
} else {
c.JSONP(200, gin.H{"error_code": 40001, "msg": tool.GetMsg(40001, "该名称已存在"), "map": maps})
}
}
}
func EditUser(c *gin.Context) {
id := tool.StringToInt(c.Param("id"))
name := c.PostForm("name")
created_by := c.PostForm("created_by")
if !models.ExistTagByID(id) {
c.JSONP(200, gin.H{
"error_code": 40001,
"msg": tool.GetMsg(40001, "ID不存在"),
})
} else {
data := make(map[string]interface{})
data["name"] = name
data["created_by"] = created_by
res, err := models.EditUser(id, data)
if res {
c.JSONP(200, gin.H{
"error_code": 0,
"msg": tool.GetMsg(40001, "编辑成功"),
})
} else {
c.JSONP(200, gin.H{
"error_code": 40001,
"msg": tool.GetMsg(40001, "编辑失败"),
"err": err,
})
}
}
}
func DeleteUser(c *gin.Context) {
id := tool.StringToInt(c.Param("id"))
if id <= 0 {
c.JSONP(200, gin.H{
"error_code": 40001,
"msg": tool.GetMsg(40001, "ID不存在"),
})
} else {
if models.ExistTagByID(id) {
maps := make(map[string]interface{})
maps["id"] = id
res, err := models.DeleteUser(maps)
if res {
c.JSONP(200, gin.H{
"error_code": 0,
"msg": tool.GetMsg(40001, "删除成功"),
"err": err,
})
} else {
c.JSONP(200, gin.H{
"error_code": 40001,
"msg": tool.GetMsg(40001, "删除失败"),
"err": err,
})
}
} else {
c.JSONP(200, gin.H{
"error_code": 40001,
"msg": tool.GetMsg(40001, "信息不存在"),
})
}
}
}
主main.go
package main
import (
"go-api/routes"
)
func main() {
//启动服务器
routes.Run()
}
启动并验证
本章节我们主要处理常规API与model层的交互以及统一返回,统一错误格式
下一章节在控制器层使用gin默认的数据校验、抽离服务层、加jwt中间件对api服务权限校验