I have been using the mgo driver for a while, but now its my first time having to write a fully tested REST API with it.
Here it my goal
GET /users - Retrieves a list of users
GET /users/12 - Retrieves a specific users
POST /users - Creates a new user
PUT /users/12 - Updates user #12
PATCH /users/12 - Partially updates user #12
DELETE /users/12 - Deletes user #12
My problems arise from the PATCH/PUT method. Here its what I have so far
dao := daos.NewUserCollection(r)
userRequest, err := dao.GetUserRequest(r)
found, err := dao.GetByID(mux.Vars(r)["id"])
err = dao.Patch(mux.Vars(r)["id"],userRequest)
updated, err := dao.GetByID(mux.Vars(r)["id"])
log.Println("##################################################")
log.Println("URL PARAMETER", mux.Vars(r)["id"])
log.Println("USER FROM BODY",util.Marshall(userRequest))
log.Println("USER FROM DB",util.Marshall(found))
log.Println("UPDATED USER FROM DB",util.Marshall(updated))
log.Println("##################################################")
I am getting the user like
func (c *UserCollection) GetByID(id string) (models.User, error) {
result := models.User{}
err := c.FindId(bson.ObjectIdHex(id)).One(&result)
return result, err
}
I am doing the patching like
func (c *UserCollection) Patch(selector string, user models.User) ( error) {
err := c.UpdateId(bson.ObjectIdHex(selector),user)
return err
}
But the logs show me an unwanted behaviour
2016/09/28 14:10:57 ##################################################
2016/09/28 14:10:57 URL PARAMETER 57ebf9a1926bbc5bd0e666d9
2016/09/28 14:10:57 USER FROM BODY {"id":"57ebf9a1926bbc5bd0e666d9","username":"Snarlripple","email":"Slavefair@confirmed.com","password":"password","role":"","devices":["POWERDEVICE"],"confirmed":false,"notification":false}
2016/09/28 14:10:57 USER FROM DB {"id":"57ebf9a1926bbc5bd0e666d9","username":"Snarlripple","email":"Slavefair@confirmed.com","password":"$2a$04$gWErsTOWohjoJNON8l0O8OBQU0zHesFxS2vtgcqrOzcbwCEvxfUC.","role":"user","devices":[],"confirmed":true,"notification":false}
2016/09/28 14:10:57 UPDATED USER FROM DB {"id":"57ebf9a1926bbc5bd0e666d9","username":"Snarlripple","email":"Slavefair@confirmed.com","password":"password","role":"","devices":["POWERDEVICE"],"confirmed":false,"notification":false}
2016/09/28 14:10:57 ##################################################
The api is changing the password and the role of the user. I do not want my clients to be able to do this. I want to make it so there are just a few fields it has Whats the idiomatic way of doing this?
UPDATE
I got it to work with the below. Not sure if it the best way, but works.
func (c *UserCollection) Patch(id string, user User) error {
coolmap := structs.Map(&user)
setBSON := bson.M{}
for key, value := range coolmap{
if !contains([]string{"ID","Role", "Password", "Devices"},key) {
setBSON[strings.ToLower(key)] =value
}
}
changes := bson.M{"$set": setBSON }
err := c.UpdateId(bson.ObjectIdHex(id),changes)
return err
}
func contains(s []string, e string) bool {
for _, a := range s {
if a == e {
return true
}
}
return false
}