Using REST API for lookup lists dependant on context - rest

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.

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"
}

Restful URI design

Let's say that the domain structure of anapplication is as follows:
There is domain object called Department.
There is a domain object called Student.
There is a domain object called Paper.
The relationship between Student and Department is many-to-many.
A student can publish (create) a Paper for himself or for a
particular Department.
A student can view all the papers published by him for
himself and for departments to which he belongs (the latter includes
papers published by other students belonging to the same department
as the given student)
Here is what I think the restful uri designs should be like
Student creates (POST) a white paper for himself :
/students/{studentid}/papers
Student creates (POST) a white
paper for a particular department
/students/{studentid}/departments/{departmentid}/papers
Get all student papers published by him for himself
/students/{studentid}/papers/self
Get all student papers published by him for himself including the papers
of the departments to which he belongs
/students/{studentid}/papers
Similar get requests for point number 1 and 2.
The other way to arrive at the above end points would be something like (considering only points 1 and 2) :
/students/{studentid}/papers
and then pass departmentid in the request body. The application would the check for the presence of departmentId in the request. If it's not null then it will assume that this paper is being published for the given departmentid, otherwise for the student himself.
Which one of the above would be a better approach?
This link could help you to design your RESTful service: https://templth.wordpress.com/2014/12/15/designing-a-web-api/.
In addition, here are my comments regarding your URLs:
Everything that identifies your resource should be within the resource path (for example departmentid)
Regarding relations, we need to identify which URLs will handle references. For example, /students/{studentid}/departments/{departmentid}/papers will allow to attach an existing paper to a department or create a new one and in addition attach it to the department
I don't understand this url: /students/{studentid}/papers/self especially the token self. Does self refer to the current authenticated user? If so, I think that should use a query parameter since it doesn't really correspond to a resource... In fact, you rather use query parameters for list filtering
Hope it helps you,
Thierry
Since departmentid is part of how a resources is identified, it must be part of the URL. Putting it into the request body is a violation of REST principles.

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?

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.

RESTful API related objects & denormalization (MongoDB)

I'm building a RESTful web application using node.js and MongoDB.
I have a Person model
Person
id: '12345'
name: 'John'
likes: [ {id: '54321', name: 'Mary'} ]
isLikeydBy: []
Person
id: '54321'
name: 'Mary'
likes: []
isLikeydBy: [ {id: '12345', name: 'John'} ]
What is the best way to model "likes" and "isLikedBy" relationships? Since I am using MongoDB I thought that this is a good way to model the relationships, as there is only one access to database needed to get all data about one person.
How to create a REST api for this relationship? What if 'John' doesn't like 'Mary' anymore. The server only receives the following put request.
Person
id: '12345'
name: 'John'
likes: []
isLikeydBy: []
But the server should also update 'Mary', because now she is not liked by 'John' anymore. (I know that MongoDB does not directly support transactions and that I have to implement them myself.)
My ideas:
1. On each update of Person (of it's 'likes' and 'isLikedBy' fields) get this person from database and compare their 'likes' and 'isLikedBy' fields with the request. There is some overhead with this approach and also I do not know if it is in the spirit of RESTful APIs.
2. Make the client send both the original 'likes' and 'isLikedBy' fields and also the new updated ones (or only the diff). This seems even further away from RESTful design, since the client must now be aware of which data was last successfully saved to the server.
3. Create a separate object which would contain the relationship information (3 fields: id, me, whoILike). But this means that each time I would want to get data about a person I would need 2 queries, one for the person and one for relationships and then combine the data into single object.
What should I do?
We've wrestled with this same problem at my company when using Mongo and tracking likes.
After much discussion we decided to store the counts of likes with the entities - in this case storing likes with people.
Opinions on your options:
The overhead in doing additional queries is probably a bad idea. Especially since "liking" stuff is seen by the users as a lightweight operation. In other words, you might find users liking a ton of stuff, which means a lot of writes - and in this case every write has an additional read or two with it.
This is a lot of work for the developer to do and it's easy to get wrong.
I think it's ok, but I still prefer to store likes with the person. Mongo isn't good at joins like you mentioned.
I think you should store the like/liked by fields with the person document. The only thing I would change is the REST call being made.
Maybe something like:
PUT http://www.rest.com/person/123/likes/456
This would say "Person 123 likes 456." Then your REST call makes sure the data is updated. It would update the Person 123 object and the Person 456 object.
To remove something like:
DELETE http://www.rest.com/person/123/likes/456
Keep in mind every time someone makes a REST call, the update doesn't have to update the entire document. You can do partial updates on the Person document with the modified likes. You can also easily add/remove an array in a document.