Translate

Thursday, March 7, 2013

REST vs RPC in Web Service Development

Ive been implementing web services using lightweight web service protocols such as XML-RPCJSON-RPC and (my favorite although proprietary) YAML-RPC for some time now.

I had some discussions last year about web service development using REST, a concept I had heard about for some time, but I did not see the advantages of it.  I knew that it had become the predominate web development architecture model, but for some reason I could not see the advantages of REST over pure lightweight RPC approaches.

My first experiences with an RPC protocol over HTTP was with SOAP, which is a technology I've grown to strongly dislike; now I consider SOAP a horrible enterprise technology since it's cumbersome and expensive to implement and often suffers from serious compatibility issues between different vendor implementations (Qore also has SOAP support - both server and client, however I would recommend avoiding it if you can).   My great appreciation for the lightweight RPC over HTTP protocols listed above is to no small degree based on my dislike of SOAP, so when hearing and reading about REST, I could not see that it would be as great a leap as from SOAP to XML-RPC for example.

(As a footnote Wikipedia lists XML-RPC as the precursor to SOAP, which makes SOAP an absolutely classic case of overengineering by committee - since from my point of view XML-RPC with all its faults is vastly superior to SOAP.  Also here is a link which humorously sums up my thoughts on SOAP: http://harmful.cat-v.org/software/xml/soap/simple)

However, finally I've gotten into REST a little deeper, and having developed an initial RestHandler for the Qore HTTP server, the advantages of a REST architecture are completely clear and compelling.

Using REST forces you to have a logical and straightforward organization of your web service development.  Each type of object will have it's own URL, and (in the Qore RestHandler at least) it will have a dedicated class to handle requests to objects of that type.

For example, in the Qore RestHandler, if you register a class with the name "workflows" at the root level of your REST handler, then a request like

   GET /workflows

will be directed to your workflow class's get() method, which will handle the request.

Classes (and therefore URLs) can be stacked, so a request like

   GET /workflows/1/instances/2?action=stop

Will be directed to the appropriate class's "getStop()" method.   If the appropriate method name (derived from the HTTP method name in the request and any action verb given as a URI argument) is not implemented in the class, then the RestHandler returns a user-friendly 400 response.

This easy and logical hierarchical organization of the objects corresponding to the URLs along with the simple dispatching to handler methods of objects of the appropriate class makes implementing the REST service trivial in Qore.

Additionally, the RestHandler transparently takes care of deserializing request bodies based on the HTTP Content-Type header and serializing any response body based on the client's HTTP Accept header.

This also makes the REST approach superior to the lightweight RPC protocols mentioned above.

It's easy to see why REST is the dominant web service architecture; Qore's RestHandler will continue to be under active development for the upcoming release of Qore (0.8.8), and I hope it will be useful for others as well.

Saturday, March 2, 2013

Class Inheritance vs Class Wrapping

Qore supports "standard" class inheritance for polymorphism, but also supports another construct that may be unique to Qore.  In Qore there is the possibility of "wrapping" a class and providing a compatible interface with the wrapped class without using inheritance.

There are several advantages and also some drawbacks to this approach.  Let me first explain what I mean by "wrapping" a class and also explain how it's done in Qore.

To "wrap" a class, you embed an object of the desired class as a member of the new class and implement a methodGate() method that redirects method calls from outside the class to unimplemented methods.  Additionally a memberGate() method can be implemented to redirect accesses to unknown members from outside the class and return an arbitrary value for the member access.

For example, you can wrap a class to provide logging for all method calls or provide external thread synchronization to an unsynchronized class.  The following is an example that does both.

class MySocket {
    private {
        Socket $.sock();
        Mutex $.m();
    }

    static log(string $fmt) {
        vprintf(now_us().format("YYYY-MM-DD HH:mm:SS.us Z") + ": " + $fmt, $argv);
    }
    
    any methodGate(string $method_name) {
        MySocket::log("MySocket::methodGate() method called: %y args: %y\n", $method_name, $argv);
        $.m.lock();
        on_exit $.m.unlock();

        return callObjectMethodArgs($.sock, $method_name, $argv);
    }
}

This can be very useful for testing and for other purposes, requires very little typing to implement, and its purpose is clear from the implementation (even without comments).  Additionally, this method is completely independent of the definition of the wrapped class.

The main disadvantage is that it doesn't claim compatibility with the Socket class, so you cannot pass an object of class MySocket to code that expects a Socket object.

Currently there is no way in Qore to wrap a class in this way and to remain type-compatible (i.e. to appear to be a subclass of the wrapped class).  To remain type-compatible in this way, every method of the class has to be explicitly wrapped as above, and if the wrapped class has any method interface changes (for example, new method), the subclass has to changed accordingly.

However despite the drawbacks, it's still a very useful construct.   Possibly a future version of Qore will allow such wrapped classes to claim class compatibility with the wrapped class and therefore address the typing issues.

Sunday, February 3, 2013

Exceptions vs Error Codes

Recently I was reading about throwing exceptions vs returning error codes, and I realized that this is a very interesting topic in programming language design that had been in the back of my head, but deserves to be properly thought through.

I don't believe that one approach is better than the other for all cases; from my point of view the biggest argument for exceptions over return codes is that with exceptions you avoid situations where errors are silently ignored (resulting in confusing results for users and difficult to debug situations for the programmer).

Basically Qore tries to be as intuitive as possible for the programmer (and obviously fails sometimes, as seen from the occasional design and interface changes as the language progresses), and therefore should try to get this right.

After thinking about it a bit, it seems to me that Qore builtin code should always throw exceptions if errors are not likely to occur (and therefore be more likely to be ignored).  Examples of this would be Socket send methods (changed from returning error codes to throwing exceptions in 0.8.6) and File write methods (even less likely to throw exceptions, already changed to throw exceptions in svn - to be released in 0.8.7 shortly).

It also seems that for code that is more likely to throw an error could justifiably return error codes instead of throwing exceptions, as ignoring the return code would be clearly bad programming practice.   If the code in question already returns a result code, then this model fits even better.

Making a language as intuitive as possible for all programmers is not easy.  Basically I can only try to do it for myself and try to think through and make educated guesses about what should work for others.  However at the end of the day, it's all about maximizing productivity.  Having silent errors in an important program could cost a lot of money to debug.  If the programming language is not intuitive, then it also costs money every time programmers get stuck on some weirdness with the language or have to debug problems caused by the same.  Intuitive programming languages are also more fun to program in.

This last point is the main reason why Qore's design was originally based on perl - I found perl very intuitive and wanted to make a language like perl that was suitable for enterprise development.  I know that quite a few programmers do not like perl, but possibly a lot of those have never programmed much in it.  Anyway, I believe Qore is getting better and better with each release, I find it more intuitive, and I hope those that are brave enough to try Qore do too.