Using a sub-resource or not? - rest

Let's take the following example:
We want to expose company and employee information from a RESTful API.
Company data should be quite simply:
GET api/v1/companies
GET api/v1/companies/{id}
Employees BELONG to a company, but we still want to retrieve them individually as well, so which solution is best:
Solution 1: Using sub-resources
Get all employees for a company:
GET api/v1/companies/{companyId}/employees
Get a specific employee:
GET api/v1/companies/{companyId}/employees/{employeeId}
Solution 2: Using an independent resources
Get all employees for a company:
GET api/v1/employees?companyId={companyId}
Get a specific employee:
GET api/v1/employees/{employeeId}
Both options seem to have their pros and cons.
With sub-resources, I may not always have the CompanyId on hand when wanting to retrieve an individual employee.
With an independent resource, getting all employees for a company should use the sub-resource approach if we want to be RESTful.
Otherwise, we could use a mix, but this lacks consistency:
Get all employees for a company:
GET api/v1/companies/{companyId}/employees
Get a specific employee:
GET api/v1/employees/{employeeId}
What is the best approach to take in such a situation if we want to stay true to RESTful standards?

For me this sounds like the common many-to-many relationship problem for RESTful services. (see How to handle many-to-many relationships in a RESTful API?)
Your first solution seems good at first but you will have problems whenever you want to access the relation itself.
Instead of returning the employee with the following GET request you should return the relation.
GET api/v1/companies/{companyId}/employees/{employeeId}
If the relation can be identified by 2 keys this solutions seems to be fine. But what happens if the relation is identified by 3+ id's? The URI becomes rather long.
GET api/v1/companies/{companyId}/employees/{employeeId}/categories/{categoryId}
In this case I would come up with a separate resource for the relation:
GET api/v1/company-employees/{id}
The returned model in JSON would look like this:
{
"id": 1 <- the id of the relation
"company": {
"id": 2
},
"employee": {
"id": 3
},
"category": {
"id": 4
}
}

I think it would be okay to provide both. If you want the client to browse through the list of companies first, then select a company and then get the list of all employees, the first approach is necessary. If, may be in addition, you want the client to be able to filter employees by name or age, but without knowing the company identifier, you must provide the second approach as well. It depends on what you want the client to do. In my opinion, it would not be necessary to provide the second approach, if clients can only filter employees by company identifier.

I would go for the first approach and providing some links to retrieve the subordinate resource.
If I take the example of a new employee that you may add in a company. It seems to be difficult, for the client with the second approach to make a POST on your collections. Why ? Because he has to know the company id that is "somewhere else".
With the first approach, as you followed a path, you already know this information (the companyId)... so it's easier for the client to add a new employee.
Back to your example, the main benefit of the second approach is, if your client want something like "the amount of employees in a city", where you don't care about the notion of company.
But it seems that you need the notion of company, so I would go for the first.
Also, very related to this question: RESTful design: when to use sub-resources?

Related

Designing REST end-point(s) for GET request supporting different IDs

I seek suggestions regarding designing an API endpoint.
I have a table (resource) with id (PK) and some other ids, which are not unique but have not-null constraints.
Now for designing this:
For the PK search /<resourceName>/{id}
Non-PK search
2.1 /<resourceName>/someOtherIdName/{someOtherId} - using path param, distinct for different IDs
2.2 or /<resourceName>?<nameOfId>=<value> - using query param
For 2nd one, which way is better? If I use 2.2, then multiple IDs can be supported but it becomes convoluted, as I have to check the nameOfId. And what about 2.1?
Edit: For example, take transactions to be a resource, and txn_id as primary key, and txn_event_id and txn_activity_id as other IDs. The last two ids can represent a group of related transactions. Does 2.2 suits for the last two IDs?
In case of 2.1, the implementation looks like:
#Path("/transactions")
class TransactionResource {
#Path("/eventid/{event_id}")
public List getTxnWithEventId(#PathParam("event_id") String eventId) {
// do a "event_id" based search
}
#Path("/activityid/{activity_id}")
public List getTxnWithActivityId(#PathParam("activity_id") String txnActivityId) {
// do a "pin" based search
}
}
In case of 2.2, the implementation becomes something like:
#Path("/transactions")
class TransactionResource {
public List getTxnsWithAnotherId(#QueryParam("searchKey") String id,
#QueryParam("searchValue") String value) {
if("event_id".equals(id)) // do a "event_id" based search
else if("activity_id".equals(id)) // do a "activity_id" based search
else return null;
}
}
In my opinion, the 2nd option feels better for searches but why not the former if thats true?
I think it all comes down to the developer's preference. I would not go with either of the options you listed. My approach would be collectionId/resourceId/collectionId/resourceId. So in your case, it would be something like users/1/messages to get all messages of a specific user of users/1/messages/1 to get message with id of 1 for that specific user. That way, you create clearer API endpoints which can be routed more efficiently in your app and can be better documented and managed.
Have a look at how Google's API Design Guide approach this subject for their Gmail resource model:
A collection of users: users/*. Each user has the following resources.
A collection of messages: users/*/messages/*.
A collection of threads: users/*/threads/*.
A collection of labels: users/*/labels/*.
A collection of change history: users/*/history/*.
A resource representing the user profile: users/*/profile.
A resource representing user settings: users/*/settings.
For 2nd one, which way is better?
Either of these is fine for most use cases
/<resourceName>?<nameOfId>=<value>
/<resourceName>/<nameOfId>/<value>
Tomato, tomato.
One reason that you might care about the difference is in the use of relative resolution and dot segments. Dot segments are useful for traversing the hierarchical portion of the URI, which is to say the path segments.
Another reason that you might care is that the query part of a URI has not always been understood to be part of the identifier. Old versions of the HTTP spec described exceptions to the caching rules when the query part was present. In the current standard, it shouldn't make a difference.
If you are struggling with readability of the URI with data encoded into the path segments, there are a number of spelling conventions that may help -- many derive ideas from TBL's work on Matrix URIs. If your clients and servers have access to decent URI Template implementations, then a lot of the work has already been done for you.
I am not sure what your resources are specifically but here are some tips that you can keep in mind while designing RESTful APIs
Identify what the primary resource is.
For example: employees
In your first case, you'd then access employees as
GET /employees. To get all employees.
GET /employees/1. Get a specific employee with ID 1.
Search is specific to your needs. If you need to fetch multiple employees based on IDs, you could do
GET /employees?id=1,2,3,4
Alternately if you find that you will need to search based on more than one parameter, I'd recommend a POST
POST /employees/search
{
id: [1,2,3,4],
department: "computer-science"
}

REST endpoint design for retrieving results in many to many relationship

I have read many of the other posts on designing many to many relationships restfully; however, i couldn't quite found the answers i was looking for.
Basically, I have 2 tables in the database and another many-to-many table that bridges these 2 tables.
For simplicity lets call them:
Course(CourseID, CourseName)
Instructor(InstructorID, InstructorName)
CourseInstructor(CourseID, InstructorID, lectureRoomName) (MANY-TO-MANY)
I have 2 questions:
1) How should I get all the entries inside the CourseInstructor table.
Is GET /courses/instructors correct? (or GET /instructors/courses or both)
Or should I have a seperate endpoint called /coursesinstructors
2) Also I want to be able to get all rows in the CourseInstructor table by passing in CourseName.
Normally i think i would do, /courses?name=coursename if i was searching for a course. And, I might use the endpoint /courses/{courseId}/instructors/{instructorId} to search for a specific entry in the many-to-many table.
Thus, I am curious would something like this work: /courses?name=coursename/instructors (Is this even possible?)
Another alternative is to have another endpoint called /coursesinstructors and i can make /courseinstructor?name=coursename to get the results.
Or should i make 2 calls to get the results by doing:
- get the id through /courses?name=coursename
- and follow it with courses/{id}/instructors
I am open to any other suggestions and solutions other than the ones I came up with above (not sure mine are correct solutions anyways).
For the first scenario, it really depends on what your use cases are. GET /courses/instructors would imply (only) retrieving the instructors, so I'd personally go with just GET /courses, and embed the instructors.
As for the second scenario, /courses?name=coursename should be good enough (plus /courses/{courseId}/instructors/{instructorId} for drilling down to a specific entry). The 2 calls is another valid option. However, an URL like /courses?name=coursename/instructors doesn't seem to be valid, according to RFC 3986.
If you really do need (1), a full dump of all course-instructor pairings, then I think your best bet is to support
GET /course-instructors
GET /course-instructors?courseName=whatever
You can then either link to or embed the course and the instructor.
{
"course": "/courses/12",
"instructor": "/instructors/54"
}
{
"course": {
"name": "Political Science",
...
},
"instructor": {
"name": "Hober Mallow",
...
}
}
What you return depends on the needs of your clients. Perhaps you return abbreviated information plus a link to the full representation, or perhaps it's ok to return just the links because courses and instructors are (should be!) highly cacheable.
As an aside, I think you'd be well-served to stop thinking about how the database stores data, and rather think about what clients need from your API.

What is the correct REST endpoint for adding an item to an array field?

Say I'm trying to model the action of adding a Student to a Group in a RESTful API written in Go with MongoDB.
A Group is modeled like this:
type Group struct {
Section mgo.DBRef
Instructor mgo.DBRef
Students []mgo.DBRef
}
An additional constraint is that the API is implementing HAL+JSON protocol, where resources are represented as links.
I've seen a couple of options (below):
POST /groups/{groupID}/students/{studentID} will add student with studentID to the group. The problem with this approach is that since I'm implementing the HAL+JSON protocol, I don't want the client to have manually pull out the ID and generate this link. All resources will be represented, i.e. /person/123 could be a Student.
PUT /groups/{groupID} while sending the complete array of Students that should belong to the group. This seems like it will introduce a lot of complicated parsing logic.
If there are other options I'd be open to it too.
EDIT: The approach that I'm going with is the following:
* POST /groupmembership/ by sending a JSON with the ID of the student and the ID of the group to add the student to. However, on the backend, I'm not generating a new model, but instead taking the object and programmatically adding the specified student to the specified group.
The question then is how would I remove the Student from the Group? Can I similar send a DELETE request to /groupmembership with
{
"student": 123,
"group": 456
}
to remove student 123 from group 456?
where resources are represented as links
This is not true. Links are possibly operations calls, so they are representing possible resource state transitions.
To add something to a collection, you need a collection resource and you have to decide what you want to store in that collection. In your case this can be 2 things: group-student memberships or students. If this is an 1:n relation, then you can store students and remove students. If this is an n:m relation then you have to store memberships and remove memberships, since you don't want to remove the students from your storage, just the memberships.
You can identify the memberships 2 ways:
you can use the ids of the participants: /groups/1/memberships/student:1 or /students/1/memberships/group:1
you can add a unique id to each membership: /memberships/1234
notes:
The URI structure matters only from a human perspective. The REST client will check the link relations and not the URI structure.
The resources are different from the entities in your database. Only by simple CRUD application represent them the same thing. So REST has nothing to do with your database structure.
First of all, there's no correct REST endpoint. URL semantics are irrelevant to REST. All that matters is that URLs are obtained from hypertext and not from out-of-band information, and seems like you got that part right, since you're using HAL. So, the correct REST endpoint is whatever link your server gives to the clients in order to add the item.
As long as an option isn't incorrect from an HTTP standpoint, I'd say to stick with whatever is more consistent with the REST of your API.
The option to POST /groups/{groupID}/students/{studentID} in order to create a new student in that location is incorrect, since a POST is submitting the payload to be processed by the targeted resource, and in this case it doesn't exist yet. A common pattern is to use POST /groups/{groupID}/students, where the collection acts as a facory for new elements, with the creation parameters in the payload, and returning the created student URL in the Location header, with 201 HTTP status code.

Using REST API for lookup lists dependant on context

I am currently trying to decide on the best approach to solve a problem I am having with designing my REST API.
The simplified scenario is my web application has two resources for example departments and employees. Both are security controlled within the business layer.
A user can exist who has access to employee but not to department, however when this user edits an employee they need to be able to select that employee's department from a drop down list (similarly they might have a list of employees that they want to filter by department).
Ordinarily that user would not have access to the department object so wouldn't be able to call /department/ for example but in the case of editing an employee they need the list of departments.
What would be the recommended way of dealing with this, would I return a list of departments on each GET of /employee/ or would I create another resource which was a combination of employee and department objects (department being the full list of departments)?
I can't currently change the security on the objects as this is deeply ingrained in the application logic.
Has anybody got any ideas?
Regards,
Gary
Create a new resource called something like 'DepartmentList'
Note: I think plural names are better.
You have to think of what would make the life of your users (devs) easier.
A combined resource would 'pollute' your api. Your api would expose /employees, /departments and /employeeDepartments. I don't think the latter deserves to be that high in the hierarchy.
It'd be also be a little more complex for your users to use:
"To edit an employee you need to set a department, BUT that department is not always available at /department, so you better get it from employeeDepartments ... "
Think of your employee object: GET /employees/123
employee:{
name: John,
...
department: {
id: ID
--a subset of data--
}
}
The subset of data should be enough to operate for Users with no rights, and Users with right access may operate on /departments/ID.
Now, how to get the list of available options?
I use to provide a 'special' action /new where I provide a 'form' which users can use as a template to post and create a new resource. This is not an adopted Rest 'standard' but is HATEOAS friendly - it really helps to the discoverability of your api.
So, GET /employees/new could print
employee:{
name: "",
...
department: [{ id: 1, --subset of data-- },{ id: 2, --subset of data-- }.. ]
}
There is some convention to be taken on the format (e.g: user needs to know that it only has to pick one department). But that's a hole new discussion.

MVC:RESTful routing with nested urls, when entities are not really nested

I 'm really having a hard time with the RESTful paradigm + nested urls. I have asked a question that lead me to where I am right now here. My Domain is roughly this: there are schools, courses of a school and teachers of schools. Now schools, courses and teacher are not "nested" entities in the sense that you can refer to any of them with one Id. The site is a collection of "micro-sites" for each school showing each one's courses and teachers. A course or teacher can only exist in one school.
say we have a url like /schools/1/courses/10 . Course 10 of school 1. This works fine. Say that the user changes by hand 10 into 11, which happens to exist but is a course of school 2. Right now that leads to a mess, my site still "thinks" the user is in school 1 but shows course 3 as part of it.
Should I make detail-actions parametric to both the Id being asked for AND the "parent" entity (the school in this case) that it involved? Fetch from repositories not only by id but with a school constraint?
Or is there any better way to do this?
The way I would think about it is this; even though there may be a course 11 in your service, there is no resource that exists at the URI /schools/1/courses/11. Since there is no resource at this URI, I would return an HTTP 404 response to requests for the URI.
One way you may improve your service would be to replace the integer ID values with the names of the entities (this would require the names be unique). This would make your URIs more user friendly. An example would be /schools/Hogwarts/courses/Potions.
To further improve your service, you'll want to give users a way to navigate through the service to all of the different resources available. For example you'll probably want to allow them get a list of all courses offered by a certain school. To do that you'd expose a resource at /schools/Hogwarts/courses/ whose return type would be a list of all courses offered by the school. The representation of this list could be an XML document like the following snippet:
<courses>
<course uri="/schools/hogwarts/courses/defense+against+the+dark+arts">Defense against the dark arts</course>
<course uri="/schools/hogwarts/courses/potions">Potions</course>
</courses>
Should I make detail-actions
parametric to both the Id being asked
for AND the "parent" entity (the
school in this case) that it involved?
Fetch from repositories not only by id
but with a school constraint?
Yes.
Or is there any better way to do this?
Nothing wrong with what you described above.
You could do it with a catch-all route, and then parsing the url elements yourself.