0

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
}
CESCO
  • 7,305
  • 8
  • 51
  • 83
  • 1
    You need to use `$set` [operator](https://docs.mongodb.com/manual/reference/operator/update/set/). This [answer](http://stackoverflow.com/questions/23583198/partial-update-using-mgo) is related to your question. – putu Sep 28 '16 at 23:48
  • 1
    And in order to use the PATCH as expected, you need to use `$set` with the `bson/map[string]interface{}` with that exact path to update. If you use `user`, it will become PUT and whole data will be overwritten. – Anzel Sep 29 '16 at 07:23
  • thaks @putu . think I got it now – CESCO Sep 29 '16 at 20:17

0 Answers0