Pascal
Pascal

Reputation: 3165

Removing an item from a collection in a HATEOAS way

I am working on a project whose client uses REST/HATEOAS to get and modify data.
Here is a part of the class diagram: class diagram.

A hal+json HATEOAS response of the request /group/12345 would look like:

{
  "id": "12345",
  "_links": {
    "self": {
      "href": "/group/12345"
    },
    "roles": {
      "href": "/group/12345/roles"
    }
  }
}

To remove a role from this group I could simply execute a DELETE on the specific role. (because every role has to be in exactly one group and moving a role to another group shouldn't be allowed).
So I would add a link with the rel "drop" to the role. Therefore the client knows if or rather when a DELETE request is allowed:

{
  "id": "67890",
  "_links": {
    "self": {
      "href": "/roles/67890"
    },
    "users": {
      "href": "/roles/67890/users"
    },
    "drop": {
      "href": "/roles/67890"
    }
  }
}

So to delete a user the client looks for the drop link. If no link is found, the delete is not allowed. Otherwise it executes a DELETE request on the found link.

But what should I do if I want to remove a user from a role?
I cannot simply delete the user. The role -> user relation is not an aggregation.
How can I tell the client if removing a user from a role is allowed?

To remove a user from role I would use DELETE /groups/12345/roles/67890/users/ABC. And to delete the user I would use DELETE /users/ABC.

So where should I put the "remove user from role" link?

Thank you in advance :)

Upvotes: 1

Views: 1254

Answers (1)

VoiceOfUnreason
VoiceOfUnreason

Reputation: 57277

Links typically have three parts

  • A context identifier
  • a link relation type
  • a target identifier

Frequently, the context identifier is implied by the... umm... context, rather than being made explicit.

From what I can see, hal+json doesn't have a mechanism for explicitly specifying the context identifier, which would mean that you need to rely upon the implicit approach.

That suggests that if you want to be communicating about removing a user from a role, then you need a context that implies the right identifier.

You would normally do this in one of two ways

  • have a chain of links that leads to a representation of the user in that role, and include the drop role link relation in the list of links
  • embed a representation of the user in some other representation, and include the drop role link within that embedded resource.

For example, you might have a representation of /roles/67890/users that looks something like

_links: {
    self: {
        href: /roles/67890/users
    }
}

_embedded: {
    users: [ {
        _links: {
            self: /users/ABC
            /role/remove :  /groups/12345/roles/67890/users/ABC
        }
   } ,
   ... ]
}

Upvotes: 2

Related Questions