I'm building an app that will allow users to manage groups. Each group contains a name, campus, and data type. They are not in any particular hierarchy - semantically, a campus could be considered to have many groups, but it would be also natural to consider a group at the top of the hierarchy, spread out over many campuses.
A combination of name/campus/data_type is unique
NAME CAMPUS DATA_TYPE
---------------------------------------
LABS WEST IPv4
LABS WEST IPv6
LABS EAST IPv4
USERS NORTH userids
USERS WEST userids
USERS EAST userids
So for example, the LABS group for the WEST campus with DATA_TYPE of IPv4 will contain all the IP subnets related to west-campus labs.
Now, the only requirement for drilling down to this data is by group. It is not a requirement to gather a list of all WEST campus groups, for example, or all groups that have a "IPv6" data type. However it is necessary to get a list of all campuses that have a "LABS" group, and it is also necessary to get all the data_types for LABS.
So how should I create my endpoints?
Long, but fairly clear URLs.
GET /groups/LABS/ (returns LABS groups across all campuses and data_types)
GET /groups/LABS/data_type/IPv4 (returns all IPv4 LABS groups across all campuses)
GET /groups/LABS/campus/WEST (returns all WEST LABS groups across all data_types)
POST /groups/LABS/campus/NORTH/data_type/IPv4 (create a new group)
POST /groups/LABS/campus/NORTH/data_type/userids (another new group)
ADVANTAGE:
DISADVANTAGES:
Treat the group as the only part of the hierarchy, and treat "campus" and "data_type" as non-hierarchical identifiers:
GET /groups/LABS
GET /groups/LABS?campus=WEST
GET /groups/LABS?data_type=IPv4
GET /groups/LABS?campus=WEST&data_type=IPv4
POST /groups/LABS (POST data: {campus: "WEST", data_type: "IPv4})
POST /groups/LABS (POST data: {campus: "WEST", data_type: "IPv4})
ADVANTAGE:
DISADVANTAGES:
I'm leaning towards option 2. Is that the best way to represent this data? Or am I thinking about it wrong?
I would suggest instead supporting two endpoints. It's clear from your description that a group is not uniquely defined by a name, but your URI structure implies that it is. Instead, use a synthetic id to uniquely identify a group.
GET /groups
?name={}
?campus={}
?data_type={}
<- some collection of all groups that match whichever criteria are specified
POST /groups
-> { "name": "LABS", "campus": "WEST", "data_type": "IPv4" }
GET /groups/{id}
<- { "name": "LABS", "campus": "WEST", "data_type": "IPv4" }
This approach gives you more flexibility for in the future when they decide to add a new property, or want to search by data_type across all groups.
You can either include unique ids in responses from the server (meh) or include hypermedia links to give you interesting relationships, such as all other groups with the same name, or on the same campus.