Documentation

Installation

Note: this section describes the manual installation process of vibe.d. The recommended way, however, is to use DUB instead and simply add "vibe-d" as a dependency to your project.

On Debian and Debian based systems such as Ubuntu, you can install an APT repository that will allow you to stay up-to-date including all dependencies automatically. See the github page for instructions.

On all other systems, the installation currently is a simple manual process. You just have to extract the downloaded archive and make the vibe script callable from anywhere.

On Windows, add the 'bin' directory to the PATH by going to Advanced System Settings/Advanced/Environment Variables and entering the path into either the user PATH variable or the system wide version.

For *NIXes, there are setup scripts that create the symlink and add an unprivileged 'www-vibe' user to allow for privilege lowering on server systems. Depending on the operating system, run the appropriate setup script from directory where the files have been extracted:

$ ./setup-linux.sh
 or
$ ./setup-mac.sh
 or
$ ./setup-freebsd.sh

On non-Windows systems you may need to install some additional dependencies. See the github page for more information.

After the installation, you can run any vibe.d application by typing 'vibe' from inside the application's root directory. You can try this by starting one of the exammples:

$ cd examples/http_server
$ vibe
Checking dependencies in 'C:\Users\sludwig\Develop\vibe.d\examples\http_server'
Listening on 0.0.0.0 port 8080 succeeded
Listening on :: port 8080 succeeded
Running event loop...

First steps

Note: this section assumes that you have installed DUB. If you have directly installed vibe.d instead, simply invoke "vibe" instead of "dub" on the command line.

The easiest way to get started is to run the following command from your projects directory:

$ cd /path/to/my/projects
$ dub init <project-name>

This will create a new directory with the given name and creates the basic directory structure that is recommended for a vibe.d project. You can then go ahead and edit the source/app.d file. You should also edit the package.json file if you want to publish your project.

The recommended structure for a project is about as follows:

appname/
	package.json
	source/
		app.d
	public/
		images/
		styles/
			style.css
	views/
		layout.dt
		index.dt
Example structure of a web application project

For a simple web application, the 'app.d' file could look similar to this one:

import vibe.d;

void index(HTTPServerRequest req, HTTPServerResponse res)
{
	res.renderCompat!("index.dt", HTTPServerRequest, "req")(req);

	// not recommended alternative, may cause memory corruption due to a DMD bug
	//res.render!("index.dt", req);
}

shared static this()
{
	auto router = new URLRouter;
	router.get("/", &index);

	auto settings = new HTTPServerSettings;
	settings.port = 8080;

	listenHTTP(settings, router);
}
Simple app.d file with minimal routing

The 'views' sub folder is automatically searched for templates instantiated with render(). The two templates in the example structure might look like this:

!!! 5
html
	head
		title Example page
	body
		block body
Example layout.dt
extends layout

block body
	h1 Example page - Home
	p Hello, World!
Example index.dt

This structure makes use of the blocks/extensions feature of the template parser. For more advanced template features see the Diet template documentation.

Finally, you can add a "package.json" file to let the vibe.d package manager automatically download and compile extension libraries. This file will also provide the description that is needed to later put your own library into the public extension registry.

{
	"name": "appname",
	"description": "My fabulous new app",
	"copyright": "Copyright (C) 2000 Me. All rights reserved.",
	"homepage": "http://appname.org",
	"authors": [
		"Hans Wurst"
	],
	"dependencies": {
		"vibe-d": ">=0.7.12"
	}
}
Example package.json

Once you have the project in place, simply run vibe from the project's root directory and it will get all dependencies, compile the application, and run it:

$ cd path/to/project
$ dub
Checking dependencies in 'path/to/project'
Listening on 0.0.0.0 port 8080 succeeded
Listening on :: port 8080 succeeded
Running event loop...

HTTP

Server configuration

The HTTP server supports a number of configuration options to customize its behavior. By default, the server will listen on all local network adapters on port 80 and will perform complete request parsing. The following list gives an overview of the most common settings:

port
The port on which the HTTP server shall listen
bindAddresses
A list of all interfaces on which the server shall listen. IPv4 and IPv6 addresses, as well as domain names are supported.
options
Controls optional features of the web server. Certain options can be disabled to increase speed or to decrease memory usage. By default, the following options are enabled: parseURL, parseQueryString, parseFormBody, parseJsonBody, parseMultiPartBody, parseCookies. Enabled options are ORed together.
errorPageHandler
Provides a way to customize error pages. For example:
void errorPage(HTTPServerRequest req,
               HTTPServerResponse res,
               HTTPServerErrorInfo error)
{
	//res.render!("error.dt", req, error); // still affected by a compiler bug
	res.renderCompat!("error.dt",
		HTTPServerRequest, "req",
		HTTPServerErrorInfo, "error")
		(req, error);
}

shared static this()
{
	auto settings = new HTTPServerSettings;
	settings.errorPageHandler = toDelegate(&errorPage);
	// ...
}
Inside of the error.dt template, the variables req, code and msg are available in this example.
sslContext
Lets the server operate as an HTTPS server. You should probably also set the port to 443 in case this field is set.

Routing

The URLRouter class provides a convenient way to let different functions handle different URLs. It supports static path matching, variable placeholders and wild-cards. Any matched variable will be available as an entry in the params dictionary.

In addition to the path, the HTTP method is also used for matching requests. Each HTTP method has a corresponding method in the URLRouter class (e.g. get() or post()). The following example will route all GET requests matching the path scheme "/users/*" to the userInfo handler and serve all other GET requests using the files in the public folder.

import vibe.d;

void userInfo(HTTPServerRequest req, HTTPServerResponse res)
{
	auto username = req.params["user"];
	render!("userinfo.jd", username)(res);
}

void addUser(HTTPServerRequest req, HTTPServerResponse res)
{
	res.redirect("/users/"~req.post["user"]);
}

shared static this()
{
	auto router = new URLRouter;
	router.get("/users/:user", &userInfo);
	router.post("/adduser", &addUser);
	router.get("*", serveStaticFiles("./public/"));

	// To reduce code redundancy, you can also
	// use method chaining:
	router
		.get("/users/:user", &userInfo)
		.post("/adduser", &addUser);
		.get("*", serveStaticFiles("./public/"));

	listenHTTP(new HTTPServerSettings, router);
}
Example: GET/POST routing and static file serving

Diet templates

Vibe supports HTML templates with a syntax mostly compatible to jade templates. They provide a concise way to dynamically generate the HTML code of the final web pages. D expressions and statements can be embedded and the full vibe API is available within templates.

Templates should reside somewhere inside the 'views' folder of a project. They are then rendered using the render function, which takes the template file name as the first template argument, followed by a list of variables that should be available to the template. Finally, it takes a HTTPServerResponse to render into.

The following example shows a number of features of the template parser. A full reference of the template syntax is found on the Diet templates page.

!!! 5
html
	head
		title My page: #{pageTitle}
	body
		h1= pageTitle
		p This is the content of this page. The
			| title "#{pageTitle}" is inserted dynamically.
			| We can also use loops and other D statements:
		block placeholder
		p
			- foreach(i, ch; pageTitle)
				| #{i+1}. character: #{ch}
		p.special.small This paragraph has the 'special'
			| and 'small' CSS classes
		p#footer This paragraph has the id 'footer'.
		#somediv
			| I'm a text inside the div ##somediv
Example: Template file with dynamic code inserts and several other template features

Error pages

There are two ways in which an error page is sent back to the client:

  • An exception is thrown from the request handler or while parsing the request. By default, a 500 "Internal Server Error" is returned. By throwing a HTTPStatusException , the status code can be customized.
  • The request handler does not write a response. In this case the server automatically returns a 404 "Not Found" error.

The HTTPServerSettings can be used to provide a custom error page handler. If one is provided, it is called for any of the two conditions and must render an error page to the response object. If no handler is given, a simple plain-text error page is generated.

import vibe.d
void error(HTTPServerRequest req, HTTPServerResponse res, HTTPServerErrorInfo error)
{
	res.renderCompat!("error.dl",
		HTTPServerRequest, "req",
		HTTPServerErrorInfo, "error")
		(req, error);
}

shared static this()
{
	auto settings = new HTTPServerSettings;
	settings.errorPageHandler = toDelegate(&error);

	auto router = new URLRouter;
	// ...

	listenHTTP(settings, router);
}
Example: A typical setup for an error page handler

Authentication

Currently, the only built-in authentication method is HTTP-Basic-Auth. HTTP-Digest-Auth will follow later and higher level mechanisms such as OAuth will be provided using extension libraries.

The recommended practice for plugging authentication into a web application is to use the fall-through feature of the URLRouter. If the user is properly authenticated, the performBasicAuth function will not do anything and the URLRouter will continue to match the request to all following routes. If, however, there is no authentication or if the username/password pair is not valid, it will throw a HTTPStatusException exception which generates a 403 error page so that the user is prompted with a password dialog on the browser side. The routing stops in this case.

import vibe.d;

bool checkPassword(string user, string password)
{
	return user == "admin" && password == "secret";
}

shared static this()
{
	auto router = new URLRouter;
	// the following routes are accessible without authentication:
	router.get("/", staticTemplate!"index.dl");
	router.get("/about", staticTemplate!"about.dl");
   
	// now any request is matched and checked for authentication:
	router.any("*", performBasicAuth("Site Realm", toDelegate(&checkPassword)));

	// the following routes can only be reached if authenticated:
	router.get("/profile", staticTemplate!"profile.dl");
	router.get("/internal", staticTemplate!"internal.dl");

	// ...
}
Example: Using HTTP-Basic-Auth to restrict access

Sessions

Cookie based HTTP sessions are supported directly by the HTTP server. To be able to use them, you first have to set a SessionStore in the HTTPServerSettings . Sessions are then established by calling HTTPServerResponse.startSession and stopped using HTTPServerResponse.terminateSession . The returned Session object behaves as a key value store taking strings as keys and values.

import vibe.d;

void login(HTTPServerRequest req, HTTPServerResponse res)
{
	// todo: verify user/password here

	auto session = res.startSession();
	session["username"] = req.form["username"];
	session["password"] = req.form["password"];
	res.redirect("/home");
}

void logout(HTTPServerRequest req, HTTPServerResponse res)
{
	res.terminateSession();
	res.redirect("/");
}

void checkLogin(HTTPServerRequest req, HTTPServerResponse res)
{
	// force a redirect to / for unauthenticated users
	if( req.session is null )
		res.redirect("/");
}

shared static this()
{
	auto router = new URLRouter;
	router.get("/", staticTemplate!"index.dl");
	router.post("/login", &login);
	router.post("/logout", &logout);
	// restrict all following routes to authenticated users:
	router.any("*", &checkLogin);
	router.get("/home", staticTemplate!"home.dl");

	auto settings = new HTTPServerSettings;
	settings.sessionStore = new MemorySessionStore;
	// ...
}
Example: Using a HTTP session for user authentication

Client requests

Client request are done using the requestHTTP() function.

import vibe.vibe

void main()
{
	auto res = requestHTTP("http://google.com",
			(scope req) {
				/* could e.g. add headers here before sending*/
			},
			(scope res) {
				logInfo("Response: %s", res.bodyReader.readAllUTF8());
			}
		);
}
Example: Performing a simple HTTP request

A connection pool is used internally in conjunction with persistent HTTP connection to reduce the number of connection establishments.

Database support

MongoDB

A native MongoDB driver is part of the distribution supporting the standard set of database operations. Data is exchanged using the Bson struct.

For an comprehensive documentation of MongoDB's operations see the MongoDB manual . The API reference contains the documentation for the driver.

import vibe.d;

MongoClient client;

void test()
{
	auto coll = client.getCollection("test.collection");
	foreach (doc; coll.find(["name": "Peter"]))
		logInfo("Found entry: %s", cast(Json)doc);
}

shared static this()
{
	client = connectMongoDB("127.0.0.1");
}
Example: Finding entries in a MongoDB

Redis

A rudimentary client for the structured storage server Redis is included in Vibe. Commands and operations on Redis data types are implemented as instance methods of the client. The methods are named after their corresponding Redis command documented in the command reference .

Raw TCP

Low level TCP connections are handled using the TCPConnection class, which implements the Stream interface. Connections can be established by either listening on a specific port for incoming connections or by actively connecting to a remote server.

Server

Listening for TCP connections is done using the listenTCP function. An implementation of a very simple echo server could look like this:

import vibe.d;

shared static this()
{
	listenTCP(7, (conn){ conn.write(conn) });
}

Calling listenTCP like this will listen on all local network devices. To listen only on a specific device, the bind address can be given as an additional parameter:

import vibe.d;

shared static this()
{
	listenTCP(7, conn => conn.write(conn), "127.0.0.1");
}

The address can be given as an IP address string (IPv4 or IPv6 format), as an uint for numeric IPv4 addresses or as a in6_addr for numeric IPv6 addresses.

Client

Connecting to a TCP server is done with the connectTCP function. The following example gets the current time using the Daytime Protocol .

import vibe.d;

shared static this()
{
	auto conn = connectTCP("time-b.timefreq.bldrdoc.gov", 13);
	logInfo("The time is: %s", cast(string)conn.readAll());
}

Advanced topics

Publishing on the DUB registry

The DUB registry contains packages that use the same package management as vibe.d. Many of them extend and supplement vibe.d's functionality. The packages are automatically downloaded if the corresponding entry in the "dependencies" section of the project's package.json file is present.

If you have written an extension library yourself, you can register it in the DUB registry so others can easily make use of it. For this to work, you will first have to write a proper package.json, which has to lie in the root directory of your project (the project should adhere to the structure mentioned in the first steps). The project currently also has to be hosted on github. See http://registry.vibed.org/publish for more information.

{
	"name": "vibelog",
	"description": "A light-weight embeddable blog implementation",
	"homepage": "https://github.com/rejectedsoftware/vibelog",
	"authors": [
		"Sönke Ludwig"
	],
	"dependencies": {
	}
}
Example: A package.json file suitable for registration as a DUB package.

You can then register your project on registry.vibed.org and as soon as you then add a new git tag with the name matching the current version prefixed with "v" ("v0.0.1" for the example here), it should appear there. Note that the update can take up to 30 minutes. Anyone can then add an entry similar to the following to their project to make use of the library:

{
	...
	"dependencies": {
		"vibelog": ">=0.0.1"
	}
}
Example: Corresponding dependency to use the published DUB package.

Custom main function

When writing a client application, maybe something like wget, it may not be desirable to start an explicit event loop, but instead exit right after the work is done. Some applications might also need more control of how vibe is initialized or when the event loop is started. To support such usage scenarios, you can implement your own main() function. To be able to do this, you just have to import "vibe.vibe" instead of "vibe.d" add "VibeCustomMain" to the "versions" field in your package.json file. This will tell the compiler to not use the main() function that vibe.d provides.

import vibe.vibe;

int main(string[] args)
{
	processCommandLineArgs(args);
	return runEventLoop();
}
Example: Simple custom main function that runs an event loop.
import vibe.vibe;

void main()
{
	auto f = openFile("test.html", FileMode.CreateTrunc);
	f.write(download("http://google.com/"));
}
Example: Client application that downloads a document

Privilege lowering

For server applications it may be desirable to start the application as root so that it can listen on privileged ports or open system log files for writing. After these setup tasks, such applications impose a security risk because a hole in the application that allows to somehow execute commands on the server will give the attacker full access to the system. For this reason vibe supports privilege lowering, where the user id and group id of the process are changed to an unprivileged user after the setup process, right before the event loop is started.

Privilege lowering can be configured in the configuration file /etc/vibe/vibe.conf (on Windows vibe.conf must be in the application's root directory instead). The two fields "user" and "group" have to be set to the the name or numeric ID of the unprivileged user/group.

{
	"user": "www-data",
	"group": "www-data"
}
Example vibe.conf file