在Go中重复使用或强制转换结构以进行验证,API结果和数据库保存

I'm trying to write an API that will do different things with the data depending on its purpose.

  • API results - The API should expose certain fields to the user
  • Validation - Validation should handle different schemas e.g. login form doesn't require Name, but register does
  • Database - The database should save everything, including password etc. - if I try using the same struct for the API and DB with json:"-" or un-exporting the field the database save also ignores the field

Some sample code is below with a couple of comments in capitals to show where I ideally need to type cast to change the data. As they are different structs, they cannot be type cast, so I get an error. How can I fix this?

Alternatively, what is a better way of doing different things with the data without having lots of similar structs?

// IDValidation for uuids
type IDValidation struct {
    ID string `json:"id" validate:"required,uuid"`
}


// RegisterValidation for register form
type RegisterValidation struct {
    Name     string `json:"name" validate:"required"`
    Email    string `json:"email" validate:"required,email"`
    Password string `json:"password" validate:"required,min=8"`
}

// UserModel to save in DB
type UserModel struct {
    ID        string `json:"id,omitempty"`
    Name      string `json:"name"`
    Email     string `json:"email"`
    Password  string `json:"password,omitempty"`
    Active    bool   `json:"active,omitempty"`
    CreatedAt int64  `json:"created_at,omitempty"`
    UpdatedAt int64  `json:"updated_at,omitempty"`
    jwt.StandardClaims
}

// UserAPI data to display to user
type UserAPI struct {
    ID        string `json:"id,omitempty"`
    Name      string `json:"name"`
    Email     string `json:"email"`
    Active    bool   `json:"active,omitempty"`
}

// register a user
func register(c echo.Context) error {
    u := new(UserModel)
    if err := c.Bind(u); err != nil {
        return err
    }
    // NEED TO CAST TO RegisterValidation HERE?
    if err := c.Validate(u); err != nil {
        return err
    }
    token, err := u.Register()
    if err != nil {
        return err
    }
    return c.JSON(http.StatusOK, lib.JSON{"token": token})
}

// retrieve a user
func retrieve(c echo.Context) error {
    u := IDValidation{
        ID: c.Param("id"),
    }
    if err := c.Validate(u); err != nil {
        return echo.NewHTTPError(http.StatusBadRequest, err.Error())
    }
    // NEED TO CAST USER TO UserAPI?
    user, err := userModel.GetByID(u.ID)
    if err != nil {
        return err
    }
    return c.JSON(200, lib.JSON{"message": "User found", "user": user})
}