views:

100

answers:

3

Is it a requirement that RESTful interactions occur between physically separate clients and servers? i.e. does the interaction need to involve the network stack in some way? Is there any benefit to employing an HTTP-like "calling convention" between the various components of an application?

It seems to me that the benefits of REST, such as they are, are almost as applicable to communication between components of the same application as to communication between physically separate clients and servers, and that REST's constraints and guiding principles can be satisfied without the network stack being involved. (I'm not suggesting that it's a good idea for every function call to "look like HTTP", but for certain function calls or interactions, it might make sense for the interaction to be HTTP-like.)

For example, in a web application it might be useful to access ("internal") user information via URLs like http://api.local/user/34 and an "HTTP client" that routes and dispatches requests internally, rather than going through a standard HTTP routing and dispatch process. Instead of providing a conventional library and associated documentation, the developer of the user component would provide URL endpoints (resources), which could be manipulated with the standard HTTP verbs. Since developers are already familiar with HTTP, less documentation would be required, and there would be more consistency and uniformity across components.

(I think that thinking about REST in this way also helps clarify the difference between REST and RPC mechanisms like SOAP--there's no reason to ever use SOAP for "internal" calls, but the understood behaviour and semantics of REST may make it useful for "internal" calls in some situations. And of course if you're using REST for internal calls (REST Level 0?), it's trivial to convert such interactions into external calls if the need arises.)

+1  A: 

The ideas behind REST are largely driven by the economics of data transfer, remoteness and architecture neutrality. It is expensive to access a remote resource; you want an architecture that encourages cacheability, addressability and minimalistic semantics. However, for in-process communications, sending data between subsystems within is extremely cheap, and usually amounts to passing a pointer, which satisfies or obviates all three goals.

I admit I haven't thought deeply about this, so a return question might be in order: how would in-process HTTP make my life easier?

Marcelo Cantos
To answer your question, I'd say in-process REST makes your life easier because, among other reasons: (a) RESTful interactions are well understood, and to a large degree self-documenting; and (b) it makes it trivial to move services from being satisfied in-process to remote if necessary. I think "addressability" and "cacheability" and benefits apply about as well to in-process REST to external REST. (e.g. it's quite common to use memcache internally--why not make its involvement transparent if you can?)
mjs
@mjs: Point (a) is unconvincing. Function calls are well understood too, even more so than REST. Point (b) is an interesting one; I can see it being useful if you might go remote later (or want to mix and match). I disagree with the cacheability comment, since a function can transparently cache results if this is worthwhile and there is little gain in exposing HTTP-style caching semantics to the caller. One area where caching might help is in a database API, but this is no longer the same scenario (nor is memcache).
Marcelo Cantos
@mjs: Just to clarify a point: The reason HTTP caching doesn't benefit an in-process client-server interaction is that once a function decides to cache a result, it doesn't matter if the caller comes back repeatedly for the same data; the function simply returns the same pointer, at negligible cost. In a conventional HTTP/REST interaction, client-side caching makes a big difference.
Marcelo Cantos
Perhaps I'm not following you, but I don't see why a client side HTTP-style cache is fundamentally less useful than (for example) a client side memcached cache. Sure, it doesn't allow you to avoid a network round trip (since there's no network stack involved), but the sophistication of HTTP's cache control headers (both the client and server have a measure of control over when and how the cache is used) would seem to be useful in some circumstances. And they're also well-defined--if you know HTTP, you already know how both the "server" and "client" are supposed to behave.
mjs
@mjs: Perhaps my phrasing was unclear. What I meant was that HTTP-style caching and memcache aren't useful at all when client and server are in the same process (which is the context of this discussion, isn't it). You can relegate caching semantics to being an implementation detail of the function that acts as the "service". In fact, this is a well-known technique that goes by the name of memoization (or, more generally, dynamic programming).
Marcelo Cantos
Why do you say that memcache isn't useful when the client and server are in the same process? My experience is that memcache is frequently used this way, particularly in web applications. Anyway, memoization is usually completely transparent, and the caller has no way of forcing the callee to invalidate their cache. An advantage of a HTTP-style "calling convention" (as I see it) is that it gives the *caller* a well-defined procedure that allows it to clear the cache. Given that cache invalidation is one of the two "hard problems" of CS (together with naming things), I think this can be useful.
mjs
I have never seen memcache interposed between agents inside the same running process. It is certainly not done frequently. The most common use of memcache is between web-app servers and database servers, but that is always inter-process (usually inter-host), never intra-process.
Marcelo Cantos
+1  A: 

Using REST principles and HTTP semantics in-process definitely does make sense, but probably only if your application also eventually is a client or server communicating with HTTP.

The hard part is honoring the layered constraint of HTTP since it's so easy to call that singleton on the other sie of the layer, since it's just a function call away.

One benefit, however is that you can in fact move a layer from one place to another. It's probably hard to achieve this fully, but I think it's doable, although I'll hazard a guess that it's never been done.

In my own thought experiments for this all of the benefits of HTTP come into play, in ways that mere memcached or in-process caches can't handle it. Take, for example cache validation, or conditional puts. Imagine being able to make a function call with the expressiveness of a HTTP request:

retrieve this thing from this service, but only if its ETag isn't "A" or "B" or W/"C", since those are the ones I have at the moment

Or

store this over here, but only if the ETag W/"DEF" is still valid, since that's the tag I used when I did my GET just now.

and

I'd like to search for widgets like this, and have the result preferably as an IAtomCollection, but i'll take a List instead (Accept). The last time I asked this question I got an ETag of "foo" (If-None-Match), so I don't need it if it didn't change, but if you don't mind, I'd like to verify the validity of my cache with the origin server (Cache-Control: must-revalidate). Oh and by the way here are my credentials (Authorization).

Questions like these are so easy to do in HTTP, and we all know how to forge such complicated queries.

The same goes for HTTP responses:

Hi, I found your IAtomCollection, and I did actually verify it with the origin server. The thing you have isn't valid any more, so here's a new one for you. It has the ETag of "bar", and you're allowed to consider it fresh for two minutes without revalidating with me, but if I'm gone the next time you ask, you can extend the freshness period for another minute. And of course the response varies based on your credentials (goes without saying, right?) and your preferences.

Again, plain old HTTP. Imagine being able to make method calls that are that smart!

As for HATEOAS, putting some thought into encapsulating identifiers would make it possible to honor that constraint too. But my thought experiments haven't gone very far in this direction...

mogsie
A: 

In a RESTful system that emphasizes the resource, rather than the function behind it, the resource's URI is often the most natural way to address the resource. That's what the resource is known by, so why not use it?

In some systems, it is not always clear which function calls are to be executed in order to get the data that is provided by a resource. Again, simply addressing the resource through its URI (even from within your code) might be most convenient.

In RESTx, we catered for that by giving you as the component author a very simple means to access the data of a resource that's hosted on this server. At the same time, this abstraction makes it also possible to refer to data that's hosted on other servers using the exact same syntax. But instead of doing a manual HTTP request, you call the accessCode(<uri>) method. Of course, if the uri refers to a local resource then there won't be an actual HTTP request, but that's something you don't have to worry about. Here is an example of what that looks like.

Naturally, you don't have to use hard-wired URIs in your code. RESTx is about reusable code, which is configured as needed in order to create a new RESTful resource. So, oftentimes the URIs you are referring to are part of the component's configuration.

jbrendel