I'm interested in the correct convention to use when requesting a calculation on an entity from the server. That is - a specific entity is involved, but its data is not returned. Instead, a calculation based on the entity is returned.
Take for example a site that stores multiple clocks, each with a different offset/timezone value. The purpose of the site is to present images of analog clocks with hands pointing in the appropriate direction.
Using good convention I would expect to be able to do this:
POST /clocks
{
"offsetHours": 5
}
And I would receive this response:
201 (Created)
{
"id": "fe884d5e",
"offsetHours": 5
}
Now I would expect to be able to retrieve that clock object:
GET /clocks/fe884d5e
Which responds:
200 (OK)
{
"id": "fe884d5e",
"offsetHours": 5
}
This is all fine so far. But there are two other endpoints I would expect to have access to. The first one would return the current time calculated for a clock's offset. The second one would return image data displaying an analog clock based on the clock's current time.
My question is: what does convention dictate the GET requests for these data items should look like? Or is convention loose when it comes to dealing with calculated views of entities?
But there are two other endpoints I would expect to have access to. The first one would return the current time calculated for a clock's offset.
Something like
GET /clocks/fe884d53/localTime
The second one would return image data displaying an analog clock based on the clock's current time.
Something like
GET /clocks/fe884d5e/localTime/analogClock.jpg
or
GET /clocks/fe884d5e/analogClock.jpg
The key idea here is that these are information resources, in precisely the same way that the description of the clock itself is an information resource.
From the point of view of the consumer, the representation is just a document. There shouldn't be any way to know if the document was freshly generated, or copied from a document store, or pulled out of a web cache.
The fact that there is a calculation is just an implementation hidden behind the api.
Once you have clear the idea that these are different resources that share implementation details, the remainder of the work is just bike shedding (is it easy for our routing to find the right implementation? do we have the hierarchical data in the path segment, and the non hierarchical parts in the query, does the spelling look enough like a "resource" to conform with our local coding standards, etc).
Related
I have the following route with cars as a collection resource.
/api/v4/cars
/api/v4/cars/{carId}
Now I want to introduce a "Price per car", but this price is dependent on the input, not fixed. So when the user calls the pricing endpoint, it should send some data ex. color, enginse size etc. which then would determine the price for a car X.
My question now is, how this route should look like?
Does one of those make sense, what is the general approach one should take in such cases:
/api/v4/cars/{carId}/price
/api/v4/cars/{carId}/calculatePrice
/api/v4/cars/{carId}/getPrice
So when the user calls the pricing endpoint, it should send some data ex. color, engines size etc. which then would determine the price for a car X.
Sounds like submitting a web form; on the web, you would end up with the data appearing as encoded key value pairs in the URI.
GET /2c5d1cd4-0259-4c2b-9ca3-6215426732b8?color=red&transmission=automatic
Aside from the fact that browsers already know how to encode form values into a query string, there's no particular advantage to using a query; you could do path segments instead if you wanted to
GET /2c5d1cd4-0259-4c2b-9ca3-6215426732b8/color/red/transmission/automatic
Clients that understand how URI templates work can handle just about any layout of information you are interested in. HTML processing on the web isn't quite sophisticated enough to handle arbitrary uri templates; encoded key value pairs is a nice answer if you care about those use cases.
/api/v4/cars/{carId}/price
/api/v4/cars/{carId}/calculatePrice
/api/v4/cars/{carId}/getPrice
These are all "fine"; consumer code really doesn't care. A key idea to keep in mind is that a URI is an identifier; which is to say it is the name of the document (resource) that it fetches. If you have a clear understanding of your domain, it should be relatively straight forward to work out what the name of the document is, and choose an identifier spelling that makes understanding/remembering/guessing easier for human beings.
I want to implement a REST endpoint to figure out whether a particular item can be closed. How can I do it properly from the point of view of REST design?
/items/canbeclosed - sounds ugly
maybe something like
/items/status but I have already status endpoint used for another purpose
How can I do it properly from the point of view of REST design?
REST doesn't care what spelling you use for your URI.
It might help to think about what's true of the items now, rather than thinking about which actions are possible. For instance, if the items "can be closed" because they are "completed", then /items?completed or /items/completed or even '/completedItems' might be reasonable spellings.
Alternatively, perhaps these are tasks, sitting in a task queue, with different queues set up for your different stages. So something like /stages/closeItem/tasks might be the right thing.
Your touchstone, as with all things REST, is to imagine your API as a web site. If you had to navigate to a web page to access this information, what would the identifier of the web page be? and there you go.
You have several different possibilities depending on what you want to do specifically.
For getting whether a particular item can be closed, retrieve the item and have a field that answers this question:
GET /items/{itemNumber}
{
"canBeClosed": true,
...
}
You could also use a subresource for that particular field:
GET /items/{itemNumber}/can-be-closed
true
This would also be "resty" but it's only helpful in some edge cases. You wouldn't want to make a call over the network for every little piece of information. This would result in bad performance.
Note that the solutions above point to a single resource identified by its ID. Have a look at restapitutorial.com for the difference between collection resources and item resources.
Maybe you want to get a list of the items which are closable:
GET /items?closable=true
In this case I'd like using a matrix param more:
GET /items;closable=true
Matrix params are much like query params except that they are bound to a particular path element rather than to the end result. So you can have something like this:
GET /customers;country=Germany/orders
which would return the orders of customers living in Germany. This is not possible with query params as they are always added to the end. So in my eyes they are better for paging and sorting while matrix params are better for filtering.
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).
I'm coming from the RPC world but currently investigating if using REST is a good idea for my project. As for as I understand from Wikipedia the basic idea of RESTful services is to provide access to collections and their individual elements.
In my case the server would be a measuring instrument. I must be able to start, stop, and pause the measurement routine, and read the data at any time.
Currently, I'm considering the following:
POST /measure (start measurement, this continues until stopped by the user)
PUT /measure pause=true/false (pause/unpause)
DELETE /measure (stop)
GET /measure (get measurement data)
However, I'm not sure if this fits the REST model, since I don't really work with collections or elements here.
My question: How would I access a singleton resource and do the start/stop requests to the server break the RESTful stateless constraint?
Not RESTful
No, your approach isn't RESTful, because if I understand the workflow, you would delete the resource to stop the measurement and then get the resource to read out the final result. But deleting a resource implies that there would be nothing left to GET.
The fact that your resource is a singleton isn't a problem at all. The problem lies in the way you're mapping verbs and state.
Your description is a bit abstract, so let's be a bit more concrete: let's assume that the instrument in question measures the angular velocity of a fly wheel in radians/sec. This instrument has some cost associated with measurement, so the client needs to be able to disable measurement for some periods of time as a cost-saving measure. If this is roughly analogous to your scenario, then the exposition below should be applicable to your scenario.
Verbs
Now, let's review your verbs.
GET returns a representation of a resource. So when you GET /measure, it should return some data that represents the current measurement.
PUT creates or updates a specific, named resource. The resource is named by its URL. So PUT /measure implies that you're updating the state of a resource called /measure, or creating that resource if it doesn't already exist. In your case, the instrument value is read-only: we can't write a radian/sec value to the instrument. But the paused/active state of the instrument is mutable, so PUT /measure should include a body that modifies the state of the instrument. You could use a lot of different representations here, but one simple approach would be a request body like active=true or active=false to indicate what thew instrument's new state should be.
POST is similar to PUT, except that the client does not specify the name of the resource that should be created or updated. In a different API, for example, the client might POST /articles to create a new a article. The server would create a resource and give it a name like /articles/1234 and then it would tell the client about this new name by returning a 201 CREATED HTTP code and adding a Location: /articles/1234 header to tell the client where the new resource is. In your scenario, POST isn't a meaningful verb because you always know what the name of your singleton resource is.
DELETE means you remove a resource, and since a resource is identified by a URL, DELETE /measure implies that /measure no longer exists. A subsequent GET /measure should return either 404 NOT FOUND or 410 GONE. In your case, the client can't actually destroy the instrument, so DELETE isn't meaningful a meaningful verb.
Conclusion
So in sum, a RESTful design for your service would be to have PUT /measure with a request body that tells the instrument whether it should be active or not active (paused) and GET /measure to read the current measurement. If you GET /measure on a paused instrument, you should probably return a 409 CONFLICT HTTP status. Your service shouldn't use POST or DELETE at all.
You are still working on a resource, and the way you broke it down sounds good to me. Fielding explicitly mentions temporaral services in the REST chapter:
The key abstraction of information in REST is a resource. Any
information that can be named can be a resource: a document or image,
a temporal service (e.g. "today's weather in Los Angeles")
Maybe it would make sense to give each measurement a unique id though. That way you can uniquely refer to each measurement (you don't even have to store the old ones, but if someone refers to an old measurement you can tell them, that what they are requesting is not up to date anymore).
Building upon the last answer. Here is how you might want to break it down
measures/ - GET all the measures from the instrument (Paginate/limit if needed based on query params)
measures/:measure_id - GET a particular measure
measures/ - POST - Starts a new measure. This returns the new measure ID which you can deal with later.
measures/:measure_id - DELETE - stop the measure.
measures/:measure_id - PUT - update the measure
measures/last_measure - Last measured resource.
Let's say I have a RESTful, hypertext-driven service that models an ice cream store. To help manage my store better, I want to be able to display a daily report listing quantity and dollar value of each kind of ice cream sold.
It seems like this reporting capability could be exposed as a resource called DailyReport. A DailyReport can be generated quickly, and there doesn't seem to be any advantage to actually storing reports on the server. I only want a DailyReport for some days, other days I don't care about getting a DailyReport. Furthermore, storing DailyReports on the server would complicate client implementations, which would need remember to delete reports they no longer need.
A DailyReport is transient; its representation can be retrieved only once. One way to implement this would be to offer a link "/daily-reports", a POST to which will return a response containing a DailyReport representation listing the information for that day's sales.
Edit: Let's also say that I really do want to do a POST request. A DailyReport has many different options for creating a view such as sorting ice cream types alphabetically, by dollar value - or including an hourly breakdown - or optionally including the temperature for that day - or filtering out certain ice cream types (as a list). Rather than using query parameters with a GET, I'd rather POST a DailyReport representation with the appropriate options (using a well-defined custom media type to document each option). The representation I get back would display my options along with the report itself.
Is this the correct way to think about the problem, or should some other approach be used instead? If correct, what special considerations might be important when implementing the DailyReport resource? (For example, it probably wouldn't be appropriate to set the Location header when returning after a POST request).
If you want to make daily reports for past days available, you could implement it as a GET to /daily_reports/2009/08/20. I agree with John Millikin that a POST is unnecessary here - there's no need for something like this to be a user-creatable resource.
The advantage of making the report for each day available as its own URI is cacheability.
EDIT: A good solution might be to merge the two answers, making daily_report/ a no-cache representation of the current day's data and daily_reports/yyyy/mm/dd a cacheable representation of a full day's data.
There's no need to use a POST for this, since requesting the report doesn't change the state of the server. I would use a resource like this:
GET /daily-report/
200 OK
Pragma: no-cache
<daily-report for="2009-04-20" generated-at="2009-4-20T12:13:14Z">
<!-- contents of the report here -->
</daily-report>
Responding to your edit: if you are POSTing a description of the report to a URL, and retrieving a temporary data set as a result, that's not REST at all. It's RPC, in the same vein as SOAP. RPC is not an inherently bad thing, but please, please don't call it RESTful.
Sometimes it is desirable to keep a record of requests for reports, in those cases it is not unreasonable to POST to a collection resource. It is also useful for long running reports where you want handle the execution asynchronously. How long the server holds onto those report requests is up to you.
I would do something like
POST /DailyReportRequests
which would return a representation of the request, including options, and when the report is completed, a link to the report results.
Another alternative which is good when you have a set of pre-canned reports is to create a DailyReports resource that contains a list of preconfigured report links. The OpenSearchDescription spec allows you to do something similar to this using the Query tag.
I think Greg's approach is the correct one. To expound upon it, I don't think you should provide a /daily-report resource that changes daily, because running the report on Tuesday at 11:59 would yield different results than running it Wednesday at 00:01, which can be A) confusing for clients expecting the resource to be the same, and B) doesn't allow clients to retrieve a previous day's data after the day has passed. You should provide a unique resource identifier for each daily report that's available, that way clients can access the information they need at any time.