Building a simple Web server with arsd CGI framework

Mon Jan 11 2021
on
#D
#arsd
#webdev

No one

Frameworks for building web servers in the D programming language come with different conventions and design choices. I previously wrote about using the vibe.d web framework both in it's route-base style and declarative web interface style. However there's another alternative, the CGI style, which the arsd CGI web framework was designed with (kind of).

Ards CGI is just one module among a collection of modules under the arsd namespace.

The interesting thing about using arsd for me is it's simplicity and how lightweight it is. It's quite straightforward to get a web server up and running with very few lines of code. Moreover, arsd by default comes with zero system dependencies. It does not require you to install any system package to use unlike vibe.d. This advantage makes arsd easy to run in any environment especially when you do not have system access to install system dependencies (cloud functions, PaaS, etc).

Zero system dependencies!!

Now, I'm will be using the D package manager, dub, to run the server app. Create a dub project by running dub init arsd-cgi-demo command from your command line where arsd-cgi-demo is your project's name. Make sure to add arsd-official:cgi when prompted to add a dependency as follows:

dub init arsd-cgi-demo
Package recipe format (sdl/json) [json]:
Name [arsd-cgi-demo]:
Description [A minimal D application.]:
Author name [aberba]:
License [proprietary]:
Copyright string [Copyright © 2021, aberba]:
Add dependency (leave empty to skip) []: arsd-official:cgi
Adding dependency arsd-official:cgi ~>9.0.4
Add dependency (leave empty to skip) []:
Successfully created an empty project in '/home/aberba/workspace/d/arsd-cgi-demo'.
Package successfully created in arsd-cgi-demo

Dub comes bundled with the D compiler when installed.

So lets see an example server:

import arsd.cgi;

void handler(Cgi cgi)
{
	cgi.setResponseContentType("text/html");

	switch (cgi.pathInfo)
	{
		case "/":
			cgi.write("Hello, World!");
			break;

			// other routes go here

		default:
			cgi.setResponseStatus("404 Not found");
			cgi.write("Requested page not found.");
			break;
	}
}

void main()
{
	RequestServer server;
	server.listeningPort = 9000;
	server.serve!handler;
}

That's all it takes. You first create a handler which takes a Cgi parameter with all the facilities to handle both receiving an http request and sending a response.

cgi.pathInfo is used to match the request route and response according. You may also use cgi.requestMethod to match the request method which may be one of cgi.RequestMethod.GET, cgi.RequestMethod.POST, cgi.RequestMethod.PATCH and friends. The following code shows how you may do that in the handler function:

void handler(Cgi cgi)
{
	cgi.setResponseContentType("text/html");

	switch (cgi.pathInfo)
	{
		case "/":
			if (cgi.requestMethod == cgi.RequestMethod.GET)
			{
				cgi.write("Hello from GET");
			}
			else
			{
				// you may also send 404. Whatever you want, 🤷‍♀️

				cgi.write("Hello, I'm also here.");

			}
			break;

			// other routes go here

		default:
			cgi.setResponseStatus("404 Not found");
			cgi.write("Requested page not found.");
			break;
	}
}

You may also notice that the cgi.setResponseStatus() method for setting both a response status code and text. The prefix, 404, becomes the response code whilst the text that follows, in this case Not found, then becomes the status text. This is a convention used in certain aspects of arsd CGI. I will dive into those aspects in another post later.

Now since arsd CGI is written in D, a language with very powerful metaprogramming support, it is capable of abstracting things to minimize the lines of code needed to implement certain functionalities. Let's see the same example in an idiomatic D code:

import arsd.cgi;

void handler(Cgi cgi)
{
    // the rest of the content goes here
}

mixin GenericMain!handler;

That's it!. No need to manually initialize a request server or register a port manually. Arsd takes care of generating the code needed to handle all of that for you. Pretty neat.

This is just a tease of what arsd CGI web framework can do. It also supports a declarative style for handling requests with a URL dispatcher. I will write about that later.

Now it's not all rainbow and sunshine with arsd CGI. It does not support all the features you might get out of the box with Vibe.d such a SSL cert integration (you may use NGINX as a proxy to handle SSL). This might be good thing or bad depending on what you are used to or your use case. As mentioned, arsd CGI is just one module in a whole collection. It's meant for you to pick and choose additional modules based on your needs including packages available in the D package repository.