PDA

View Full Version : Direct or REST which is the best? :-)



misha
25 Jun 2009, 12:58 AM
Hi guys,

My big dilemma is whether should I use:
1. Ext.direct and its PHP provider
2. or Zend framework that generates appropriate REST pages for Ext.

Is the main difference deciding whether I want my server API to be RPC or REST?

Are there any drawbacks in using direct btw?

dj
25 Jun 2009, 3:19 AM
If your backend needs to communicate with other systems that support RESTful services then you should implement a REST interface. Besides that REST interface I would implement an Ext.Direct router that is the central place for all ExtJS communication. The benefit of having this central router is that you can batch several requests so that only one HTTP request is sent to the server. You cannot do that with directly using the REST interface of your backend but if your application makes many small requests (as it probably would if you use a REST architecture) it greatly benefits from batching requests.

If your backend is only used with your ExtJS frontend then don't bother implement a REST interface.

misha
25 Jun 2009, 3:43 AM
Thanx dj,

The thing is that I would like to publish API interface of my backend for others to use too, so REST would be a bit more logical for that.

You gave batching as main reason for using direct. But isn't batching possible with REST approach too?

I can set autoSave to false on my restful store, and call save() by hand, so all changes to the store will be submitted in one call as opposed to multiple calls if autoSave is true, right?

dj
27 Jun 2009, 2:09 AM
The thing is that I would like to publish API interface of my backend for others to use too, so REST would be a bit more logical for that.


Sure, REST is widely used and as such is a better fit for a public API. However, using Ext.Direct as an router between your REST interface and your ExtJS frontend makes sense...



You gave batching as main reason for using direct. But isn't batching possible with REST approach too?

I can set autoSave to false on my restful store, and call save() by hand, so all changes to the store will be submitted in one call as opposed to multiple calls if autoSave is true, right?

... because HTTP request batching is not possible with REST. It's quite a core concept of REST that each resource has a unique URI. If you want to update user 1 and user 2 you have to POST to /my/RESTful/interface/user/1 and /my/RESTful/interface/user/2. That are 2 HTTP requests and you cannot batch them into one. If you did that it wouldn't be REST anymore.

If you call save() on a batchSave:true, restful:true store, it will generate multiple HTTP requests. One for each updated/newly created/deleted record. Calling save() on a Ext.Direct enabled store with batchSave:true only generates one HTTP request regardless of how many updated, new or deleted records are in that store.

grzegorz.borkowski
27 Jun 2009, 12:31 PM
You can do batching with REST, using WebDAV extensions. See for example HTTP status code 207 created for this purpose.

dj
27 Jun 2009, 1:09 PM
You can do batching with REST, using WebDAV extensions. See for example HTTP status code 207 created for this purpose.

Do you have more information about this? HTTP status code 207 is a response code. How would one do a request that should return this response code? As far as I understand [1] and [2] one would need one single URL that the request has to go to and you would also need some sort of a router on the server. AFAIK such a router is not part of a REST interface.



[1] http://www.webdav.org/specs/rfc2518.html#multi-status.response
[2] http://restpatterns.org/HTTP_Status_Codes/207_-_Multi-Status

grzegorz.borkowski
27 Jun 2009, 1:24 PM
Yes, you need some filter/proxy on the server facade which acts as splitter for incoming requests, and as aggregator for outcoming responses. If it is REST interface or not, it depends how you define REST :) For details how to use such batching, you should probably look at WebDAV specifications. Also as far as I know Subversion uses WebDAV, so perhaps you can find some examples in SVN documentation.
But I never used this feature personally, so I'm not a competent person to give you much help on this topic.

Nalfein
27 Jun 2009, 5:12 PM
Are there any drawbacks in using direct btw?

You lose simplicity, browser caching and scalability.

The argument with batching request is a red herring in the discussion. REST supports batch requests natively at HTTP level, using persistent connections! All modern browsers support that. All you have to do is to send appropriate headers.

When you make proper use of browser caching you will gain another boost in performance.

I don't know why Ext's creators decided to use a RPC solution. It is a step back.

mnovakovic
28 Jun 2009, 2:50 AM
I guess that we all agree on that any good application should have some kind of API exposed over REST, which is currently widely accepted "standard" (not to say that is ql).

So if i need to use REST for this purpose why should i use Direct and how should i use it because i would then need 2 points of access for clients which can be hard to maintain at some point...

dj
28 Jun 2009, 3:27 AM
You lose simplicity, browser caching and scalability.


Simplicity and browser caching I understand and I (at least with browser caching) agree with. Could you elaborate on why one would loose scalability?



The argument with batching request is a red herring in the discussion. REST supports batch requests natively at HTTP level, using persistent connections! All modern browsers support that. All you have to do is to send appropriate headers.


Persistent connections are a bit ambiguous in this domain so to clarify that we are talking about the same thing: HTTP 1.1 Persistent Connections: keeping the TCP connection open after one HTTP request finished so that further HTTP requests can be made without the overhead of establishing a TCP Connection first. Header involved Connection: keep-alive and Keep-Alive: 123.

You are right modern browser support that and automatically set these header for XHRs. That's great because the TCP connection does not need to be reestablished for every XHR. But sending multiple XHRs as opposed to only one batched XHR is nevertheless slower because: (a) of the added HTTP overhead (Header, HTTP roundtrip) (b) even modern browser only support 2 or 6 parallel TCP connections to one domain. Pipelining the requests through available TCP connections brings another overhead. (c) Content encoding algorithms (i.e. gzip/deflate) can only see and process the individual response. That's not as efficient as gzip'ing the batched response (one dictionary, synergy effects).

I cannot quantify the overhead of (a), (b) and (c) but I did see a significant speed improvement after implementing Ext.Direct's RemotingProvider in one of my apps so I assume that it is significant.

dj
28 Jun 2009, 3:53 AM
So if i need to use REST for this purpose why should i use Direct and how should i use it because i would then need 2 points of access for clients which can be hard to maintain at some point...

Yes, you would have two different access vectors but that does not have to mean that you have to maintain these two independently. It should be fairly easy to add Ext.Direct's router as a (fairly transparent) layer between the RESTful interface of your application and your client side javascript. So you only have to maintain the RESTful interface. Nevertheless it is added complexity but it also brings you added benefits. Consider what's more important in your case.


PS: Ext.Direct and Ext.Direct's RemotingProvider are not the same. Batching requests is a feature of the RemotingProvider. Ext.Direct is a quite abstract thingy; Comet/Polling provider for it are in the works, a REST provider would be easy to do. So whenever I praise the benefits of Ext.Direct I actually mean the benefits of its remoting provider.

Nalfein
28 Jun 2009, 7:28 AM
Simplicity and browser caching I understand and I (at least with browser caching) agree with. Could you elaborate on why one would loose scalability?

Using REST you can without extra work split your load between multiple machines using just URLs. No central server or a load balancer is needed for that. In a well-designed REST API, when traversing is done using links embedded in resource representation, you can change URL scheming very easily and make your application distributed without much effort.



Persistent connections are a bit ambiguous in this domain so to clarify that we are talking about the same thing: HTTP 1.1 Persistent Connections: keeping the TCP connection open after one HTTP request finished so that further HTTP requests can be made without the overhead of establishing a TCP Connection first. Header involved Connection: keep-alive and Keep-Alive: 123.

Yes. Another great feature of HTTP 1.1 is HTTP pipelining (http://en.wikipedia.org/wiki/HTTP_pipelining): "The pipelining of requests results in a dramatic improvement in page loading times". Unfortunately there are yet some servers that don't support this and therefore some browsers including Firefox has pipelining disabled by default. You can safely turn it on (described here (http://egonitron.com/2007/05/25/the-truth-about-the-firefox-pipelining-trick/)) and set network.http.pipelining.maxrequests is 2. You can experiment with higher values but some webpages may not work correctly if they limit number of simultaneous requests per user.



But sending multiple XHRs as opposed to only one batched XHR is nevertheless slower because: (a) of the added HTTP overhead (Header, HTTP roundtrip)

That is right, but the overhead can be very small and forgivable compared to simplicity and easiness of debugging. To make it small you use persistent connections and caching.

An Ext JS may group requests logically and send them one after another. If caching is done properly and they are really sent in a persistent connection the perceived response time should be similar.


(b) even modern browser only support 2 or 6 parallel TCP connections to one domain. Pipelining the requests through available TCP connections brings another overhead.

Where is the overhead? You have two channels compared to a one when we use Ext.Direct.


(c) Content encoding algorithms (i.e. gzip/deflate) can only see and process the individual response. That's not as efficient as gzip'ing the batched response (one dictionary, synergy effects).

I would like to see some numbers. Even if we get 2% smaller messages, we are adding Ext.Direct's code.


I cannot quantify the overhead of (a), (b) and (c) but I did see a significant speed improvement after implementing Ext.Direct's RemotingProvider in one of my apps so I assume that it is significant.

I think that that happened because you haven't optimized your REST services properly. It is much more difficult than setting up an Ext.Direct point. You need to use caching and make sure that your requests are sent with appropriate headers. For example, if you miss Content-Length or it is calculated incorrectly, the connection would be dropped. A nice script to test cacheability: http://www.mnot.net/cacheability/

dj
30 Jun 2009, 4:04 PM
Using REST you can without extra work split your load between multiple machines using just URLs. No central server or a load balancer is needed for that. In a well-designed REST API, when traversing is done using links embedded in resource representation, you can change URL scheming very easily and make your application distributed without much effort.


Agreed. Although, you will run into problems (solvable with some effort with e.g. JSONP) when connecting your ExtJS frontend with such a service. Keyword: Same-domain-policy of XHRs.





(b) even modern browser only support 2 or 6 parallel TCP connections to one domain. Pipelining the requests through available TCP connections brings another overhead.

Where is the overhead? You have two channels compared to a one when we use Ext.Direct.


I don't really see that overhead anymore either. In fact more parallel connections can speed up the requests because they can be processed in parallel on the server. (Can be done also with a sophisticated Ext.direct.RemotingProvider router in a more enterprisy environment, e.g. a Java application server or a Rails application with a thread pool that processes the combined requests in parallel. ... but that's rather complex to do)





(c) Content encoding algorithms (i.e. gzip/deflate) can only see and process the individual response. That's not as efficient as gzip'ing the batched response (one dictionary, synergy effects).

I would like to see some numbers. Even if we get 2% smaller messages, we are adding Ext.Direct's code.


It can get far more effective than 2%. The gain highly depends on the data you are sending. In the test I describe below the gain from combining all messages compared to sending them individually is a decrease in size by 90%. Anything is possible between 0% and 90% depending on your data.



I think that that happened because you haven't optimized your REST services properly. It is much more difficult than setting up an Ext.Direct point. You need to use caching and make sure that your requests are sent with appropriate headers. For example, if you miss Content-Length or it is calculated incorrectly, the connection would be dropped. A nice script to test cacheability: http://www.mnot.net/cacheability/

The web application with which I observed this significant performance improvement after implemented the Ext.Directs Remoting API is a Ruby on Rails application. As you might know, Ruby on Rails has ETag handling build-in. Setting max-age or future Expires header (so completely get rid of the GET requests) is not an option for me. The users of that application always want the freshest data. So the If-none-match-header has to be enough.


As I don't really can explain why I saw this significant speed improvement, I came up with a simple demo (http://ext.wirsind.info/rest-vs-direct/). It's a slightly pimped /examples/restful/ that you can find with your Ext sources. The enhancements are:

Up to 20 Grids are rendered. Each has its own grid store. (But they share the same fake-db)
Optional Ext.direct.RemotingProvider API on top of the RESTful one.
Optional gzip-encoding of the API calls.
Rudimentary timing code for timing the XHR load operation.


Have a look for yourself: http://ext.wirsind.info/rest-vs-direct/ (source code included)

The loading times vary - even in the same browser. I haven't investigated why that's the case but I assume that the timing mechanism used ((new Date()).getTime()) isn't the best and varying server load makes the rest.


In my tests in Firefox, Opera and Safari (each Mac&Windows, newest stable versions) the performance of the two different APIs is more or less the same. Sometimes the performance of the REST version is slightly better.

Google Chrome and Internet Explorer (6, 7 and 8) seam to not like the many parallel XHRs of the REST version. Often the XHRs time out - if they don't time out, loading times are ca. 10 times higher than the loading times of the Direct version. This could be a server issue (e.g. the testing server is quite slow and has little RAM thus it is configured for very few max parallel FCGI server) so please do also test the code on your own server if you can.


It would be great if you could have a look at the code and tell me any optimizations I missed. But then, when it is so hard to make a REST API that flawlessly works with an ExtJS frontend and plugging an Ext.direct.RemotingProvider router into your application is so easy...

durlabh
7 Jul 2009, 6:36 AM
Nice sample!

thesilentman
6 Jun 2012, 10:02 AM
Hi @misha,

if you decide using Ext.Direct, take a look at this list (http://www.sencha.com/forum/showthread.php?67992-Ext.Direct-Server-side-Stacks) of providers:

My personal favorite is this one (http://www.sencha.com/forum/showthread.php?102357-Extremely-Easy-Ext.Direct-integration-with-PHP).

Cheers

squalo
18 Feb 2013, 12:40 AM
Hello
I use a RESTful PHP interface to a MySQL Databse.
CRUD works fine so far. But how can I manage, that 'inserts' or 'updates' ar not done, if some criteria fails?
I know how to do this with SQL , but how is it possible to get this into my ExtJs grid?

"Insert" and "Update" API, which I use, doesn't have return values.
And if I make an extra php function for an first lookup-query (like I would do in Ext.direct),
how can I manage such a call in the well defined REST URLs?

Appreciating any hints.
Thx.