5 ms·
> 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 comple
by krick 12y ago
> 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.
- baddox 12y agoFor sending an email, what's wrong with a POST to /email? For "recalculate," it seems like a POST to /stats_report would be reasonable.
- krick 12y agoIt 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.
- angersock 12y agoA 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.
- jamroom 12y agosince "product" is the item I would do: GET /product/recommended?user_id={user_id} 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 etc... Seems clean to me, but also is just my opinion.
- danielnaab 12y agoUsually 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.
- krick 12y agoBut 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.
- politician 12y agoYou 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. [1] http://tools.ietf.org/html/rfc7231#section-4.1 http://tools.ietf.org/html/rfc7231#section-4.1
- krick 12y agoIs it really safe and reliable? Are there any situations when I should NOT add my custom verb whenever I please?
- serve_yay 12y agoThat sounds like a recipe for heartburn later, when you run into some WAF or whatever that only allows PUT/GET/DELETE/POST.
- politician 12y agoThe cockroach that you see is usually not the only one around. A framework that doesn't support extensible verbs in 2014 is bound to have more problems than just a failure to implement one RFC correctly.
- orand 12y agoHe'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.
- vetler 12y agoThis 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.
- jonahx 12y agoThis book is very good: http://www.amazon.com/RESTful-Web-APIs-Leonard-Richardson/dp/1449358063/ref=sr_1_1?s=books&ie=UTF8&qid=1416285659&sr=1-1&pebp=1416285666917 http://www.amazon.com/RESTful-Web-APIs-Leonard-Richardson/dp...
- vetler 12y agoThis 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.
- vetler 12y agoThis 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.
- BerislavLopac 12y agoWell, 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...