Consider the following relationship between two resources
College has many Faculties
Faculty belong to a College
Obviously a Faculty is not a first class resource here.
Now I need endpoints for following operations.
Create a new faculty in this college this farm. One possible way to do this in two operations.
POST /faculties/
PUT /college/1/faculties
Remove a faculty from this college. Again two operations
GET /college/1/faculties: List of associated faculties. Each will contain a self url like /faculties/1.
DELETE /college/1/faculties/1: The url looks better but how to expose this url?
Add one or more faculties under that college.
PUT /college/1/faculties that accepts a complete list of faculties of this college.
Delete that particular sector entirely.
DELETE /sectors/1: Looks good but needs to take care of the cache of /faculties/1/sectors.
What would be a better approach in this case? I have read about exposing membership resources, but with that approach, if a college has 10 faculties, it will take 10 seperate http call to get all of those from the memberships.
Moreover, this is just one small part of the full relationship tree. To extend this further, say the system has
Faculties has many Departments
Department has many labs so on.
And besides, In RESTful architecture, the client should never populate the URLs.
Any suggestion?
I wrote a post in the past on how OData implements such aspects (feature "navigation properties"). See this link: https://templth.wordpress.com/2014/12/08/updating-data-links-of-odata-v4-services-with-olingo/.
This other link could also give you some interesting hints since it describes at the end the URLs and corresponding payloads: http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/odata-v4/entity-relations-in-odata-v4.
I think that there are two cases you can leverage to minimize the number of request: working with reference or provide content. I mean if the resource detects (based on the content or a custom header) the sent content so it knows if it only needs to handle a reference (attachment only) or a content (creation and attachment).
I would see following possible requests for multiple cardinality (college -> faculties):
POST /faculties/: add a faculty with no attachment to a college
POST /college/1/faculties: attach a faculty to a college and eventually create it if not exist (based on sent content)
DELETE /college/1/faculties/?ref=/faculties/1 to detach a faculty from a college
Something that you could also consider is to put the reference to the college within the faculty (request POST /faculties). So you could attach element during its creation.
Otherwise doing this PUT /college/1/faculties aims to replace the whole representation so all faculties that are attached to a particular college.
You could also use a POST or a PATCH method to minize the number of request. You can have a look at these answers for more details: REST API - Bulk Create or Update in single request and How to Update a REST Resource Collection. Such approach allows you to create elements in one call and then attach them. It allows to gather processing on elements.
Hope I was clear and it helps you,
Thierry
Related
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.
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.
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.
This question is about optimal REST API design and a problem I'm facing to choose between nested resources and root level collections.
To demonstrate the concept, suppose I have collections City, Business, and Employees. A typical API may be constructed as follows. Imagine that ABC, X7N and WWW are keys, e.g. guids:
GET Api/City/ABC/Businesses (returns all Businesses in City ABC)
GET Api/City/ABC/Businesses/X7N (returns business X7N)
GET Api/City/ABC/Businesses/X7N/Employees (returns all employees at business X7N)
PUT Api/City/ABC/Businesses/X7N/Employees/WWW (updates employee WWW)
This appears clean because it follows the original domain structure - business are in a city, and employees are at a business. Individual items are accessible via key under the collection (e.g. ../Businesses returns all businesses, while ../Businesses/X7N returns the individual business).
Here is what the API consumer needs to be able to do:
Get businesses in a city (GET Api/City/ABC/Businesses)
Get all employees at a business (GET Api/City/ABC/Businesses/X7N/Employees)
Update individual employee information (PUT Api/City/ABC/Businesses/X7N/Employees/WWW)
That second and third call, while appearing to be in the right place, use a lot of parameters that are actually unnecessary.
To get employees at a business, the only parameter needed is the key of the business (X7N).
To update an individual employee, the only parameter needed it the key of the employee (WWW)
Nothing in the backend code requires non-key information to look up the business or update the employee. So, instead, the following endpoints appear better:
GET Api/City/ABC/Businesses (returns all Businesses in City ABC)
GET Api/Businesses/X7N (returns business X7N)
GET Api/Businesses/X7N/Employees (returns all employees at business X7N)
PUT Api/Employees/WWW (updates employee WWW)
As you can see, I've created a new root for businesses and employees, even though from a domain perspective they are a sub/sub-sub-collection.
Neither solution appears very clean to me.
The first example asks for unnecessary information, but is structured in a way that appears "natural" to the consumer (individual items from a collection are retrieved via lower leafs)
The second example only asks for necessary information, but isn't structured in a "natural" way - subcollections are accessible via roots
The individual employee root would not work when adding a new employee, as we need to know which business to add the employee to, which means that call would at least have to reside under the Business root, such as POST Api/Businesses/X7N7/Employees, which makes everything even more confusing.
Is there a cleaner, third way that I'm not thinking of?
I don't see how REST adds a constraint that two resources could not have the same value. The resourceType/ID is just an example of the easiest use case rather than the best way to go from a RESTful point of view.
If you read paragraph 5.2.1.1 of Roy Fielding's dissertation carefully, you will notice that Fielding makes the disctinction between a value and a resource. Now a resource should have a unique URI, that's true. But nothing prevents two resources from having the same value:
For example, the "authors' preferred version" of an academic paper is a mapping whose value changes over time, whereas a mapping to "the paper published in the proceedings of conference X" is static. These are two distinct resources, even if they both map to the same value at some point in time. The distinction is necessary so that both resources can be identified and referenced independently. A similar example from software engineering is the separate identification of a version-controlled source code file when referring to the "latest revision", "revision number 1.2.7", or "revision included with the Orange release."
So nothing prevents you from, as you say, changing the root. In your example, a Business is a value not a resource. It is perfectly RESTful to create a resource which is a list of "every business located in a city" (just like Roy's example, "revisions included with the Orange release"), while having a "business which ID is x" resource as well (like "revision number x").
For Employees, I would keep API/Businesses/X7N/Employees as the relation between a business and its employees is a composition relationship, and thus as you say, Employees can and should only be accessed through the Businesses class root. But this is not a REST requirement, and the other alternative is perfectly RESTful as well.
Note that this goes in pair with the application of the HATEAOS principle. In your API, the list of Businesses located in a city could (and perhaps should from a theoretical point of view) be just a list of links to the API/Businesses. But this would mean that the clients would have to do one round-trip to the server for each of the items in the list. This is not efficient and, to stay pragmatic, what I do is embed the representation of the business in the list along with the self link to the URI that would be in this example API/Businesses.
You should not confuse REST with the application of a specific URI naming convention.
HOW the resources are named is entirely secondary. You are trying to use HTTP resource naming conventions - this has nothing to do with REST. Roy Fielding himself states so repeatedly in the documents quoted above by others. REST is not a protocol, it is an architectural style.
In fact, Roy Fielding states in his 2008 blog comment (http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven 6/20/2012):
"A REST API must not define fixed resource names or hierarchies (an obvious coupling of
client and server). Servers must have the freedom to control their own namespace. Instead,
allow servers to instruct clients on how to construct appropriate URIs, such as is done in
HTML forms and URI templates, by defining those instructions within media types and link relations."
So in essence:
The problem you describe is not actually a problem of REST - conceptually, it is a problem of HIERARCHY STRUCTURES versus RELATIONAL STRUCTURES.
While a business is "in" a city and so can be considered to be part of the city "hierarchy" - what about international companies which have offices in 75 cities. Then the city suddenly becomes the junior element in a hierarchy with the business name at the senior level of the structure.
The point is, you can view data from various angles, and depending on the viewpoint you take, it may be simplest to see it as a hierarchy. But the same data can be seen as a hierarchy with different levels. When you are using HTTP type resource names, then you have entered a hierarchy structure defined by HTTP. This is a constraint, yes, but it's not a REST constraint, it's a HTTP constraint.
From that angle, you can chose the solution which fits better to your scenario. If your customer cannot supply the city name when he supplies the company name (he may not know), then it would be better to have the key with only city name. As I said, it's up to you, and REST won't stand in your way ...
More to the point:
The only real REST constraints you have, if you have already decided to use HTTP with GET
PUT and so on, are:
Thou shalt not presumeth any prior ("out of band") knowledge between client and servers. *
Look at your proposal #1 above in that light. You assume that customers know the keys for the cities which are contained in your system? Wrong - that's not restful. So the server has to give the list of cities as a list of choices in some way. So are you going to list every city in the world here?
I guess not, but then you'll have to do some work on how you are planning to do this, which brings us to:
A REST API should spend almost all of its descriptive effort in defining the media type(s) used for representing resources and driving application state ...
I think, reading the mentioned Roy Fielding blog will help you out considerably.
In a RESTful-API URL design should be quite unimportant - or at least a side issue since the discoverability is encoded in the hypertext and not in the URL path. Have a look at the resources linked in the REST tag wiki here on StackOverflow.
But if you want to design human readable URLs for your UC, I would suggest the following:
Use the resource type you are creating/updating/querying as the first part of the URL (after your API prefix). So when somebody sees the URL he immediately knows to which resources this URL points. GET /Api/Employees... is the only only way to receive Employee resources from the API.
Use Unique IDs for each resource independent of the relations they are in. So GET /Api/<CollectionType>/UniqueKey should return a valid resource representation. Nobody should have to worry where the Employee is located. (But the returned Employee should have the links to the Business (and for convenience sake City) he belongs to.) GET /Api/Employees/Z6W returns the Employee with this ID no matter where is is located.
If you want to get a specific resource: Put your query parameter at the end (instead in the hierarchical order described in the question). You can use the URL query string (GET /Api/Employees?City=X7N) or a matrix parameter expression (GET /Api/Employees;City=X7N;Business=A4X,A5Y). This will allow you to easily express a collection of all Employees in a specific City - independent of the Business they are in.
Side node:
In my experience an initial hierarchical domain data model seldom survives additional requirements that come up during a project. In your case: Consider a business located in two Cities. You could create a workaround by modelling it as two separate businesses but what about the employee who works half his time in one place and the other half at the other location? Or even worse: It's only clear for which business he works but it's undefined, in which city?
The third way that I see is to make Businesses and Employees root resources and use query parameters to filter collections:
GET Api/Businesses?city=ABC (returns all Businesses in City ABC)
GET Api/Businesses/X7N (returns business X7N)
GET Api/Employees?businesses=X7N (returns all employees at business X7N)
PUT Api/Employees/WWW (updates employee WWW)
Your both solutions use concept of REST sub-resources which requires that subresource is included in parent resource so:
GET Api/City/ABC/Businesses
in response should also return data provided by:
GET Api/City/ABC/Businesses/X7N
GET Api/City/ABC/Businesses/X7N/Employees
similar for:
GET Api/Businesses/X7N
which should return data provided by:
GET Api/Businesses/X7N/Employees
It will make size of the response huge and time required to generate will increase.
To make REST API clean each resource should have only one bounded URI which fallow below patterns:
GET /resources
GET /resources/{id}
POST /resources
PUT /resources/{id}
If you need to make links between resources use HATEOAS
Go with example 1. I wouldn't worry about unnecessary information from the point of view of the server. A URL should clearly identify a resource in a unique fashion from the point of view of the client. If the client would not know what /Employee/12 means without first knowing that it is actually /Businesses/X7N/Employees/12 then the first URL seems redundant.
The client should be dealing with URLs rather than the individual parameters that make up the URLs, so there is nothing wrong with long URLs. To the client they are just strings. The server should be telling the client the URL to do what it needs to do, not the individual parameters that then require the client to construct the URL.
The task: I have multiple resources that need to be updated in one HTTP call.
The resource type, field and value to update are the same for all resources.
Example: have set of cars by their IDs, need to update "status" of all cars to "sold".
Classic RESTFul approach: use request URL something like
PUT /cars
with JSON body like
[{id:1,status:sold},{id:2,status:sold},...]
However this seems to be an overkill: too many times to put status:sold
Looking for a RESTful way (I mean the way that is as close to "standard" rest protocol as possible) to send status:sold just once for all cars along with the list of car IDs to update. This is what I would do:
PUT /cars
With JSON
{ids=[1,2,...],status:sold} but I am not sure if this is truly RESTful approach.
Any ideas?
Also as an added benefit: I would like to be able to avoid JSON for small number of cars by simply setting up a URL with parameters something like this:
PUT /cars?ids=1,2,3&status=sold
Is this RESTful enough?
An even simpler way would just be:
{sold:[1,2,...]}
There's no need to have multiple methods for larger or smaller numbers of requests - it wastes development time and has no noteable impact upon performance or bandwidth.
As far as it being RESTful goes, as long as it's easily decipherable by the recipient and contains all the information you need, then there's no problem with it.
As I understand it using put is not sufficient to write a single property of a resource. One idea is to simply expose the property as a resource itself:
Therefore: PUT /car/carId/status with body content 'Sold'.
Updating more than one car should result in multiple puts since a request should only target a single resource.
Another Idea is to expose a certain protocol where you build a 'batch' resource.
POST /daily-deals-report/ body content {"sold" : [1, 2, 3, 4, 5]}
Then the system can simply acknowledge the deals being made and update the cars status itself. This way you create a whole new point of view and enable a more REST like api then you actually intended.
Also you should think about exposing a resource listing all cars that are available and therefore are ready for being sold (therefore not sold, and not needing repairs or are not rent).
GET /cars/pricelist?city=* -> List of all cars ready to be sold including car id and price.
This way a car do not have a status regarding who is owning the car. A resource is usually independent of its owner (owner is aggregating cars not a composite of it).
Whenever you have difficulties to map an operation to a resource your model tend to be flawed by object oriented thinking. With resources many relations (parent property) and status properties tend to be misplaced since designing resources is even more abstract than thinking in services.
If you need to manipulate many similar objects you need to identify the business process that triggers those changes and expose this process by a single resource describing its input (just like the daily deals report).