2024年您产品必备的10大AI API推荐
结合gin+gorm+go-Redis写一个基础 API
上篇
初始化
新建目录,初始化项目,运行:
code
go mod init sai0556/gin-frame
// 使用本地module
go mod edit -require=local.com/sai0556/gin-frame@v1.0.0
go mod edit -replace=local.com/sai0556/gin-frame@v1.0.0=$PWD
编码
配置部分
新建config目录,初始化并监听文件:
package config
import (
"fmt"
"github.com/fsnotify/fsnotify"
"github.com/spf13/viper"
)
type Config struct {
Name string
}
// 初始化配置
func Init(cfg string) error {
c := Config{
Name: cfg,
}
if err := c.initConfig(); err != nil {
return err
}
c.watchConfig()
return nil
}
func (c *Config) initConfig() error {
if c.Name != "" {
viper.SetConfigFile(c.Name)
} else {
// 默认配置文件是conf/config.yaml
viper.AddConfigPath("conf")
viper.SetConfigName("config")
}
viper.SetConfigType("yaml")
// viper解析配置文件
err := viper.ReadInConfig()
if err != nil {
panic(fmt.Errorf("Fatal error config file: %s \n", err))
}
fmt.Println(viper.GetString("name"))
return nil
}
func (c *Config) watchConfig() {
viper.WatchConfig()
viper.OnConfigChange(func(e fsnotify.Event) {
fmt.Println("Config file changed:", e.Name)
})
}
conf/config.yaml,语法可自行研究下,比较简单。
YAML入门
code
name: gin-frame
db:
name: blog
host: 127.0.0.1:3306
username: root
password: 111111
charset: utf8mb4
数据库gorm
连接数据库,构建连接池:
go
package model
import (
"fmt"
"sync"
"errors"
orm "github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
"github.com/spf13/viper"
)
type MySqlPool struct {}
var instance *MySqlPool
var once sync.Once
var db *orm.DB
var err error
// 单例模式
func GetInstance() *MySqlPool {
once.Do(func() {
instance = &MySqlPool{}
})
return instance
}
func (pool *MySqlPool) InitPool() (isSuc bool) {
dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=%s", viper.GetString("db.username"), viper.GetString("db.password"), viper.GetString("db.host"), viper.GetString("db.name"), viper.GetString("db.charset"))
db, err = orm.Open("mysql", dsn)
if err != nil {
panic(errors.New("mysql连接失败"))
return false
}
// 连接数配置也可以写入配置,在此读取
db.DB().SetMaxIdleConns(50)
db.DB().SetMaxOpenConns(50)
// db.LogMode(true)
return true
}
main.go
我们完善一下main.go,初始化配置,并构建连接池:
go
package main
// import 这里我习惯把官方库,开源库,本地module依次列出
import (
"log"
"os"
"errors"
"github.com/spf13/pflag"
"local.com/sai0556/gin-frame/config"
"local.com/sai0556/gin-frame/model"
)
var (
conf = pflag.StringP("config", "c", "", "config filepath")
)
func main() {
pflag.Parse()
// 初始化配置
if err := config.Init(*conf); err != nil {
panic(err)
}
// 连接mysql数据库
isSuc := model.GetInstance().InitPool()
if !isSuc {
log.Println("init database pool failure...")
panic(errors.New("init database pool failure"))
}
}
写完不妨运行一下,看看效果吧!
code
go run main.go -c=./conf/config.yaml
中篇
在上篇里,我介绍了读取配置,并尝试连接了数据库,那么这一篇呢,我们主要利用gin框架来写写简单的接口。
路由
为了便于管理,还是将路由文件单独出来,新建routes:
go
package router
import (
"net/http"
"github.com/gin-gonic/gin"
"local.com/sai0556/gin-frame/controller"
)
func Load(g *gin.Engine) *gin.Engine {
g.Use(gin.Recovery())
// 404
g.NoRoute(func (c *gin.Context) {
c.String(http.StatusNotFound, "404 not found");
})
g.GET("/", controller.Index)
return g
}
控制器
上面的代码中我们看到了controller,我们建一个目录controller:
先建base.go文件,用于写一些基础的方法,如SendResponse返回json。
go
package controller
import (
"net/http"
"github.com/gin-gonic/gin"
)
type Response struct {
Code int `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data"`
}
func SendResponse(c *gin.Context, code int, message string, data interface{}) {
c.JSON(http.StatusOK, Response{
Code: code,
Message: message,
Data: data,
})
}
再来写个index.go,处理逻辑。
go
package controller
import (
"github.com/gin-gonic/gin"
)
func Index(c *gin.Context) {
SendResponse(c, 0, "success", nil)
}
启动gin
go
// main.go
// 在连接数据库后加入以下代码
gin.SetMode("debug")
g := gin.New()
g = router.Load(g)
g.Run(":8080")
不妨启动看看效果。
go run main.go -c=./conf/config.yaml
当然,这里的服务启动、停止可以写得再优雅一些。
下篇
前两篇我们已经完成了gin+gorm部分,今天我们来补充go-Redis,并进行测试。
整合go-Redis
我们把Redis相关也放在model下面,使用的是常见的go-redis:
go
// redis.go
package model
import (
"fmt"
"github.com/spf13/viper"
"github.com/go-redis/redis"
)
var RedisClient *redis.Client
func RedisInit() {
RedisClient = redis.NewClient(&redis.Options{
Addr: fmt.Sprintf("%s:%s", viper.GetString("redis.host"), viper.GetString("redis.port")),
Password: viper.GetString("redis.auth"),
DB: 0,
})
_, err := RedisClient.Ping().Result()
if err != nil {
panic("redis ping error")
}
}
然后在连接Mysql的前面加入初始化redis连接的操作即可。
go
// redis 初始化
model.RedisInit()
你可以做一些简单操作,或者在redis.go做一些常用方法的封装,比较简单,就不赘述了,更多go-redis操作可见:
- go-redis
- github太慢就看这个
测试
新建测试目录test,建立三个文件:
// index.go
package test
import (
"net/http"
"io/ioutil"
)
func Sum(a int, b int) int {
return a+b
}
func HttpIndex() []byte {
resp, err := http.Get("http://127.0.0.1:8080/")
if err != nil && resp.StatusCode != 200 {
panic(err)
}
//关闭连接
defer resp.Body.Close()
//读取报文中所有内容
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
//输出内容
return body
// index_test.go
package test
import (
"testing"
"encoding/json"
"local.com/sai0556/gin-frame/controller"
)
func TestSum(t *testing.T) {
ret := Sum(2, 7)
if ret != 9 {
t.Error("Expected 9 ~wow~")
}
}
func TestHttpIndex(t *testing.T) {
data := HttpIndex()
target := controller.Response{}
// json转换
if err := json.Unmarshal(data, &target); err != nil {
t.Error(target)
}
ret := controller.Response{0, "success", nil}
if target != ret {
t.Error("json error")
}
}
// index_bench_test.go
package test
import (
"testing"
)
func BenchmarkSum(b *testing.B) {
for i := 0; i < b.N; i++ {
Sum(2, 7)
}
}
func BenchmarkHttpIndex(b *testing.B) {
for i := 0; i < b.N; i++ {
HttpIndex()
}
}
私以为go的测试相比其他语言还是比较简洁的,这里需要注意几点:
- 测试文件以_test结尾
- 基础测试方法名要以TEST开头
运行起来,看一下:
对图中做一些说明:
code
// -run="none"不执行基础单元测试,bench指定基准测试方法
go test -v -run="none" -bench="Bench*"
// 最后一个BenchmarkHttpIndex-4后面测试结果表示
一共执行了11010次,每次执行耗时107392ns(~0.107ms)
test标准库
结后语
文章很基础,主要是介绍了结合了gin+gorm+go-redis,并写了简单的测试,是相对基础的文章,但足以应付一些api接口了。希望对你有帮助,有问题可留言或私信。
点击查看项目DEMO
文章转自微信公众号@SaiWeng