Search code examples
resthateoashttp-patch

Best approach for updating a relation to another resource in a REST API


Let's say I have a REST API adhering to basic HATEOAS principles. Items belong to a User.

GET /item/13

{ 
  id: 13,
  name: 'someItem',
  type: 'someType',

  _links: [
    {
      rel: 'user',
      href: '/user/42'
    }
  ]        
}

Now I need a way to change the user for a given item. Using either a PUT or a PATCH, which is the preferable way of performing that modification?

  1. Establish the new relation by setting the id of the new linked resource as a simple property in the JSON body

    PATCH /item/13
    {
      userId: 43
    }
    
  2. Establish the new relation by having the client pass the link itself as the input

    PATCH /item/13
    {
      _links: [
        rel: 'user',
        href: '/user/43'
      ]
    }
    

I usually think of links as read-only representations of relations stored in other formats (such as id:s to other resources), returned from GET calls. It doesn't feel very natural to me to have links as input to POST/PUT/PATCH calls, and the fact that links is an array makes it even stranger (should you be able to update all links? One single link?), but I have seen it suggested in various articles. Is there a best practice? What would be the benefits of using the links approach?


Solution

  • The point of REST is (at least one of them) is to make everything visible through a standard interface. In other words, if the 'relations' are a thing, than it too should have its own resource.

    The API should also be more descriptive. This might be subjective, and I don't know all the details of your model/design, but 'items' don't have 'links'. 'Items' might instead have a single 'owner'. If this is the case, it might look something like:

    GET /item/123/owner
    

    So POSTing or PUTing an URL of a user (or some simple representation) would 'change' the owner of the item. It might be not allowed to DELETE the owner, depending on if the model allows unowned items.

    Note, that the representation under "/item/123" would in this case have to link to "/item/123/owner", since the client only follows links it gets from the server.

    So, think about what are important 'things', all of those should have a resource. Also, try to add as much 'meaning'/semantics as you can. The relation should not be called 'user', it should be called 'owner' (or whatever the meaning should be in your model).