As you can see, with the project scaffold tool, a lot of code unrelated to the project’s business logic has already been pre-generated, so we only need to focus on the business logic implementation. Let’s take a look at how to implement the specific CURD logic.

Create

Implementation of Creation Logic

internal/controller/user/user_v1_create.go

  1. package user
  2. import (
  3. "context"
  4. "demo/api/user/v1"
  5. "demo/internal/dao"
  6. "demo/internal/model/do"
  7. )
  8. func (c *ControllerV1) Create(ctx context.Context, req *v1.CreateReq) (res *v1.CreateRes, err error) {
  9. insertId, err := dao.User.Ctx(ctx).Data(do.User{
  10. Name: req.Name,
  11. Status: v1.StatusOK,
  12. Age: req.Age,
  13. }).InsertAndGetId()
  14. if err != nil {
  15. return nil, err
  16. }
  17. res = &v1.CreateRes{
  18. Id: insertId,
  19. }
  20. return
  21. }

In the Create implementation method:

  • We use dao.User through the dao component to operate the user table.
  • Each dao operation requires passing the ctx parameter, so we create a gdb.Model object with the Ctx(ctx) method. This object is the framework’s model object used to operate specific data tables.
  • We use Data to pass the data that needs to be written to the data table. Here, we use the do conversion model object to input our data. The do conversion model automatically filters nil data and converts it to the corresponding data table field type at a lower level. In most cases, we use the do conversion model to pass write/update parameters, query conditions, and other data to the database operation object.
  • The InsertAndGetId method writes the Data parameters into the database and returns the newly created record’s primary key id.

Parameter Validation Implementation

Hold on, you might wonder why there is no validation logic here. This is because the validation logic is already configured on the request parameter object CreateReq. Remember the v tag introduced earlier? Let’s take another look at this request parameter object:

api/user/v1/user.go

  1. type CreateReq struct {
  2. g.Meta `path:"/user" method:"put" tags:"User" summary:"Create user"`
  3. Name string `v:"required|length:3,10" dc:"user name"`
  4. Age uint `v:"required|between:18,200" dc:"user age"`
  5. }
  6. type CreateRes struct {
  7. Id int64 `json:"id" dc:"user id"`
  8. }

The required/length/between validation rules here are automatically executed by the GoFrame framework’s Server before calling the route function Create. If the request parameter validation fails, an error will be returned immediately, and the route function will not be executed. This mechanism of the GoFrame framework greatly simplifies the development process, developers only need to focus on the business logic implementation in this route function.

Step5 - Implement API Logic - 图1info

Of course, if there are some additional, customized business logic validations, they need to be implemented in the route function by yourself.

Delete

internal/controller/user/user_v1_delete.go

  1. package user
  2. import (
  3. "context"
  4. "demo/api/user/v1"
  5. "demo/internal/dao"
  6. )
  7. func (c *ControllerV1) Delete(ctx context.Context, req *v1.DeleteReq) (res *v1.DeleteRes, err error) {
  8. _, err = dao.User.Ctx(ctx).WherePri(req.Id).Delete()
  9. return
  10. }

The deletion logic is relatively straightforward. Here, we use a WherePri method, which takes the given parameter req.Id as the primary key for Where condition restriction.

Update

internal/controller/user/user_v1_update.go

  1. package user
  2. import (
  3. "context"
  4. "demo/api/user/v1"
  5. "demo/internal/dao"
  6. "demo/internal/model/do"
  7. )
  8. func (c *ControllerV1) Update(ctx context.Context, req *v1.UpdateReq) (res *v1.UpdateRes, err error) {
  9. _, err = dao.User.Ctx(ctx).Data(do.User{
  10. Name: req.Name,
  11. Status: req.Status,
  12. Age: req.Age,
  13. }).WherePri(req.Id).Update()
  14. return
  15. }

The update API is also straightforward. Besides the already introduced WherePri method, it also requires using the Data method to pass the data to be updated when updating the data.

GetOne

internal/controller/user/user_v1_get_one.go

  1. package user
  2. import (
  3. "context"
  4. "demo/api/user/v1"
  5. "demo/internal/dao"
  6. )
  7. func (c *ControllerV1) GetOne(ctx context.Context, req *v1.GetOneReq) (res *v1.GetOneRes, err error) {
  8. res = &v1.GetOneRes{}
  9. err = dao.User.Ctx(ctx).WherePri(req.Id).Scan(&res.User)
  10. return
  11. }

In the data retrieval API, we use a Scan method, which can intelligently map the retrieved single data table record to a structure object. It should be noted that the User attribute object in &res.User is actually not initialized and its value is nil. If data is retrieved, the Scan method will initialize and assign it. If no data is retrieved, the Scan method will do nothing, and its value will remain nil.

GetList

internal/controller/user/user_v1_get_list.go

  1. package user
  2. import (
  3. "context"
  4. "demo/api/user/v1"
  5. "demo/internal/dao"
  6. "demo/internal/model/do"
  7. )
  8. func (c *ControllerV1) GetList(ctx context.Context, req *v1.GetListReq) (res *v1.GetListRes, err error) {
  9. res = &v1.GetListRes{}
  10. err = dao.User.Ctx(ctx).Where(do.User{
  11. Age: req.Age,
  12. Status: req.Status,
  13. }).Scan(&res.List)
  14. return
  15. }

When retrieving list data, we also use the Scan method, which is very powerful. Like retrieving single data’s logic, it only initializes &res.List when data is retrieved.

Learning Summary

Example source code for this chapter: https://github.com/gogf/quick-demo/tree/main/internal/controller/user

As you can see, using the GoFrame database ORM component can very quickly and efficiently complete API development work. Throughout the CURD API development, the business logic that developers need to implement requires only a few lines of code😼.

The improvement in development efficiency is not only due to the scaffold tool automatically generating the dao and controller code but also thanks to the powerful database ORM component. As you can see, when we operate the database table, the code is very concise and elegant, but the internal design of the database ORM component involves a lot of fine design, strict code testing, and the result of years of functional iteration.

With the API logic development completed, in the next step, we need to perform some database configuration and route registration operations, which is also very simple. Let’s take a look together.