如何在Golang中为太多的表设计RestAPI

huangapple go评论67阅读模式
英文:

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.

huangapple
  • 本文由 发表于 2022年6月15日 13:19:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/72626239.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定