Thursday, 4 April 2013

Part 5: vibe.http.rest in details

REST interface generation module is my favorite vibe.d part and one I have made most contributions to. Everything that was said before hints how good native development may be for web services in general and specifically vibe.d; this parts shows what D programming language can add here and why recreating something similar in C, C++ or even Go is not practically possible.

Idea of vibe.http.rest is simple - any HTTP API essentially matches certain HTTP requests to some inner handling code. With any reflection-capable language we can generate the boilerplate code automagically based on internal data structures. With D we can do it during compilation time.

By using powerful static introspection capabilities, compiler can generate resulting code that is no different from manual binding of URL's to functions and has no extra overhead. URL's and HTTP methods are deduced automatically, function parameters serialized to JSON and back if needed, everything can be customized via User Defined Attributes. In other words, everything users of web frameworks written in modern scripting languages are used to. Except it is done during compilation and you need not care about what it actually costs performance-wise. This perfectly matches one of main D ideas - having modern convenience without harming old-school performance capabilities.

One additional killing feature of this module is that it is not only capable of generating REST boilerplate for server. Clients are supported, too. After all D is general purpose language and chances are you will be using it for user applications, not server code. With vibe.d you can both create client to your own server API (one-liner!) and describe some foreign API using D entities. vibe.http.rest will then act as some kind of Remote Procedure Calling implementation via HTTP, you will get an object on client side that will have exactly same methods as matching server implementation.

In my opinion, first case (own service + client) is especially important. It both speeds up client prototyping for your services and provides strong guarantees that server and client built from same repo revision will have matching network API - because both are generated using the very same interface definitions.

Usage examples are explained in great details in rest example project. Small motivating example for your convenience:

import vibe.http.rest, vibe.http.common;

interface IExampleAPI
{
// GET /something?a={int}&b={array encoded in json}
string getSomething(int a, double[] b);

struct Item
{
string first, second;
}

// POST /
// (item encoded in json in POST data)
void addIndex(Item item);

@path("/custom/") @method(HttpMethod.PUT)
Item nameNotUsed();
}

class Example : IExampleAPI
{
override:
// ...
}

shared static this()
{
// for server
auto routes = new URLRouter();
registerRestInterface!IExampleAPI(routes, new Example(), "/api/");

// for client
auto client = new RestInterfaceClient!IExampleAPI("http://127.0.0.1/some/url/");
}

Vibe.d rocks.

No comments:

Post a Comment