Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Go struct separation best practices

Tags:

go

I am trying to figure out a decent approach toward dealing with multiple uses for a struct. Let me explain the scenario.

I have a struct that represents the Model in gorm. In the current implementation, I have validation bound to this struct so when a request hits the endpoint I would validate against the model's struct. This works fine for most cases. But then there are some instances where I want to have more control over the request and the response.

This is possible by introducing a few additional internal structs that will parse the request and response. And I can decouple the validation from the model into the request specific struct. I am trying to figure out what the best practice is around these patterns. Pretty sure a lot of peeps would have faced a similar situation.

// Transaction holds the transaction details.
type Transaction struct {
    Program    Program
    ProgramID  uuid.UUID
    Type       string
    Value      float64
    Reference  string
}

// TransactionRequest for the endpoint.
type TransactionRequest struct {
    ProgramKey string    `json:"program_key" validator:"required"`
    Type       string    `json:"type" validator:"required,oneof=credit debit"`
    Value      float64   `json:"value" validator:"required,numeric"`
    Reference  string    `json:"reference" validator:"required"`
}

Update:

I managed to find a balance by introducing additional tags for update requests, I wrote about how I achieved it here

like image 838
Gayan Hewa Avatar asked Apr 11 '20 13:04

Gayan Hewa


Video Answer


1 Answers

I faced similar problem and for solving that, defined a method for validating and didn't use tags. I had to, because I follow DDD and we should validate in service layer not API layer.

here is a sample of my apporach:

type Station struct {
    types.GormCol
    CompanyID   types.RowID            `gorm:"not null;unique" json:"company_id,omitempty"`
    CompanyName string                 `gorm:"not null;unique" json:"company_name,omitempty"`
    NodeCode    uint64                 `json:"node_code,omitempty"`
    NodeName    string                 `json:"node_name,omitempty"`
    Key         string                 `gorm:"type:text" json:"key,omitempty"`
    MachineID   string                 `json:"machine_id,omitempty"`
    Detail      string                 `json:"detail,omitempty"`
    Error       error                  `sql:"-" json:"user_error,omitempty"`
    Extra       map[string]interface{} `sql:"-" json:"extra_station,omitempty"`
}

// Validate check the type of
func (p *Station) Validate(act action.Action) error {
    fieldError := core.NewFieldError(term.Error_in_companys_form)

    switch act {
    case action.Save:
        if p.CompanyName == "" {
            fieldError.Add(term.V_is_required, "Company Name", "company_name")
        }

        if p.CompanyID == 0 {
            fieldError.Add(term.V_is_required, "Company ID", "company_id")
        }

    }

    if fieldError.HasError() {
        return fieldError
    }
    return nil
}

file's address: https://github.com/syronz/sigma-mono/blob/master/model/station.model.go

like image 163
Diako Amir Avatar answered Nov 15 '22 05:11

Diako Amir