Forbid extra keys in request body of gin golang - go

I want to do a validation for sending the extra keys in the JSON body.
My Model
type User struct {
gorm.Model
Username string `json:"username" validate:"required" gorm:"unique"`
Email string `json:"email" validate:"required,email" gorm:"unique"`
Password string `json:"password" validate:"required" `
}
Now if someone sends an id:111 in the request body then it gets save into db. I want to stop that only.
Validator that I'm using is "github.com/go-playground/validator/v10" but it's not working
validate := validator.New()
err := validate.Struct(user)

The go-playground/validator package you're using won't validate unknown fields in the JSON body by default. To validate only the fields in the struct, you can use the omitempty tag:
type User struct {
gorm.Model
Username string `json:"username" validate:"required" gorm:"unique"`
Email string `json:"email" validate:"required,email" gorm:"unique"`
Password string `json:"password" validate:"required" `
ID int `json:"id,omitempty" validate:"-"`
}
The omitempty tag means that the ID field won't be marshaled into JSON if its value is zero-value (0 for int). The validate:"-" tag means that the field won't be validated.

Related

How do I store the data from DTO Gorm

I am using golang fiber and GORM. I am trying to store the data from DTO. For example, I have created a post entity and post dto like below.
type User struct {
gorm.Model
Name string
Address string
Phone string
}
This is my DTO
type PostDto struct {
Name string `json:"name"`
Address string `json:"address"`
Phone string `json:"phone"`
}
I am trying to store the data like below
var postDto models.PostDto
c.BodyParser(&postDto)
err := database.DB.Model(models.User{}).Create(&postDto).Error
fmt.Println(err.Error())
But I am getting the below error
panic: reflect: call of reflect.Value.Field on string Value
Could anyone help to resolve this issue?
Thanks in advance
I don't know what you are doing? this is go language, not java, why do you define two structs?
You can use tag to complete that you want.
type User struct {
gorm.Model `json:"-" gorm:"-"`
Name string `json:"name" gorm:"column:name"`
Address string `json:"address" gorm:"column:address"`
Phone string `json:"phone" gorm:"column:phone"`
}
var user User
err := database.DB.Model(User{}).Create(&user).Error
fmt.Println(err.Error())
User and PostDto structures are not same, using one model to get and save data from another is wrong.
Either create a function to convert from PostDto to User, adn use its output in Create
func (postDTo PostDTo) ToUser() *User {
return &User{Name: postDTo.Name, Address: postDTo.Address, Phone: postDTo.Phone}
}
OR, as User and PostDto structs are so similar, add json ignore to gorm.Model in User and use it instead of PostDto
type User struct {
gorm.Model `json:"-"`
Name string `json:"name"`
Address string `json:"address"`
Phone string `json:"phone"`
}
var postData models.User
c.BodyParser(&postData)

GORM embedded struct not working correctly

I receive this error
controllers/users.go:61:36: user.ID undefined (type models.User has no field or method ID)
when using
var user models.User
...
jwtToken, err := generateJWT(user.ID, user.Username)
The definition of User model:
package models
import "time"
type BaseModel struct {
ID uint `json:"id" gorm:"primaryKey"`
CreatedAt time.Time
UpdatedAt time.Time
}
type User struct {
BaseModel BaseModel `gorm:"embedded"`
Username string `json:"username"`
Password string `json:"password"`
}
Actually I put BaseModel in different file but in the same package with User. Migration works fine as table users have all columns in BaseModel. What is the problem? I use golang 1.18 and latest version of GORM
You have used BaseModel as attribute in your model so even though gorm can very well map it to the table column to access it, you have to use the attribute name
To access you would do
jwtToken, err := generateJWT(user.BaseModel.ID, user.Username)
you could also try this next code to see if it works otherwise the above will work for sure
type BaseModel struct {
ID uint `json:"id" gorm:"primaryKey"`
CreatedAt time.Time
UpdatedAt time.Time
}
type User struct {
BaseModel `gorm:"embedded"`
Username string `json:"username"`
Password string `json:"password"`
}
now you might be able to access it like your original pattern
jwtToken, err := generateJWT(user.ID, user.Username)

How can I change the fields of a struct's json marshal?

tl;dr
How can I dynamize the JSON fields of a struct?
I am using gorm as the ORM. I have my model definition as a struct:
type UserAccessToken struct {
Id uint `gorm:"primaryKey" json:"-"`
CreatedAt time.Time `json:"createdAt"`
DeletedAt gorm.DeletedAt `json:"deletedAt"`
User User `gorm:"constraint:OnDelete:CASCADE" json:"-"`
UserId uint `gorm:"not null" json:"-"`
IpAddress string `gorm:"not null" json:"ipAddress"`
Token string `gorm:"not null" json:"token"`
}
I have multiple endpoints and I want to use different fields of the struct serialized on each endpoint.
For example, on POST /user-access-tokens/ user will be basic authenticated and a new access token will be created and returned on the response. However, on GET /user-access-tokens/ list API endpoint, the response will be a list of the UserAccessTokens, but the Token won't be on the response. And I am planning to create another endpoint only to be used by the administration interface, and all fields will be available there.
There are two I can think of:
Creating a different struct and reading from the database into this struct.
Adding a method like Map(scenario string) to the model struct which will create a map of the struct according to scenario, but in this case, I also need to add function to handle multiple instances of the struct.
What is the recommended way for this?
You can use another struct:
type UserAccessstruct {
Id uint `gorm:"primaryKey" json:"-"`
CreatedAt time.Time `json:"createdAt"`
DeletedAt gorm.DeletedAt `json:"deletedAt"`
User User `gorm:"constraint:OnDelete:CASCADE" json:"-"`
UserId uint `gorm:"not null" json:"-"`
IpAddress string `gorm:"not null" json:"ipAddress"`
}
type UserAccessToken {
UserAccessstruct
Token string `gorm:"not null" json:"token"`
}
func Get() {
var userAccess UserAccessToken
db.Select(selectQuery).First(&userAccess)
return userAccess // Full return
return userAccess.UserAccessstruct // Inner struct without token
}

How to init and insert struct with foreign key constraint into db using GORM

I am trying to create a rest API with golang. Each time a user is created, I would like to create a 'Profile' which is associated with that user.
My initial thought was to first create the user, and then separately create the profile referencing the user ID and inserting that into the database.
I'm not sure if this kind of thinking aligns with the way go should be used as i'm just starting with the language.
Using below code, I create the user, but cannot create the profile. I receive this error: using unaddressable value
var db *gorm.DB
func GetDB() *gorm.DB {
return db
}
type User struct {
gorm.Model
Email string `gorm:"type:varchar(100);unique_index"`
Password string `json:"password"`
Name string `json:"name"`
Token string `json:"token";sql:"-"`
}
type Profile struct {
gorm.Model
User User `gorm:"foreignkey:UserRefer"` // use UserRefer as foreign key
UserRefer uint
FirstName string `gorm:"default:'John'"`
LastName string `gorm:"default:'Doe'"`
Description string `gorm:"default:'Mysterious'"`
}
func (user *User) Create() (map[string]interface{}) {
if resp, ok := user.Validate(); !ok {
return resp
}
hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(user.Password), bcrypt.DefaultCost)
user.Password = string(hashedPassword)
GetDB().Create(user)
profile := Profile{}
profile.UserRefer = user.ID
GetDB().Create(profile)
if user.ID <= 0 {
return u.Message(false, "Failed to create account, connection error.")
}
response := u.Message(true, "Account has been created")
response["user"] = user
return response
}
I'm hoping someone will be able to help me understand what is going wrong here?
You should pass a pointer on gorm's Create method to get your model Filled after creation...
GetDB().Create(&profile)
But, as is showed in https://gorm.io/docs/associations.html gorm Auto create the associations.
You can change your models, like so... (I am supposing that User and Profile has a 1..1 relation ok?)
And everything will get done automatically
type User struct {
gorm.Model
Email string `gorm:"type:varchar(100);unique_index"`
Password string `json:"password"`
Name string `json:"name"`
Token string `json:"token";sql:"-"`
Profile Profile
ProfileID uint
}
type Profile struct {
gorm.Model
UserID uint
FirstName string `gorm:"default:'John'"`
LastName string `gorm:"default:'Doe'"`
Description string `gorm:"default:'Mysterious'"`
}

Cannot embed struct in struct

I have the following two structs:
type Profile struct {
Email string `json:"email"`
Username string `json:"username"`
Name string `json:"name"`
Permissions []string `json:"permissions"`
}
type Session struct {
Token string `json:"token"`
User Profile `json:"user"`
}
and I'm trying to create a new Session using:
session := Session{token, profile}
where token is a string and profile is a Profile both created earlier.
I'm getting the error cannot use profile (type *Profile) as type Profile in field value when I compile.
Am I missing something?
Your profile is a pointer. Either redefine your Session to be
type Session struct {
Token string `json:"token"`
User *Profile `json:"user"`
}
or dereference it.
session := Session{token, *profile}

Resources