> For a clean and conscice structure, you should always use nouns.
Well, yeah, it's what everyone says, but not so easy to do in practice. Especially in complex apps there's a lot of stuff that isn't actually creating, updating or deleting an object, it is semantically an action. Say, action "send email" (and not some random email, but related or even defined by some business object you are referring to). Or in bookkeeping apps you often need something like "recalculate", which you probably wouldn't like to think of as "updating" because it isn't "take these values and apply to that object", but rather "hey, it's time to make some decision: please run some process (probably, with side effects) and tell us what the result is". Or it might be an action like "moveToQueue<Name>". Or better yet, you explicitly are telling your system to make some interaction with third-party service which is essentially imperative (like GDS, or some external trading API or whatever that isn't an object for your system, but really more like a service for which your app is just a friendly gateway). It is a little bit hard to think of good example right away, because if there is action "purchaseTicket" and there's no object "ticket" in your system you might ask WHY there's no object ticket in your system, but in all specific enough systems there always are situations like this, and mostly for some good reason. And yeah, there's also decisions made for performance sake or simplicity of client-app (like some frontend-side "action queue" so that you can use reactive programming on front-end in more natural way).
So what do I do then? All URLs like "/user/123/order[s]"(PUT,GET,...), "/product/321/comment[s]"(PUT,GET,...) and, suddenly "/sale/copyToAnotherService"? Now that kind of inconsistency is something I really don't like.
…And while I was writing the last one I though about: how should look url for something like "getRecommendedProducts" which depends on both user and product?
Now writing nouns/action names is a bit messy and so not-RESTful, but you always are able to write exactly what you mean by that request.
You know that the verb mechanism is extensible, right?
If your API could benefit from a particular verb (SEARCH, MOVE, CHECKOUT), just use it. You don't need (more) permission from (another) RFC - RFC 2616 and 7231 [1] already gave you permission to add verbs.
Most libraries and tools support arbitrary verbs including `XMLHttpRequest` and `curl`. Yes, there are a few libraries and frameworks that don't easily support arbitrary verbs, but the ones that have added support for PATCH generally have opened up.
Look, there are two Internets. One for people and one for machines. Our RESTful APIs are intended for consumption by machines, not people. You don't have to wedge everything into GET and POST and abuse query parameters to convey what you really mean.
Yes, of course there are situations when you shouldn't use a custom verb.
- Routes that intended for use by people via clickable links (web browsers and email clients) obviously must use GET; I believe HTML forms are likewise limited to GET and POST by the `method` attribute (I've never submitted a PATCH form myself).
- You may have to interop with intermediate proxies that perform some form of DPI. For example, some proxies know that certain requests can be cached based on a URI. These proxies may not have support for custom verbs.
- Corporate firewalls may whitelist verbs [1].
In general, the idea is to strive to use verbs that have broad applicability in your API, but that doesn't mean every resource must implement every verb (e.g. read-only collections usually don't implement DELETE). But that's just an standard application of the uniform access principle.
He's not talking about a framework, he's talking about web application firewalls that only support the default verbs. It's quite common and has nothing to do with which framework you use.
Thanks for clearing that up, yes, as I've said, you should not use custom verbs if you have to interop with firewalls or proxy caches that perform DPI unless you've tested them.
Problem is that you may test the system now and it all works fine. But the day after you deploy, somebody named Murphy adds or updates a proxy somewhere in your topology that breaks things. Or your organization gets a new customer or partner with a differently configured network.
Your request may go through proxy servers that do not recognize these verbs. Or users of your API may be stuck with an outdated framework that simply doesn't allow them.
Keep things sane and stick to GET/POST/PUT/DELETE.
Well, as its name implies, REST is intended for resources, and is basically a "database on the Web". There is nothing wrong with using other types of Web services -- particularly those based on procedures and messages -- where appropriate. Religiously adhering to "pure REST" just because it's en vogue is as dangerous as ignoring it completely.
EDIT: If we consider adding methods to HTTP, it is easy to imagine a new method, named say CALL or RUN, which would allow arbitrary procedures to be run bound to the requested resource, allowing for a sort of "object-oriented" RPC over REST...
This reflects my experience as well - most (all?) literature and presentations on REST cover extremely simple use cases, and when you start building complex applications things start to get ... complicated, and you discover that there aren't really any REST best practices to fall back on.
If anyone has anything on implementing more complex REST APIs, I'd be interested in reading it.
the "type" of products you want is a sub-set of all products (recommended). For differentiators I think using params is good. You can then do something like:
GET /product/recommended?user_id={user_id}&rating=5
Usually actions can be thought of as a consequence of a state change. For example, instead of exposing an API to send an email related to some business object, your backend should know to send an email when some corresponding state requires it.. e.g., send notification email when an order is created.
But often it is the opposite. Say, it is backend app and users are sales agents. There appears to be need for them to have a button like "send email number 4 to client" which is standard pre-composed email with few variables defined by user. And later on somebody comes up with idea that when this email is sent there should happen few (up to 20) other things in the system, they all are linked to this "send email" action, but none of them is that major and well defined as creating an order or something like that, but more like "this object linked to this order should appear now in two more queues, also few requests to external systems are made to notify somebody that this user did that thing on that time" and so on. It's hard to decompose that because this email was really the most obvious and thus the key action, the most natural description of what happened. Business logic of backoffice apps tends to get really messy and there's pretty much no way to avoid it completely. Sent email actually is somewhat simple case as everybody knows what email is. The real problem with that kind of apps is that there's a lot of atomic (from users perspective) actions that actually are a hundred of seemingly unrelated other actions linked in one with some "name of that specific business procedure" which is traditional for your users but pretty much meaningless for a layman. There's just no way to define what happened in terms of "order created" and such: only some magic spell that defines this particular business procedure completely.
A POST to /email would be fine...you'd expect back a 201 Created.
To really do it, you'd want /emails instead of /email, and then you'd expect that you could access any given email by /emails/<id>, getting a 401 or 403 if you tried to access one that doesn't exist. Further, you could expect that you could then augment the email resource with a status flag, and then you could even sort for sent emails by /emails?status=sent_and_acknowleged or similar.
For your second case, a POST would be a little weird, unless it returned you a new stats_report. I'd suggest changing that to /stats_reports, and have it create a new stats_report object. To view latest, you'd GET /stats_reports/head or something.
It depends, but POST to /email is more like "create new email template". As for "recalculate" what I mean is completely different from report. It is that there's some specific state of some object, when all info is already in the system and user has no control over it, but some values (depending on other values that all are already there) are denormalized and specific command from competent user is required to make it happen. For example, thing we "recalculate" might be balance or comission, but it cannot happen automatically, as some human has to verify manually that some parts of that process have been done properly.
Well, yeah, it's what everyone says, but not so easy to do in practice. Especially in complex apps there's a lot of stuff that isn't actually creating, updating or deleting an object, it is semantically an action. Say, action "send email" (and not some random email, but related or even defined by some business object you are referring to). Or in bookkeeping apps you often need something like "recalculate", which you probably wouldn't like to think of as "updating" because it isn't "take these values and apply to that object", but rather "hey, it's time to make some decision: please run some process (probably, with side effects) and tell us what the result is". Or it might be an action like "moveToQueue<Name>". Or better yet, you explicitly are telling your system to make some interaction with third-party service which is essentially imperative (like GDS, or some external trading API or whatever that isn't an object for your system, but really more like a service for which your app is just a friendly gateway). It is a little bit hard to think of good example right away, because if there is action "purchaseTicket" and there's no object "ticket" in your system you might ask WHY there's no object ticket in your system, but in all specific enough systems there always are situations like this, and mostly for some good reason. And yeah, there's also decisions made for performance sake or simplicity of client-app (like some frontend-side "action queue" so that you can use reactive programming on front-end in more natural way).
So what do I do then? All URLs like "/user/123/order[s]"(PUT,GET,...), "/product/321/comment[s]"(PUT,GET,...) and, suddenly "/sale/copyToAnotherService"? Now that kind of inconsistency is something I really don't like.
…And while I was writing the last one I though about: how should look url for something like "getRecommendedProducts" which depends on both user and product?
Now writing nouns/action names is a bit messy and so not-RESTful, but you always are able to write exactly what you mean by that request.