deitch
deitch

Reputation: 14581

How should I build REST resource paths when there is a many to many relationship

I have users, and I have groups

GET /user/1 -> {id:1,name:"john"}
GET /user/2 -> {id:2,name:"sam"}
GET /group/1 -> {id:100,name:"myGroup"}

Obviously, group-to-user is a many-to-many relationship. Ignoring the storage implementation, I am trying to figure out the sanest way to represent it.

/user/1/group // lists the groups of which "john" is a member, e.g. [100]
/group/100/user // lists the users who are members of "myGroup", e.g. [1]

One? The other? Both of them?

To take it one step further, what if I allow sam to see john (but no one else), because they are both members of group 100? Conceptually, LinkedIn or Facebook similarly allow you to see info about someone once you are connected.

So if john (1) requests info about sam (2), should I do:

/user/2 // allows it, with some backend mechanism finding the memberships of sam and john, and then finding that they are in the same group?

OR

/group/1/member/2 // this is john saying, "I want to access user 2 who is a member of group 1 and so am I"

The second option makes the request explain why they should be together, and makes the logic far simpler. On the other hand, user 2 already is a resource at /user/2, so the alternate route seems strange?

Upvotes: 0

Views: 92

Answers (2)

William Durand
William Durand

Reputation: 5519

First, your collections should use a plural form such as:

/users
/groups

Representing your users and groups depends on your business, I would say that your "users" are first-class citizens, so it should be:

/users/{userId}/groups

That would return all groups for user identified by its userId. Note that /users/{userId} could return user's groups as well, but it is up to you.

The following URI would work as well, but then again, it depends on what you want to do:

/groups/{groupId}/users

To take it one step further, what if I allow sam to see john (but no one else), because they are both members of group 100? Conceptually, LinkedIn or Facebook similarly allow you to see info about someone once you are connected.

This could be implemented by some sort of Access Control Lists (ACLs). If user A can't see data of B because they are not friends, then querying /users/B will return nothing. However, if C (who is friend with B) performs the same request on /users/B, he will be able to see data of B.

So I would go for the first option.

Upvotes: 1

Eric Stein
Eric Stein

Reputation: 13672

I would consider making a separate resource, maybe groupMemberships, which holds the relationship. You can still have something like GET /users/1/groups to get the groups directly, if it was worth it to you.

GET /groupMemberships?user=1
GET /groupMemberships?group=100

{
    "href": ".../groupMemberships/abc123"
    "user": {
        "href": "/users/1"
    }
    "group": {
        "href": "/groups/100"
    }
}

Upvotes: 0

Related Questions