Create REST API’s with FreePascal

Marcus Fernström
5 min readJul 3, 2019

--

I’m going to show you how to create a REST API using only the packages bundled with FreePascal and Lazarus, no frameworks or other tools needed.

We’ll end up with is a small executable webserver with two endpoints. The first will respond with the current time and the other with a friendly greeting.

Since JSON is the de-facto standard for moving non-binary data over the web we’ll use that.

Start Lazarus and select New -> Simple Program to create a no-frills project.

You’ll end up with something like this.

If you see {$R *.res} as above just remove it, we’re not using Lazarus resources.

Add {$mode objfpc}{$H+} to use object-fpc mode and turn on ansistrings.

First we need to add the packages we’ll be using.

Under the {$mode objfpc}{$H+} you just added, go ahead and add this uses block.

I’ve wrapped the cthreads and cmem in an ifdef block so you can copy and paste the code no matter if you’re on Windows, Linux, or MacOS.

uses
{$IFDEF UNIX}cthreads, cmem,{$ENDIF} sysutils, fphttpapp, httpdefs, httproute, fpjson, jsonparser;

The uses section defines the packages used in this specific Unit (The source file is a Unit).

And now we add the first procedure of our code, the timeEndpoint.

procedure timeEndpoint(req: TRequest; res: TResponse);
var
jObject : TJSONObject;
begin
jObject := TJSONObject.Create;
try
jObject.Strings['time'] := TimeToStr(Time);
res.Content := jObject.AsJSON;
res.Code := 200;
res.ContentType := 'application/json';
res.ContentLength := length(res.Content);
res.SendContent;
finally
jObject.Free;
end;
end;

We’re defining the jObject variable to be of type TJSONObject, a rich variable type which holds JSON data to be translated into a JSON object.

There are TJSON-types for all the JSON data types which gives us an easy way to work with data that is ultimately going to be formatted as JSON.

In the jObject we’re setting a string with the key time to the current time.

Next up all we need to do is set the response Content and send it on out.

TJSONObject has a function called AsJSON which outputs its data as a JSON formatted string.

Before we can actually try it out, we have to set up the server application.

Add the following code below the procedure

begin
Application.Port := 9080;
HTTPRouter.RegisterRoute('/time', @timeEndpoint, true);
Application.Threaded := true;
Application.Initialize;
Application.Run;
end.

All we need to do is set the port, register what route the procedure should fire on, set up the Application, and finally Run it.

Save and compile all that and open up http://localhost:9080/time in your browser, you should see something like

{ "time" : "21:39:38" }

And there you do, that’s all it took to create an API, grab the current time, and generate JSON.

Here’s the complete code so far.

Go ahead and shut down the server and we’ll create the next endpoint. This one will take a name as a url parameter and return a friendly greeting.

Add the second procedure like so

procedure greetingEndpoint(req: TRequest; res: TResponse);
var
jObject : TJSONObject;
begin
jObject := TJSONObject.Create;
try
jObject.Strings['greeting'] := 'Hello, ' + req.RouteParams['name'];
res.Content := jObject.AsJSON;
res.Code := 200;
res.ContentType := 'application/json';
res.ContentLength := length(res.Content);
res.SendContent;
finally
jObject.Free;
end;
end;

As you can see, it’s very similar to the timeEndpoint, except we’re concatenating the name parameter value instead of just returning a time string.

Before you can access it we need to register the path with RegisterRoute().

begin
Application.Port := 9080;
HTTPRouter.RegisterRoute('/time', @timeEndpoint, true);
HTTPRouter.RegisterRoute('/greeting/:name', @greetingEndpoint);
Application.Threaded := true;
Application.Initialize;
Application.Run;
end.

In the new Route we’re specifying a different path, /greeting/ and a variable called name. Also note the end of the RegisterRoute we don’t include a boolean.

That boolean is for setting the default path and we want /time to be the default.

And there you have it.

In less than 50 lines we’ve created a simple REST API with two endpoints, we generate JSON on-the-fly and accept parameter values, the world is our oyster.

There’s a bit of duplication though. Let’s simplify things a bit by creating a response procedure.

Add this procedure above the first endpoint procedure.

procedure jsonResponse(var res: TResponse; data: String);
begin
res.Content := data;
res.Code := 200;
res.ContentType := 'application/json';
res.ContentLength := length(res.Content);
res.SendContent;
end;

And to use it, we’ll change this

procedure timeEndpoint(req: TRequest; res: TResponse);
var
jObject : TJSONObject;
begin
jObject := TJSONObject.Create;
try
jObject.Strings['time'] := TimeToStr(Time);
res.Content := jObject.AsJSON;
res.Code := 200;
res.ContentType := 'application/json';
res.ContentLength := length(res.Content);
res.SendContent;
finally
jObject.Free;
end;
end;

to this

procedure timeEndpoint(req: TRequest; res: TResponse);
var
jObject : TJSONObject;
begin
jObject := TJSONObject.Create;
try
jObject.Strings['time'] := TimeToStr(Time);
jsonResponse(res, jObject.AsJSON);
finally
jObject.Free;
end;
end;

Now when you want to send a JSON response, just pass the response and whatever string you want to the jsonResponse procedure.

Notice that it doesn’t do any checking to make sure you’re sending valid JSON, that’s up to you before passing it a string to send.

Look at that, we’re right at 50 lines of code.

Here’s the complete program

program RestApi;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}cthreads, cmem,{$ENDIF}
SysUtils, fphttpapp, httpdefs, httproute, fpjson, jsonparser;
procedure jsonResponse(var res: TResponse; data: String);
begin
res.Content := data;
res.Code := 200;
res.ContentType := 'application/json';
res.ContentLength := length(res.Content);
res.SendContent;
end;
procedure timeEndpoint(req: TRequest; res: TResponse);
var
jObject : TJSONObject;
begin
jObject := TJSONObject.Create;
try
jObject.Strings['time'] := TimeToStr(Time);
jsonResponse(res, jObject.AsJSON);
finally
jObject.Free;
end;
end;
procedure greetingEndpoint(req: TRequest; res: TResponse);
var
jObject : TJSONObject;
begin
jObject := TJSONObject.Create;
try
jObject.Strings['greeting'] := 'Hello, ' + req.RouteParams['name'];
jsonResponse(res, jObject.AsJSON);
finally
jObject.Free;
end;
end;
begin
Application.Port := 9080;
HTTPRouter.RegisterRoute('/time', @timeEndpoint, true);
HTTPRouter.RegisterRoute('/greeting/:name', @greetingEndpoint);
Application.Threaded := true;
Application.Initialize;
Application.Run;
end.

In future articles I’ll show you how you can split things up into a better project structure, talk to databases, generate security tokens, rate limiting, and other useful things for web based APIs.

Happy coding!

--

--

Marcus Fernström

Sr. AppSec Engineer and Software Developer with a passion for open source. Historical Fencing instructor, and drinker of copious amounts of coffee and tea.