I previously wrote a hello world app with the vibe.d web framework where I used the URLRouter
class to route requests directly. However there is a more simplistic and scalable way of writing a web service by using the Web Interface. This is possible with D programming language’s powerful meta-programming ability: to generate code during compilation.
You may want to checkout my OpenSource.com blog post on 5 reasons the D programming language is a great choice for development which highlights some “awesomeness” of D.
First, lets see a basic template vibe.d project.
If you are new to vibe.d web framework, I recommend you read my previous tutorials on 1. Getting started, 2. Form upload and 3. Multiple file upload.
import vibe.vibe;
void main()
{
// Instantiate the router and register the web interface
// to route all requests (GET, POST, ...)
auto router = new URLRouter;
router.registerWebInterface(new WebService);
auto settings = new HTTPServerSettings;
settings.port = 8080;
settings.bindAddresses = ["::1", "127.0.0.1"];
// configure routes with settings
listenHTTP(settings, router);
logInfo("Please open http://127.0.0.1:8080/ in your browser.");
runApplication();
}
As you may have noticed above, the URLRouter
class instance provides a registerWebInterface()
method to register the web interface class called WebService
. This web interface class, which will be created later, shall contain methods for handling all HTTP routes. listenHTTP()
is used to configure the IP address and port for the server.
Now let’s see how to implement the web interface itself:
class WebService {
void index(HTTPServerRequest req, HTTPServerResponse res)
{
res.writeBody("Hello, World!");
}
}
Run the server with dub
in your command-line and open the IP and port configured, in my case http://127.0.0.1:8080/
, in your browser. If everything was done correctly, you should be greeted with Hello, World!
. Now let’s understand how the web interface works.
Let’s do the math!
A web interface class methods maps to HTTP routes and serves as request handler. The routes and HTTP methods are derived from the web interface class method names. In the above example, the WebService
class method index()
handles the index (/
) route — its name is required to be exactly index
and has a return type of void
. It receives an HTTPServerRequest
and HTTPServerResponse
object as arguments when the route is accessed.
Besides the index route requirement, all other routes (GET, POST, DELETE, PUT, PATCH) are expected to have a certain prefix to indicate the type of request. The prefixes may be one of (post, create, add) or no-prefix for a POST request, (get, query) for GET, (delete, remove, erase) for DELETE, (patch, update) for PATCH and (put, set) for PUT. The remaining part of the method name after the prefix is used as route path.
For example, a GET request to the route /users
may be represented as:
void getUsers(...) {}
// OR
void queryUsers(...) {}
a POST request to the route /users
may be represented as:
void postUsers(...) {}
// OR
void createUsers(...) {}
// OR
void addUsers(...) {}
The HTTP method and path can be overridden with User Defined Attributes (UDAs) — @method()
UDA for overriding the HTTP method and @path()
for the path as follows:
// route is overridden to GET /users/all
@method(HTTPMethod.GET)
@path("users/all")
void allUsers(...) {}
There are many more features unleashed through UDAs such as authentication, route access protection, HTTP header modification, error handling and the like.
All these and many more are possible due to D’s support for code generation at compile-time — the underlining route handling implementations are generated by the compiler. I will demonstrate more advanced web interface features in future tutorial.