- 快速构建
RESTful API
- 基于
JWT
的用户授权 - 基于
Viper
的配置 - 基于
Redis
缓存器 ent
模型分页器- API 资源转换器
- 多语言翻译支持
- Swagger UI (渲染 YAML 文件)
克隆仓库
git clone https://github.com/fitv/min.git
复制配置文件
cd min && cp config.example.yaml config.yaml
运行应用
go run main.go
构建应用
go build -o min main.go
API 文档地址
http://127.0.0.1:3000/apidoc
运行数据库迁移
http://127.0.0.1:3000/api/v1/migrate
import "github.com/fitv/min/global"
global.Cache().Set(ctx, "key", "value", time.Minute)
global.Cache().Get(ctx, "key") // value
global.Cache().Has(ctx, "key") // true
global.Cache().TTL(ctx, "key") // time.Minute
global.Cache().Del(ctx, "key") // true
import "github.com/fitv/min/global"
global.Log().Debug("debug")
global.Log().Info("info")
global.Log().Warn("warn")
global.Log().Error("error")
global.Log().Panic("panic")
global.Log().Fatal("fatal")
import "github.com/fitv/min/global"
global.Lang().Trans("hello.world") // 世界
global.Lang().Locale("en").Trans("hello.world") // world
package user
import (
"context"
"strconv"
"github.com/fitv/min/app/resource"
"github.com/fitv/min/core/response"
"github.com/fitv/min/global"
"github.com/gin-gonic/gin"
)
type User struct{}
// Index returns a list of users with pagination
func (User) Index(c *gin.Context) {
paginator, err := global.Ent().User.
Query().
Paginate(ctx, c)
if err != nil {
response.HandleEntError(c, err)
return
}
resource.NewUserPaginator(c, paginator).Response()
}
// Info returns user information
func (User) Info(c *gin.Context) {
id, _ := strconv.Atoi(c.Param("id"))
user, err := global.Ent().User.Get(ctx, id)
if err != nil {
response.HandleEntError(c, err)
return
}
resource.NewUser(c, user).Append(gin.H{
"role": "staff",
}).Wrap("user").Response()
}
用户列表响应
{
"current_page": 1,
"per_page": 15,
"last_page": 1,
"total": 2,
"data": [
{
"id": 1,
"username": "u1"
},
{
"id": 2,
"username": "u2"
}
]
}
用户信息响应
{
"user": {
"id":1,
"name":"u1"
},
"meta": {
"role": "staff"
}
}
type Auth struct{}
type UserFormLogin struct {
Username string `json:"username" binding:"required"`
Password string `json:"password" binding:"required"`
}
func (Auth) Login(c *gin.Context) {
var form UserFormLogin
err := c.ShouldBind(&form)
if err != nil {
response.HandleValidatorError(c, err)
return
}
// do login...
}
验证失败响应,返回状态码422
{
"message": "姓名为必填字段",
"errors": {
"password": "密码为必填字段",
"username": "姓名为必填字段"
}
}
package user
import (
"context"
"github.com/fitv/min/ent"
"github.com/fitv/min/ent/user"
"github.com/fitv/min/global"
)
type User struct{}
func (User) Update() {
global.DB().WithTx(ctx, func(tx *ent.Tx) error {
user, err := tx.User.Query().Where(user.ID(1)).ForUpdate().First(ctx)
if err != nil {
return err
}
// do update...
})
}