REST API: Can nested URI co-exist with lookup by ID? - rest

Suppose I have a collection of "Orders".
(a) Orders are divided into three categories: "pending", "confirmed", "completed".
(b) Naturally, orders can be looked up by ID
Initially I thought of this URI scheme:
For (a):
GET /orders/:id
For (b):
GET /orders/pending
GET /orders/confirmed
GET /orders/completed
The problem with this approach is that there is a (very very rare) chance that an order will receive the ID "pending" (or "confirmed" or "completed"), in which case the URI /orders/pending becomes ill-defined.
The other alternative is to use: GET /orders_pending but this seems less elegant.
Any suggestions?

A solution that immediately came to mind was to use
GET /orders?category=pending HTTP/1.1
This works with a query and should be easy to implement on any server.
Resource's properties should not be used as url segments because ideally, every url segment represents a resource (or multiple), not a property. I think you already know that because you said it yourself
The problem with this approach is that there is a (very very rare)
chance that an order will receive the ID "pending" (or "confirmed" or
"completed"), in which case the URI /orders/pending becomes
ill-defined.
If you want to filter results based on the value of a property, using a query in the url is the way to go.
Also, as #mahemoff pointed out
It's possible to build on this, e.g. ?category=pending&paid=true, and
you can't really extend /orders/pending style of URL to cover all
possible query inputs.

Related

Add subcategories in a filtered API Restful resource

I'll give an example as the title might sound a bit confusing.
How to build a resource path for something like that:
GET /courses/?language=english&active=true/units
I want to filter the courses (not using an id as usually) and then get the units of this result. How would you do that? I guess using question marks between the path is not allowed.
That would depend a little on your DB schema of what is a "course" and a "unit". The whole point on using the RESTful way is to always build requests and urls resource-specific.
But let's say that one course has X units on it. Here's what i would do to make a RESTful path to that request:
Due to the path problem of filtering courses AND using the /unit suffix, it can be done by adding another query parameter that specifies what fields the request is supposed to return. Something like this:
GET /courses?language=english&active=true&fields=units
That would filter the courses, and then return only the 'units' field on the response. As i said, depending on your DB and models, if the units are not stored inside the courses, it would be a bad practice to get them by requesting a /courses path. In that case, first request the courses that match the desired filter, and then make another request to the /units context sending i.e the courses ID's as query parameters.

REST url for unique resource (url with singular ?)

I have a webserver with some configuration properties and I want to be able to change them using a REST API.
Example
{
"maxUsers" : 10,
"refreshPeriodInMin" : 5
}
I would like to represent this with a "configuration" object. According to REST principle I believe the best way to do it is :
GET/PUT/POST/DELETE /configurations/{id}
But in my case I have only one configuration object and I do not like the idea of have to query
GET /configurations
just for one object.
Because there is only one object the easiest solution I found is to use id=default
Would give something like
GET /configurations/default
Is there a better way to represent a "unique" resource ? As mentionned by djmorton in the comments would /configuration be correct in a REST world ?
Another solution I though about would be to have one object per property. This would give
GET /properties/maxUsers
Problem with that solution is that you need to know the name of property to be able to query it. PLus you will make several queries if you have multiple changes to make.
Keep the resource singular if it truly represents a singular thing. If you will only have one, there is no reason not to simply PUT to that resource when you want to create or update it, and GET from that resource when you want to retrieve it.
If it can not be deleted, return a 405 METHOD NOT ALLOWED on DELETE requests. If it can be deleted, a DELETE request to that resource is acceptable, after which GET requests can return a 404 NOT FOUND.
In many ways, adding an id element to the path like /configuration/default would probably confuse users because they might expect that they would be able to POST new configurations to /configuration in addition to the default one.
The key is to do something that is sensible and intuitive to consumers of the API.

POST to get REST resource - three approaches - which one would you recommend?

I have REST resource (Ex: Tickets). To be able to obtain a set of Tickets that match a given set of constraints (Ex: start date, end date, price and other criterion) a user will need to pass information. This information can be included as query parameters and the protocol can define:
GET: Tickets?start-date=date&end-date=date&price=someprice...
The set of constraints to pass could be a lot.
In such situations, is it better to use a POST and pass the set of constraints as JSON object within the body?
POST: Tickets
Body:
{
"start-date": "date"
"end-date" : "date"
. . .
}
What are the drawbacks of such an approach? Does it still agree with the REST guidelines?Ref: http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven
Another alternative is the client could create a new resource called "Constraints" on the server, obtain a constraint-id (ex:123) as a response. Then it could use:
GET: Tickets?constraints-id=123
But this will mean that the server will periodically have to expire and delete "Constraint" objects, as clients might keep creating those without completing the business flow (ex: without confirming a Ticket in the end)
A third approach could be still use POST, but not create any resource. We can use a URI scheme like this:
POST: Tickets\Constraints
Body:
Body:
{
"start-date": "date"
"end-date" : "date"
. . .
}
Response:
200 OK ...
Tickets
This will mean that allthough no resource was created on the server, the need to POST the constraints to obtain Tickets is still made clear.
Which of these approaches would you recommend? What is most intuitive? Or is other any other alternative you would recommend?
Simply according to the HTTP spec, a POST is not a valid method to send a large amount of data for a query, as the intention is that the body of the request is to be stored by the server in some way, which is not the case in your example.
My current project faced the same problem and we decided to go with the more correct GET with many templated query parameters. Despite supporting over a dozen query params which can be quite long in length, most servers specify a GET request maximum length of 8KB, which I would expect to be an ample amount. I suppose this limit could be reached if you were attempting to send a GET with a large amount of the same query parameter to describe a long list, but if this is this case then it would suggest taking a step back and seeing how this has become a requirement of the API.
In my opinion a GET is the most intuitive and clearest use, and definitely seems to be the "correct" RESTful implementation. If the size of the request is an issue for you and you control the environment you are deploying to, you can even increase your server's max request size.
Yes, definitely OK and a good idea, especially if the post data is large, as it may exceed the max url length. It is better as part of the body of the message rather than on the url.

Using a POST method in WebApi rather than a GET method. Should I?

I have a REST API that provides access to a resource using GET.
Using this method I can get a specific instance or all instances.
In this case one instance isn't enough and all is too many.
What I've done is create a new Controller with a pattern like /api/filteredresource and made that a POST request with the body containing a representation of a filter to be used to limit the list of items returned.
I'm not looking for a "How do I..." answer, more a "Should I do it this way..." one.
What's the besrt practice here?
This StackOverflow article seems to suggest I shouldn't do it this way as the data canno (or rather should not) be cached but in this instance caching this filtered data doesn't make sense. I suppose I'm looking for a pragmatic answer rather than a technically correct one.
** EDIT **
The inital requirement was to just search for instances of the resource matching a particular status, but it seems that this was to be a 'first step'. They have a 'search key' that they want to use that contains all sorts of properies matching, in many cases, elements of the resource itself and they want to be able to use this 'search key' (or a representation of it) as the filter.
** END EDIT **
It's fine to use POST for any operation that isn't standardized, but retrieval of any kind is standardized and should be done with GET. As you figured, this depends on how pragmatic you want to be, and how much you want to stick to the standards.
If your problem is that the query string isn't readable or easy to represent, and you really want to stick to REST principles, you should have a query or filter resource subordinated to the filteredresource you want to filter, then it's semantically correct to make a POST with a body of filter parameters. This POST should return a 303 with a Location URI for a GET to the filteredresource, with a querystring that will yield the result you expect. Since this is generated by the API, and doesn't have to be readable, how easy it is to build or read shouldn't be an issue at this point. That URI will be cacheable and you'll be doing your retrieval with GET.
A compromise between pragmatism and purism is having that POST simply returning the result.
If you want to be pragmatic, just POST to `fiteredresource' and don't worry about it.
Use query parameters to filter:
GET /rest/things/1
gets the thing with id=1.
GET /rest/things
gets all things.
GET /rest/things?color=yellow
gets only the yellow things.

Handling long queries without violating REST

We have a REST api, and we've done a pretty good job at sticking to the spirit of REST. However, we have an important consumer, and they're requesting a way to reconcile their datastore. The flow works like this:
Consumer makes a GET call to retrieve all inventory objects created within a date range. Lets say this returns 1 million inventory VINs.
Consumer compares the payload with their own datastore, see's that they're missing 5,000 inventory objects
Consumer would like to make a request with the 5,000 VIN id's, and return those 5,000 objects.
The problem is that the long query string (JSON array of vins) bumps into the query string length limits imposed by our server. Possbile ideas - make 5k separate calls (seems horrible), increase querystring length limit on server (would like not to do this), use POST instead (not RESTful?).
So, I'm wondering what Roy Fielding would do...
What about a POST submitting the JSON file with the id's list to a new resource, e.g. called /inventory/difference?
If the computation goes any long, you can answer with 202 Accepted and the id of the resource being generated, then point back to it at /inventory/difference/:id.
Somewhat similar to what moonwave99 suggested, but instead you create a resource called a "set".
You POST to /set a list of identifiers that you wish to be in the set. The result of the POST is a redirect URL to the resource that names the specific set.
So:
POST /set
Result:
301 Moved Permanently
Location: /set/123
Then:
GET /set/123
Returns the list of items in the set.
Sets are orthogonal to the use case of "fetching differences", they're simply a compilation of items.
If the creation of a set takes a long time, and you consider the set itself to be a snapshot of the data, when the user tries to do the GET /set/123 can simply reply with a 202 Accepted until the actual dataset has been completed.
You can then use:
GET /set/123/identifiers
To get a collection of the actual identifiers in the set, for example, if you like.
You can do something like
POST /setfromquery
and send a list of criteria (name like "John*", city = "Los Angeles", etc.). This doesn't really need its own specific resource, just define your query "language" to include both simple lists of IDs as well as perhaps other filter criteria.
Set operations (unions, differences, etc.). Lots of powerful things can be done with a set resource.
Finally, of course, there's the ever popular:
DELETE /set/123
I don't think anyone would fault you in working around GET not accepting a request body by using POST for a request that needs a request body. You are just being pragmatic.
I agree, making 5000 individual requests or upping the query string limit are ugly. POST is the way forward.
Using a post without creating a resource just seemed too dirty for me. In the end, we made it so that there was a limit of 100 ids requested in a "chunk". In practice, these requests will rarely be > 100, so hacking REST principles to accomodate an edge case seemed like a bad idea. I made sure the limitation was clearly defined in our API docs, done and done...