Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

comment on

( [id://3333]=superdoc: print w/replies, xml ) Need Help??
I'm sorry in return for even hinting about using something other than JSON.

REST is still wrong (even though it is better than SOAP). I actually feel strongly enough about it that I will explain in length why for posterity's sake.

My post began with "use JSON POSTing over HTTPS. Always." Mistakenly I added an update to use "whatever" which you seem to have grasped onto. I stand by the first part: "use JSON POSTing over HTTPS. Always."

Here are my reasons why to consistently use JSON POSTing over HTTPS always rather than use REST:

You yourself mention that your "fairly half baked" REST services is "not particularly RESTy." This seems to happen often when people claim to follow REST. I have no doubt whatsoever that your solution you mentioned was absolutely brilliant (and I'm very glad you used REST instead of SOAP). But if it wasn't truly REST, or if even if it was, the client consumers likely had to write custom code.

If you do have a REST client in any language on any platform - it will work with my "JSON POSTing over HTTPS" because JSON POSTing over HTTPS RESTish (1/4th of REST).

If you don't have a REST client, it will take fewer lines of code and will be far more consistent to make your client speak to a consistent "JSON POSTing over HTTPS" than it will be to communicate with any REST based service.

If you are writing a web based service, and are using *any* library to do your REST work (such as Mojo or the other frameworks, or some custom service), you can use that very same service to do consistent JSON POSTing over HTTPS for every method.

If you intend to consume REST from the browser, you need a plugin to manage it. If you "always use JSON POSTing over HTTPS", it is easy to make beautiful unified API pages that make requests to the service (ajax consumption works just fine, but our consistent server layer also allows for normal x-www-urlencoded browser requests in addition to JSON POST for development and discovery purposes but we leave the normal client communication as JSON POSTing over HTTPS).

I have consumed many REST services and each time I have these thoughts: PUT and DELETE are contrived; but at least this isn't SOAP.

I don't like to use numbers to back up arguments, but we have at least 9 service APIs pulling over 12 million hits a day spiking to 20 million on some days (I know this is small compared to some shops). And they have consistently been doing this for over 7 years. Every single service is JSON POSTing over HTTPS. It is so consistent that our consuming code looks like this (seriously):
my $client = API::Client->new({service => "dist"}); my $data = $client->server_info({hostname => "foo.bar.com"}); # this maps out to https://someserver.com/dist/server_info POSTing +{"hostname":"foo.bar.com"}
It is so consistent that our server code looks like this (our methods are self documenting and discoverable):
package DistService; use API::Base; sub server_info__meta { return { desc => 'Returns information about a server', args => { server_id => {desc => 'The Id of this server', required => + 1}, }, resp => {success => 1}, }; } sub server_info { my ($self, $args) = @_; my %data; ... return \%data; }
The API::Client code ends up being simple wrappers around configuration and existing perl network libraries. And we have consumers around the world running on many varied platforms. And they all had an easy time consuming because we "always use JSON POSTing over HTTPS." Just like REST (but moreso) it is even trivial to use curl or wget if you use consistent JSON POSTing over HTTPS.

If you have commandline clients (every single one of our clients and servers has commandline interfaces) keeping the nouns and verbs in your consistent method names allows for calling the exact same method names on the commandline as you do in your API and even can keep them the same as listed in your code. You have to come up with new and creative ways of representing method names if you want to use REST since the noun and verb are separate. Here is a sample:

[rhandom@somehost ~/%] ds server_info hostname foo.bar.com Arguments: +----------+-------------+ | hostname | foo.bar.com | +----------+-------------+ Data: +---------------+---------------------+ | access_tag | MDEV | | added_by_uid | 33 | | date_added | 2013-09-27 09:17:47 | | description | - | | hostname | foo.bar.com | | ip | 0.0.6.11 | | server_id | 26208 | +---------------+---------------------+
Notice the client code, and the url, and the server code, and the commandline code all use the exact same method name - consistency will save time and frustration. You cannot do that with REST.

Our implementation of JSON POSTing over HTTPS is consistent enough and simple enough and clean enough that we will likely eventually release our API based code to CPAN, despite the plethora of existing RPC tools on CPAN already.

REST clients require you to determine which parts (if any) are the resource identifiers used in the URL, and which parameters are part of the JSON request, and then you have to keep your noun and verb separate. Consistent JSON POSTing over HTTPS allows for simple method/arg calls without having to do any parameter mapping.

REST PUT and DELETE responses do not return data (or shouldn't if you are following real REST). Typically it is *very* useful to actually get back information from a delete (such as rows deleted, or if the record was already gone, or if it is pending, etc). Consistent JSON POSTing over HTTPS allows for returning data with any type of action.

Lets look at the apache logs. Here is a tiny sampling from one of our lower hit services (with the ips munged to protect the innocent):
0.0.20.86 - - [27/Sep/2013:08:12:50 -0600] "POST /dist/server_info HTT +P/1.0" 200 292 "-" "-" 0.0.66.29 - - [27/Sep/2013:08:12:50 -0600] "POST /dist/unmanaged_add H +TTP/1.0" 200 21 "-" "-" 0.0.80.14 - - [27/Sep/2013:08:12:50 -0600] "POST /dist/undone_list HTT +P/1.0" 200 218214 "-" "-" 0.0.69.86 - - [27/Sep/2013:08:12:50 -0600] "POST /dist/unmanaged_add H +TTP/1.0" 200 21 "-" "-" 0.0.54.28 - - [27/Sep/2013:08:12:50 -0600] "POST /dist/unmanaged_add H +TTP/1.0" 200 21 "-" "-" 0.0.80.16 - - [27/Sep/2013:08:12:50 -0600] "POST /dist/undone_list HTT +P/1.0" 200 302337 "-" "-" 0.0.48.23 - - [27/Sep/2013:08:12:51 -0600] "POST /dist/unmanaged_add H +TTP/1.0" 200 21 "-" "-" 0.0.19.71 - - [27/Sep/2013:08:12:51 -0600] "POST /dist/server_info HTT +P/1.0" 200 290 "-" "-" 0.0.80.17 - - [27/Sep/2013:08:12:50 -0600] "POST /dist/undone_list HTT +P/1.0" 200 146432 "-" "-" 0.0.50.12 - - [27/Sep/2013:08:12:51 -0600] "POST /dist/server_info HTT +P/1.0" 200 294 "-" "-" 0.0.27.29 - - [27/Sep/2013:08:12:51 -0600] "POST /dist/server_info HTT +P/1.0" 200 293 "-" "-" 0.0.19.22 - - [27/Sep/2013:08:12:51 -0600] "POST /dist/server_info_fil +es HTTP/1.0" 200 30321 "-" "-" 0.0.58.10 - - [27/Sep/2013:08:12:51 -0600] "POST /dist/unmanaged_add H +TTP/1.0" 200 21 "-" "-" 0.0.19.22 - - [27/Sep/2013:08:12:51 -0600] "POST /dist/unmanaged_add H +TTP/1.0" 200 21 "-" "-" 0.0.63.83 - - [27/Sep/2013:08:12:51 -0600] "POST /dist/unmanaged_add H +TTP/1.0" 200 21 "-" "-" 0.0.86.42 - - [27/Sep/2013:08:12:51 -0600] "POST /dist/server_info HTT +P/1.0" 200 273 "-" "-" 0.0.24.47 - - [27/Sep/2013:08:12:52 -0600] "POST /dist/server_info HTT +P/1.0" 200 292 "-" "-" 0.0.44.15 - - [27/Sep/2013:08:12:52 -0600] "POST /dist/server_info HTT +P/1.0" 200 294 "-" "-" 0.0.33.11 - - [27/Sep/2013:08:12:52 -0600] "POST /dist/server_info HTT +P/1.0" 200 293 "-" "-" 0.0.15.80 - - [27/Sep/2013:08:12:52 -0600] "POST /dist/server_info HTT +P/1.0" 200 290 "-" "-"
Here is what the equivalent looks like if it was REST:
0.0.20.86 - - [27/Sep/2013:08:12:50 -0600] "GET /dist/server/32 HTTP/1 +.0" 200 292 "-" "-" 0.0.66.29 - - [27/Sep/2013:08:12:50 -0600] "POST /dist/unmanaged/33 HT +TP/1.0" 200 21 "-" "-" 0.0.80.14 - - [27/Sep/2013:08:12:50 -0600] "GET /dist/undone HTTP/1.0" + 200 218214 "-" "-" 0.0.69.86 - - [27/Sep/2013:08:12:50 -0600] "POST /dist/unmanaged/32 HT +TP/1.0" 200 21 "-" "-" 0.0.54.28 - - [27/Sep/2013:08:12:50 -0600] "POST /dist/unmanaged/32 HT +TP/1.0" 200 21 "-" "-" 0.0.80.16 - - [27/Sep/2013:08:12:50 -0600] "GET /dist/undone HTTP/1.0" + 200 302337 "-" "-" 0.0.48.23 - - [27/Sep/2013:08:12:51 -0600] "POST /dist/unmanaged/23 HT +TP/1.0" 200 21 "-" "-" 0.0.19.71 - - [27/Sep/2013:08:12:51 -0600] "GET /dist/server/36 HTTP/1 +.0" 200 290 "-" "-" 0.0.80.17 - - [27/Sep/2013:08:12:50 -0600] "GET /dist/undone HTTP/1.0" + 200 146432 "-" "-" 0.0.50.12 - - [27/Sep/2013:08:12:51 -0600] "GET /dist/server/31 HTTP/1 +.0" 200 294 "-" "-" 0.0.27.29 - - [27/Sep/2013:08:12:51 -0600] "GET /dist/server/38 HTTP/1 +.0" 200 293 "-" "-" 0.0.19.22 - - [27/Sep/2013:08:12:51 -0600] "GET /dist/server/32_files +HTTP/1.0" 200 30321 "-" "-" 0.0.58.10 - - [27/Sep/2013:08:12:51 -0600] "POST /dist/unmanaged/23 HT +TP/1.0" 200 21 "-" "-" 0.0.19.22 - - [27/Sep/2013:08:12:51 -0600] "POST /dist/unmanaged/25 HT +TP/1.0" 200 21 "-" "-" 0.0.63.83 - - [27/Sep/2013:08:12:51 -0600] "POST /dist/unmanaged/26 HT +TP/1.0" 200 21 "-" "-" 0.0.86.42 - - [27/Sep/2013:08:12:51 -0600] "GET /dist/server/38 HTTP/1 +.0" 200 273 "-" "-" 0.0.24.47 - - [27/Sep/2013:08:12:52 -0600] "GET /dist/server/33 HTTP/1 +.0" 200 292 "-" "-" 0.0.44.15 - - [27/Sep/2013:08:12:52 -0600] "GET /dist/server/34 HTTP/1 +.0" 200 294 "-" "-" 0.0.33.11 - - [27/Sep/2013:08:12:52 -0600] "GET /dist/server/38 HTTP/1 +.0" 200 293 "-" "-" 0.0.15.80 - - [27/Sep/2013:08:12:52 -0600] "GET /dist/server/33 HTTP/1 +.0" 200 290 "-" "-"
REST *can* or *might* win here if you care about seeing the resource id (which I have greatly simplified in this REST example). However if I'm using most log analyzation tools or even live log viewing tools including toys like logstalgia, the consistent POST over HTTPS wins because the URL includes the noun AND the verb.

REST cares too much about your abstractions and object representation. Consistent JSON POSTing over HTTPS doesn't care if you have a ${noun}_${verb} method or if you have a ${this_method_does_not_fit_anywhere} method. But it is always JSON POSTing over HTTPS. Should that random this_method_does_not_fit_anywhere method be a GET, a POST, a PUT, or a DELETE? - maybe it is just a method without object representation. Worse, what if my method updated *and* deleted a resource - which REST verb should I use? What a bout an import method that doesn't follow our normal and possibly even manages multiple resources at once? Consistent JSON POSTing over HTTPS does not care what your methods are. Conversly, you're not really REST unless you follow object abstractions to the letter.

The only real benefits to REST are the ability to pull GET resources (assuming there is no authentication) directly from a browser (which you typically are not doing), and the ability to have a tiered system with caching based on URL alone (which I have never seen any company actually do in practice).

I stand by the advice to always use JSON POSTing over HTTPS and to avoid REST. REST does not give you the benefits you think it does - but REST does put more work on the client consumers of your API.

my @a=qw(random brilliant braindead); print $a[rand(@a)];

In reply to Re^3: modern ways of doing web services - avoid REST too by Rhandom
in thread modern ways of doing web services by Anonymous Monk

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":



  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or How to display code and escape characters are good places to start.
Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others avoiding work at the Monastery: (6)
As of 2024-04-18 06:19 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found