REST endpoint design for retrieving results in many to many relationship - rest

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.

Related

Conflicting REST urls

So I'm building a REST api and need to make some urls. The problem is, I'm running into some conflicting paths. For example:
GET <type>/<id> gets the details of an object of a given type and id
GET <type>/summary gets the summary of objects of a given type
This simplified example shows a problem occurs when an object has id "summary". What is the best way to solve this? From a REST puritan perspective, what should be the solution?
Here's some of my ideas:
Put the <id> in query parameters. From what I understand this is against standards
Put a keyword at the start of the url. Also against standards?
Disallow certain id values. Not something I want to enforce for all my users and use cases and different entrances into my system
I may have an alternative to this. What if we have both book as wel as the plural books. Then you can have:
/book/{id}
and
/books/summary
or
/books/count
The URL structure is not quite right to begin with so it's difficult to solve it in a clean way.
For the sake of discussion, let's assume <type> is a books resource. So the first URL is fine - you get a book of the given ID:
GET /books/<id>
However this is not:
GET /books/summary
Because it's a bespoke URL, which I guess has a use in your application but is not restful. A GET call should return one or more resources. However a "summary" is not a resource, it's a property of a resource and that's why you end up in this situation of having IDs mixed up with book properties.
So your best option would be to change this URL to something like this:
GET /books?fields=summary
By default GET /books would return all the resources, while GET /books?fields=<list_of_fields> will return the books but with only the chosen properties.
That will be similar to your previous URL but without the ID/property conflict, and will also allow you later on to retrieve resources with specific fields (without having to create new custom URLs).
Edit:
Regarding the count of books, it's still useful to reason in terms of resources. /books gives you one or more books, but it should not be used for meta-information about the collection, such as count, but also things like "most read book", or "books that start with the letter 'A'", etc. as that will make the resource more and more complex and difficult to maintain.
Depending on what you want to achieve I think there'd be two solutions:
Create a new resource that manages the collection of books. For example:
GET /bookcase
And that will give you information about the collection, for example:
{
"count": 1234,
"most_read": "<isbn>",
// etc. - any information that might be needed about the book collection
}
Or a search engine. You create a resources such as:
GET /book_search_engine/?query=
which would return a search result such as:
{
"count": 123,
"books": [
// Books that match the query
]
}
then a query like this would give you just the count:
// Search all the books, but provide only the "count" field
GET /book_search/?query=*&fields=count
Obviously that's a more involved solution and maybe not necessary for a simple REST API, however it can be useful as it makes it easier to create queries specific to a client.
This simplified example shows a problem occurs when an object has id "summary". What is the best way to solve this? From a REST puritan perspective, what should be the solution?
As far as REST is concerned, the URI are opaque. Spelling is absolutely irrelevant. You could use URI like
/a575cc90-2878-41fe-9eec-f420a509e1f0
/f871fff6-4c4e-48f7-83a4-26858fdb3096
and as far as REST is concerned, that's spot on. See Stefan Tilkov's talk REST: I Don't Think It Means What You Think It Does.
What you are asking about is URI design, how to adapt conventions/best practices to your particular setting.
One thing that will help is to recognize is that summary is a resource, in the REST/HTTP sense -- it is a document that can be represented as a byte sequence. All you need to do is figure out where that resource belongs (according to your local spelling conventions).
Continuing to borrow the "books" example used by others
# Here's the familiar "URI that identifies a member of the books collection"
/books/<id>
# Here's the summary of the /books collection
/summaries/books
Put the in query parameters. From what I understand this is against standards
Not as much as you might think. REST doesn't care. The URI spec expresses some views about hierarchical vs non hierarchical data. HTTP supports the notion of a redirect, where one resource can reference another.
GET /books?id=12345
302 Found
Location: /books/12345
You also have options for skipping a round trip, by returning the representation you want immediately, taking advantage of Content-Location
GET /books?summary
200 OK
Content-Location: /summaries/books
...
I have the same issue. And all the solutions seem a little off b/c REST best practices seem to suggest none of them are ideal.
You could have just one off-limit id, like all.
GET <type>/<id>
GET <type>/all/summary
It might even be possible to use a single symbol instead, such as ~ or _.
GET <type>/<id>
GET <type>/~/summary
How satisfying this solution seems is of course very subjective.
The singular/plural approach seems more elegant to me but despite most REST best practice guides saying not to do this. Unfortunately some words don't have distinct singular and plural forms.
This isn't perfectly conventional for how some like to define their rest endpoints.
But I would would enforce a pattern where "id" cannot be any string. Instead I would use a uuid and define my routes as such.
GET /books/{id:uuid}
GET /books/{id:uuid}/summary
And if you really want a verb in the URL without an identifier it is still technically possible because we know the {id:uuid} in the path must conform to the uuid pattern.
With that GET /books/summary is still distinct from GET /books/{id:uuid}

REST URL Design for One to Many and Many to Many Relationships

Your backend has two Models:
One Company to Many Employees.
You want to accomplish the following:
Get all Companies
Get a Company by ID
Get all Employees for a Company
Get all Employees
Get a Employee by ID
What is the best practice for handling the REST URLs when your models have 1:M relationships? This is what I have thought of so far:
/companies/
/companies/<company_id>/
/companies/<company_id>/employees/
/employees/
/employees/id/<employee_id>/
Now let's pretend One Company has Many Models. What is the best name to use for "Adding an employee to a Company" ? I can think of several alternatives:
Using GET:
/companies/<company_id>/add-employee/<employee_id>/
/employees/<employee_id/add-company/<company_id>/
Using POST:
/companies/add-employee/
/employees/add-company/
The URIs look fine to me, except maybe the last one, that does not need an additional "id" in the path. Also, I prefer singular forms of words, but that is just me perhaps:
/company/
/company/<company_id>/
/company/<company_id>/employee/
/employee/
/employee/<employee_id>/
The URIs do not matter that much actually, and can be changed at any point later in time when done properly. That is, all the URIs are linked to, instead of hardcoded into the client.
As far as adding an employee, I would perhaps use the same URIs defined above, and the PUT method:
PUT /employee/123
With some representation of an employee. I would prefer the PUT because it is idempotent. This means, if the operation seems to fail (timeout, network error occurs, whatever) the operation can be repeated without checking whether the previous one "really" failed on the server or not. The PUT requires some additional work on the server side, and some additional work to properly link to (such as forms), but offers a more robust design.
As an alternative you can use
POST /employee
With the employee representation as body. This does not offer any guarantees, but it is easier to implement.
Do not use GET to add an employee (or anything for that matter). This would go against the HTTP Specification for the GET method, which states that it should be a pure information retrieval method.

Master/Detail with REST

I'm sure this topic must have been covered off before so I'm happy to be pointed to any articles etc that I may have missed while searching.
I need to implement a very simple REST API to add and retrieve records in a master/detail relationship. My two options are below:
OPTION 1
POST /master
POST /master/[id]/details
GET /master/[id]
GET /master/[id]/details
PROS
Feels more 'RESTful'
Can retrieve fine-grained data for performance
CONS
A master doesn't make sense without at least one detail. How to handle atomicity? Compensating DELETE on the master if the detail fails when adding?
Multiple calls required to retrieve the master/detail set
OPTION 2
POST /master_and_details
GET /master_and_details/[master id]
PROS
Easy to manage atomicity
CONS
More complex structure to manage
GETs must return entire structure (not always efficient)
Doesn't feel very 'RESTful'
Thanks,
John
REST more or less dictates option 1, option 2 is just a plain old http api.
Your statement that a master makes no sense without at least one detail is probably wrong. You have no idea how your api will be used in the future by clever developers. You can guess, but you don't really know.
If you really need the compound solution yourself you could always add an interface at a higher level that calls onto the two separate interfaces and returns a compound object.
Option 1 allows the possibility of a microservice implementation -- or at least, a separation of concerns into two separable objects. Option 2 alone would not.
At least for sake of argument, and risking my meager reputation, I'll venture a third approach.
You'd have two resources: master and detail. (not "details", unless you want to go totally plural, in which case you'd have "masters" and "details"). The representation of master would include the collection of details, or (better) link relations to the details. Consider https://www.rfc-editor.org/rfc/rfc6573 for that link relation.
Therefore GET of master includes (directly or indirectly via relation) the collection of detail. POST/PUT of master can also POST/PUT detail members by their presence in the form data.
Any detail can also be GET/PUT/POSTED independently of the master. Here, the design depends somewhat on whether a detail has its own primary key, vs. using a composite key with its master. If it has its own primary key then you could have:
GET /detail/{detailKey} - gets specific detail
POST /detail - creates new detail
GET /master/{masterkey}/detail -- gets all details for master
GET /master{masterkey}/detail/{detailkey} -- get specific detail
obviously, on the POST, the data must include the key of the master.
You see that there is more than one URI for getting a detail. I don't think that that's wrong, but it does introduce some ambiguity: if detailKey is not actually a child of masterKey, do you 404? I'd say yes.
if the detail uses a composite key, then it can't be GETed independently of the master, so the first form shown above could not be supported. Also, {detailKey}, as used in the last example above, would be the identifier of the detail item within the master (typically a sequence number).
I would definitely go with Option 1, as Option 2 has nothing to do with REST. But that does not mean, that you need to use multiple querys to get Master + Detail.
As the Detail belongs to the Master (and so it is part of it), in my opinion it is absolutely ok to return Master and the Detail, when querying the Master.
You might also consider using a parameters to control whether to send the Detail or not.
So instead of executing GET /master/1 you could use GET /master/1?detail=true.
For POST and PUT more or less the same would work. Just instead of having the query parameter, you have a "section" in your body regarding the Detail.
An Example using JSON:
{
"data": {
"name": "master",
"detail": [
{
"name": "detail1"
},
{
"name": "detail2"
}
]
}
}
A POST with this data could create a Master with the name "master" and 2 Details for this Master.
As #ElroyFlynn stated before, the Details could also be accessible without the Master, if this makes sence.
Think about a forum with Threads and Posts. Usualy a Thread is the Master and every Post is a Detail. But if you want to search all Posts of the last hour, you definitely want to query the posts directly (the query could be something like GET /post?max_age=1h).
Also I don't agree, that a Master without Detail does not make sence. There might be cases, where it doesn't, but in the case of the forum, a Thread on it's own makes sence.
For the atomicity:
It depends on the case: If you delete a User you usually keep his Posts (even here on StackOverflow). If you instead delete a Thread, I guess, you can delete the Posts to.

Using a sub-resource or not?

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?

RESTful way to ask for subset of a resource

Suppose I have a resource called user_stats, that has things like how many posts, comments, likes, and followers users have. Is there a RESTful way to only ask for parts of that statistics (i.e. for user_stats/3, tell me how many posts and comments this user has, but don't tell me how many follower this user has.)
The reason I'm asking is some statistical attributes can be computationally intensive (yes I'm generating them at query time). So simply not asking for it can reduce workload.
There is a very useful 38 page free ebook with best practices about designing Web APIs, you might find it helpful, at least I did.
For your case, it is stated:
Add optional fields in a comma-delimited list
The Google approach works extremely well.
Here's how to get just the information we need from our dogs API using
this approach:
/dogs?fields=name,color,location
It's simple to read; a developer can select just the information an
app needs at a given time; it cuts down on bandwidth issues, which is
important for mobile apps. The partial selection syntax can also be used to include associated resources cutting down on the number of requests needed to get the required information.
Maybe that's what you re looking for?
there are at least three options:
Use query parameter as a filter
e.g. user_stats?fields=posts,comments
Make user_stats composite resource and create new resources for particular stat
e.g. /user_stats in JSON
{
"blogs" : {
"count" : 10,
"link" : "/user_stats_blobs"
},
...
}
then you can get whole stats (GET /user_stats) or just a piece (GET /user_stats_blobs)
Create filter representation; use POST to post filter representation as part of request
e.g.
Request
POST /user_stats/filter
{
"fields" : [ "blogs", ...]
}
response body contains just requested/filtered data.
All solutions are RESTful. Solution 1. is easy to implement but has limited extensibility and transparency. Solution 2. expects that you create new resources which is overhead in this case (you need just one number). so, I would recommend solution 3. because is no so hard to implement, is easily extensible and transparent.