英文:
How to design RestAPI for too many tables in Golang
问题
我认为如果我继续使用下面的方法,我将不得不写太多的代码。
我为所有的表声明了结构体,并且我使用了Go的验证包进行验证。
[types.go]
type TableA struct {
Field1 string `json:"field1" validate:"required,max=10"`
Field2 int `json:"field2" validate:"number"`
}
type TableB struct {
...
}
我为每个方法初始化了路由器并连接了处理程序。
[tableA.go]
router.Get("/table-a", r.Get_tableA_Handler)
router.Post("/table-a", r.Post_tableA_Handler)
router.Patch("/table-a", r.Patch_tableA_Handler)
router.Delete("/table-a", r.Delete_tableA_Handler)
...
每个处理程序解析请求体中的JSON,验证数据并调用数据库函数。
[tableA_router.go]
func (rt *tableARouter) Post_tableA_Handler(w http.ResponseWriter, r *http.Request) error {
// 将JSON解析为结构体
req := new(types.TableA)
if err := httputils.DecodeJsonBody(r, req); err != nil {
return err
}
// 验证数据
if err := validCheck(req); err != nil {
return err
}
// 调用数据库函数
err := rt.insert_tableA_DB(r.Context(), req)
if err != nil {
return err
}
return rt.rd.JSON(w, http.StatusCreated, "创建成功")
}
...
func validCheck(data interface{}) error {
validate := validator.New()
err := validate.Struct(data)
return err
}
这是从上面的处理程序函数中调用的数据库函数(使用Gorm)
[tableA_db.go]
func (rt *tableARouter) insert_tableA_DB(ctx context.Context, data *types.TableA) error {
// 连接数据库
db, err := db.Open(rt.dbcfg)
if err != nil {
return err
}
defer db.Close()
tx := db.Begin()
defer tx.Rollback()
// == 插入数据 ==
query := `INSERT INTO table_a
(field1, field2, ...)
VALUES (?, ?, ...)`
result := tx.WithContext(ctx).Exec(query,
data.Field1, data.Field2, ...)
// 处理结果
if result.Error != nil {
...
}
现在有太多的表了... 如果有100个表,我就必须写100个处理程序和100个数据库函数。
有没有办法使用类似于/tables/{tableName}
的方式?
请给我一些建议... 谢谢。
英文:
I think if i keep using the method below, i'll have to write too much code.
I declared structures for all the tables. and i used the go validate package for validation.
[types.go]
type TableA struct {
Field1 string `json:"field1" validate:"required, max=10"`
Field2 int `json:"field2" validate:"number"`
}
type TableB struct {
...
}
2.
And i initialized the router for each method and connected the handlers.
[tableA.go]
router.Get("/table-a", r.Get_tableA_Handler),
router.Post("/table-a", r.Post_tableA_Handler),
router.Patch("/table-a", r.Patch_tableA_Handler),
router.Delete("/table-a", r.Delete_tableA_Handler)
...
3.
Each handler parses the json in the request body, validates the data and call the db function.
[tableA_router.go]
func (rt *tableARouter) Post_tableA_Handler(w http.ResponseWriter, r *http.Request) error {
//Json to Struct
req := new(types.tableA)
if err := httputils.DecodeJsonBody(r, req); err != nil {
return err
}
// Validation
if err := validCheck(req); err != nil {
return err
}
// DB function
err := rt.insert_tableA_DB(r.Context(), req)
if err != nil {
return err
}
return rt.rd.JSON(w, http.StatusCreated, "Create Success")
}
...
func validCheck(data interface{}) error {
validate := validator.New()
err := validate.Struct(data)
return err
}
4.
This is a DB function called from the handler function above (using Gorm)
[tableA_db.go]
func (rt *tableARouter) insert_tableA_DB(ctx context.Context, data *types.TableA) error {
// DB Connect
db, err := db.Open(rt.dbcfg)
if err != nil {
return err
}
defer db.Close()
tx := db.Begin()
defer tx.Rollback()
// == INSERT ==
query := `INSERT INTO table_a
(field1, field2, ...)
VALUES (?, ?, ...)`
result := tx.WithContext(ctx).Exec(query,
data.Field1, data.Field2, ...)
//Result
if result.Error != nil {
...
}
There are too many tables now... If there are 100 tables i have to write 100 handlers and 100 DB functions.
Is there any way to use something like /tables/{tableName}
?
Please give me any advice.... Thank you.
答案1
得分: 1
你可以使用ORM包,比如GORM,来简化你的工作。
或者你可以创建一个通用的处理程序,并使用反射包来分析你定义的结构体,并动态生成每个SQL查询。但是,如果你的结构体中有内部切片、其他嵌入的结构体,或者如果你需要使用连接表,你还需要手动处理。我有一些服务器,上面有200多个端点,每个端点有3-400个方法,有200多个SQL表,整个服务器都是手写的。但是我可以说,很少有情况下一个处理程序和DB函数可以在不修改的情况下重用。
也许你可以将错误处理、回滚/提交、JSON解析和响应部分封装在一个函数中,然后使用它来调用DB方法。
英文:
You can use an ORM package, like GORM to make easier your work.
Or you can make an universal handler and with the reflect package, analyze your defined structs and make every SQL query dinamically. But it's not the best solution if any of your struct has inner slices, other embedded structs, or if you need to use joined tables you also have to deal with it manually. I have servers where we have more than 200 endpoints with more than 3-400 methods with 200+ SQL tables and the whole server was written by hand. But I can say, it's very rare when a handler and the DB func can be reused without modifying.
Maybe you can wrap the error handling, rollback/commit, json parse and response parts in a func then use it to call the DB methods.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论