Skip to content

Latest commit

 

History

History
217 lines (184 loc) · 3.86 KB

README.md

File metadata and controls

217 lines (184 loc) · 3.86 KB

MIN - an API skeleton based on Gin

简体中文

Packages used

Features

  • Easily build your RESTful APIs
  • JWT Authorization
  • Configuration
  • Cache based on Redis
  • ent Paginator
  • API Resource Transformer
  • Multi-language translation support
  • Swagger UI (render YAML file)

Installation

Clone repository

git clone https://github.com/fitv/min.git

Copy the configuration file

cd min && cp config.example.yaml config.yaml

Run Application

go run main.go

Build Application

go build -o min main.go

Open the API document URL in your browser

http://127.0.0.1:3000/apidoc

Run database migration

http://127.0.0.1:3000/api/v1/migrate

Usage

Cache

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

Logger

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

Multi-language translation

import "github.com/fitv/min/global"

global.Lang().Trans("hello.world") // world
global.Lang().Locale("zh").Trans("hello.world") // 世界

Paginator & API Resource Transformer

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()
}

User Index response

{
  "current_page": 1,
  "per_page": 15,
  "last_page": 1,
  "total": 2,
  "data": [
    {
      "id": 1,
      "username": "u1"
    },
    {
      "id": 2,
      "username": "u2"
    }
  ]
}

User Info response

{
  "user": {
    "id":1,
    "name":"u1"
  },
  "meta": {
    "role": "staff"
  }
}

From Validator

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...
}

Verification failure response, return status code 422

{
  "message": "username is a required field",
  "errors": {
    "password": "password is a required field",
    "username": "username is a required field"
  }
}

Database Transaction

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...
  })
}