From 0879aec75085ccc9aae0593117210ea8b1b6bd75 Mon Sep 17 00:00:00 2001 From: Hazem Krimi Date: Tue, 3 Jun 2025 20:23:06 +0100 Subject: [PATCH] chore: add request validations --- go.mod | 5 +++++ go.sum | 10 ++++++++++ internal/api/api.go | 2 ++ internal/api/client.go | 12 ++++++++++-- internal/api/validator.go | 19 +++++++++++++++++++ internal/models/client.go | 34 +++++++++++++++++++++------------- 6 files changed, 67 insertions(+), 15 deletions(-) create mode 100644 internal/api/validator.go diff --git a/go.mod b/go.mod index 15aa01e..ba8c85c 100644 --- a/go.mod +++ b/go.mod @@ -10,10 +10,15 @@ require ( ) require ( + github.com/gabriel-vasile/mimetype v1.4.8 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.26.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/labstack/gommon v0.4.2 // indirect + github.com/leodido/go-urn v1.4.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-sqlite3 v1.14.22 // indirect diff --git a/go.sum b/go.sum index 143a250..59f1f29 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,14 @@ github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= +github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k= +github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= @@ -11,6 +19,8 @@ github.com/labstack/echo/v4 v4.13.4 h1:oTZZW+T3s9gAu5L8vmzihV7/lkXGZuITzTQkTEhcX github.com/labstack/echo/v4 v4.13.4/go.mod h1:g63b33BZ5vZzcIUF8AtRH40DrTlXnx4UMC8rBdndmjQ= github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= diff --git a/internal/api/api.go b/internal/api/api.go index 14b6e77..7c3c248 100644 --- a/internal/api/api.go +++ b/internal/api/api.go @@ -1,6 +1,7 @@ package api import ( + "github.com/go-playground/validator/v10" "github.com/hazemKrimi/crimson-vault/internal/models" "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" @@ -14,6 +15,7 @@ type API struct { func (api *API) Initialize() { db := &models.DB{} ech := echo.New() + ech.Validator = &CustomValidator{validator: validator.New(validator.WithRequiredStructEnabled())} db.Connect() db.MigrateClients() diff --git a/internal/api/client.go b/internal/api/client.go index e257d32..dd4a9bb 100644 --- a/internal/api/client.go +++ b/internal/api/client.go @@ -11,13 +11,17 @@ import ( ) func (api *API) CreateClientHandler(context echo.Context) error { - var body models.CreateClientBody + var body models.CreateClientRequestBody if err := context.Bind(&body); err != nil { log.Println(fmt.Sprintf("Error creating Client: %v.", err)) return context.String(http.StatusBadRequest, "Invalid JSON!") } + if err := context.Validate(body); err != nil { + return err + } + client := api.db.CreateClient(body) log.Println(fmt.Sprintf("Client created with ID %d.", client.ID)) @@ -71,13 +75,17 @@ func (api *API) UpdateClientHandler(context echo.Context) error { return context.String(http.StatusInternalServerError, "Unexpected error updating Client!") } - var body models.UpdateClientBody + var body models.UpdateClientRequestBody if err := context.Bind(&body); err != nil { log.Println(fmt.Sprintf("Error updating Client: %v.", err)) return context.String(http.StatusBadRequest, "Invalid JSON!") } + if err := context.Validate(body); err != nil { + return err + } + var client models.Client if err := api.db.UpdateClient(id, body, &client); err != nil { diff --git a/internal/api/validator.go b/internal/api/validator.go new file mode 100644 index 0000000..6bfa34b --- /dev/null +++ b/internal/api/validator.go @@ -0,0 +1,19 @@ +package api + +import ( + "net/http" + + "github.com/go-playground/validator/v10" + "github.com/labstack/echo/v4" +) + +type CustomValidator struct { + validator *validator.Validate +} + +func (validator *CustomValidator) Validate(i any) error { + if err := validator.validator.Struct(i); err != nil { + return echo.NewHTTPError(http.StatusBadRequest, err.Error()) + } + return nil +} diff --git a/internal/models/client.go b/internal/models/client.go index 57f5beb..f19a861 100644 --- a/internal/models/client.go +++ b/internal/models/client.go @@ -20,31 +20,31 @@ type Client struct { Email string `json:"email"` } -type CreateClientBody struct { - Name string `json:"name"` +type CreateClientRequestBody struct { + Name string `json:"name" validate:"required"` FiscalCode string `json:"fiscalCode"` - Address string `json:"address"` - Zip string `json:"zip"` - Country string `json:"country"` - Phone string `json:"phone"` - Email string `json:"email"` + Address string `json:"address" validate:"required"` + Zip string `json:"zip" validate:"required"` + Country string `json:"country" validate:"required"` + Phone string `json:"phone" validate:"required,e164"` + Email string `json:"email" validate:"required,email"` } -type UpdateClientBody struct { +type UpdateClientRequestBody struct { Name string `json:"name"` FiscalCode string `json:"fiscalCode"` Address string `json:"address"` Zip string `json:"zip"` Country string `json:"country"` - Phone string `json:"phone"` - Email string `json:"email"` + Phone string `json:"phone" validate:"omitempty,e164"` + Email string `json:"email" validate:"omitempty,email"` } func (db *DB) MigrateClients() { db.instance.AutoMigrate(&Client{}) } -func (db *DB) CreateClient(body CreateClientBody) Client { +func (db *DB) CreateClient(body CreateClientRequestBody) Client { client := Client{Name: body.Name, Country: body.Country, Phone: body.Phone} db.instance.Create(&client) @@ -73,14 +73,22 @@ func (db *DB) GetClient(id int, client *Client) error { return nil } -func (db *DB) UpdateClient(id int, body UpdateClientBody, client *Client) error { +func (db *DB) UpdateClient(id int, body UpdateClientRequestBody, client *Client) error { result := db.instance.Where("id = ?", id).First(&client, id) if result.Error != nil { return result.Error } - result = db.instance.Model(&client).Updates(Client{Name: body.Name, Country: body.Country, Phone: body.Phone}) + result = db.instance.Model(&client).Updates(Client{ + Name: body.Name, + FiscalCode: body.FiscalCode, + Address: body.Address, + Zip: body.Zip, + Country: body.Country, + Phone: body.Phone, + Email: body.Email, + }) if result.Error != nil { return result.Error