Swagger在每次db调用时初始化db(gorm)连接



我用Swagger创建了一个API,它通过gorm与Mariadb实例通信。我不满意我如何处理db连接模块,并传递db处理程序。我怎样才能使这个更健壮,也许合并接口,并且每次发出db请求时总是调用db.Open函数。

这是我的配置文件创建由Swagger

func configureAPI(api *operations.HairdooAPI) http.Handler {
// configure the api here
api.ServeError = errors.ServeError
// Set your custom logger if needed. Default one is log.Printf
// Expected interface func(string, ...interface{})
//
// Example:
//api.Logger = log.Printf
api.UseSwaggerUI()
// To continue using redoc as your UI, uncomment the following line
// api.UseRedoc()
api.JSONConsumer = runtime.JSONConsumer()
//api.UrlformConsumer = runtime.DiscardConsumer
api.JSONProducer = runtime.JSONProducer()
api.CompanyAddCompanyHandler = company.AddCompanyHandlerFunc(func(params company.AddCompanyParams) middleware.Responder {
//log.Debugf("Add commpay Handler Called")
//log.Infof("Payload Data : %v", params.Body)
response, err := handlers.AddCompany(params)
if err != nil {
return company.NewAddCompanyBadRequest().WithPayload(&models.ErrorReponse400{
Error: err.Error(),
})
}
return company.NewAddCompanyCreated().WithPayload(response)
})

这是我的AddCompany函数的实现。

package handlers
import (
"hairdoo.com/m/v2/db"
"hairdoo.com/m/v2/models"
"hairdoo.com/m/v2/restapi/operations/company"
)
func AddCompany(params company.AddCompanyParams) (*models.Company, error) {
result, err := db.AddCompany(params.Body)
if err != nil {
return nil, err
}
return result, nil
}

最后是db包实现

package db
import (
"fmt"
"time"
"gorm.io/gorm"
"hairdoo.com/m/v2/models"
)
type Company struct {
gorm.Model
Name           string `gorm:"uniqueIndex"`
Phone          string
Email          string
ContatctPerson string
CategoryID     int
Category       *Category
Status         string
}
type Category struct {
ID   int
Name string `gorm:"uniqueIndex"`
}
func AddCompany(companyObj *models.Company) (*models.Company, error) {
db := Open()
var result *gorm.DB
category := &Category{}
db.Where("name = ?", companyObj.Category.Name).First(category)
company := convertToDBCompany(companyObj, false)
if category.ID != 0 {
result = db.Exec("INSERT INTO companies (created_at, updated_at, name, phone, email, contatct_person, category_id) values (?, ?, ?, ?, ?, ?, ?);",
time.Now(), time.Now(), companyObj.Name, companyObj.Phone, companyObj.Email, companyObj.ContatctPerson, category.ID)
} else {
result = db.Create(company)
}
if result.RowsAffected < 1 {
return nil, result.Error
}
// add employee to db if object present
var employees []*models.EmployeeItems0
if companyObj.Employee != nil {
for _, employeeInput := range companyObj.Employee {
result, err := AddEmployee(employeeInput)
if err != nil {
return nil, err
}
employees = append(employees, result)
}
}
return convertToModelCompany(company, employees), nil
}

这样做的一种方法是创建一个结构体,该结构体存储db连接并将方法放在该结构体上,例如:

type dbService struct {
*gorm.DB
}
func InitDB() *dbService {
db, err := gorm.Open(...)
if err != nil {
panic("failed to connect database")
}
db.AutoMigrate(&Category{}, &Company{})
return &dbService{db}
}
func (db *dbService) AddCompany(companyObj *models.Company) (*models.Company, error) {
company := convertToDBCompany(companyObj, false)
db.FirstOrInit(company.Category, &Category{Name: companyObj.Category.Name})
result := db.Create(&company)
if result.RowsAffected < 1 {
return nil, result.Error
}

...
}

,如果你已经在使用gorm,我建议你充分利用它的ORM功能;)

您当然不希望每个请求都连接到db,因为Gorm(和底层db库)实现了连接池,以便在多个请求之间透明地重用连接,并且每次重新连接都完全取消了所有辛苦的工作。

总的来说,你需要首先初始化你的应用程序,让它准备好尽快回答请求。

全局使用静态init

一个选项是在包级别静态地进行配置和初始化:

db/db.go

package db
import (
"os"
"gorm.io/gorm"
"gorm.io/driver/sqlite"
)
var DB *gorm.DB
func init() {
DB, err = gorm.Open(sqlite.Open(os.Getenv("SQLITE_DB")), &gorm.Config{})
// error handling
}

init自动运行,此后任何其他包都可以访问db.DB作为全局对象来运行查询。

全局协调init

对数据库初始化的时间有更多的控制通常更好,因为它可能依赖于必须初始化的值(例如,必须读取配置文件)。在这种情况下,您将把init重命名为Init(或其他任何东西),然后从main或其他设置函数调用该函数,该函数协调应用程序初始化。在go-swagger中使用标准模板,可以在configureAPI函数中完成。

func configureAPI(api *operations.HairdooAPI) http.Handler {
// ...
db.Init(...)

// ... setup handlers
}

之后,您应该能够从其他db函数(如AddCompany)访问打开并准备好的db.DB全局。

依赖注入样式

以上应该足以回答你的问题;随着你的应用变得越来越大,你可能会考虑一种不同的架构风格,在这种风格中,你不依赖于全局变量,这会使你的代码难以测试。这有点像joelazar所建议的,每个处理程序或服务都是一个具有*gorm.DB字段的结构体,该字段在init进程中设置。说明:

package handlers
import "gorm.io/gorm"
type Company struct {
DB *gorm.DB
}
func (h *Company) AddCompany(models.Company, ...) ... {
h.DB.Foo()
}
func configureAPI(api *operations.HairdooAPI) http.Handler {
dbHandler := db.Init(...)
companyHandler := handlers.Company{DB: dbHandler}
...
api.CompanyAddCompanyHandler = company.AddCompanyHandlerFunc(func(params company.AddCompanyParams) middleware.Responder {
response, err := companyHandler.AddCompany(params)
...
}
}

关于这种设置还有很多要说的。使用go-swagger,我发现平流层模板对于生成耦合更少、更可测试的架构很有用。从长远考虑。

相关内容

  • 没有找到相关文章

最新更新