CRUD web APIs using the Racket web server

Writing sophisticated web services in Racket is possible, but upon reading the official documentation, you might not feel that way. The truth is that you can make modern CRUD (create, read, update, delete) HTTP APIs (by which I mean web applications that aren’t necessarily generate HTML, to be accessed and handled by a web browser) straightforwardly, all using Racket’s built-in web server. In this post I’ve got some starter code that should give you an idea of how this kind of web application can be written.

Before diving into the code, let’s begin by describing, first, what our application is supposed to do. Imagine that we’re dealing only with a part of a whole web application. Let’s concentrate on just one bit, with the understanding that we can flesh out the application in other ways using code not given here.

Imagine a web service that handles a catalog that can be modified. The URLs look like this:

URLMethodsDescription
/catalogGETA JSON rendering of the current catalog database
/catalog/123GETA string showing the current value (returning 404 if does not yet exist)
PUTUnconditionally associate (possibly overwriting) a value
DELETEUnconditionally delete 123 from the catalog database (succeeding even if it does not exist at the time)

The idea is that we can fetch the whole catalog, and get a JSON object back. We can add items to and delete items from the catalog. Item identifiers are simply integers.

Some features are missing, such as authentication. But that’s a whole other ball of wax.

Here’s the code (let’s call it crud.rkt):

Things get going at the very bottom, with dispatch-rules. There, we define the routes (URLs) that interest us. It closely parallels the table above.

One thing to notice at the very bottom of the module is the #:servlet-regexp #rx”” that makes sure that every request gets handled by our code above. We do not want the built-in Racket web server to helpfully return a response that we do not explicitly handle. Notice that in the dispatch-rules we have a fallback clause that calls the not-found function (which we define here) that simply generates a 404 response.

Another thing to notice how exceptions are used to make sure that we are really dealing with input that we know how to handle. The idea, specifically, is that we want an the value of an item to be a UTF-8 string. But our input is a sequence of bytes. Many sequences of bytes are not valid UTF-8 strings, so we need to check that we’re dealing with a legitimate byte string.

This code could be tightened up in certain respects. And, again, it is obviously but one piece of a larger site. But hopefully this is enough to give you a sense for how to get started with this kind of web programming in Racket.

Using the server

There are a couple ways to run the server: at the command line or with DrRacket.

To run the server on the command line, just do:

racket crud.rkt

If you’d like to run the code in DrRacket, just open crud.rkt there and hit Run. In the definitions are, you won’t see any output, but the server is running. (Do you see the little DrRacket running man in the lower right corner?

How about testing our mini CRUD service? There are, again, many ways to do this. Here’s a simple way to do it in the shell. Try:

curl -X PUT --data “hi there” http://127.0.0.1:6892/catalog/123

You should see no output. If you’re curious, try adding --verbose to the curl command.

curl -X GET http://127.0.0.1:6892/catalog/123
hi there

Play around with other URLs using curl or any other tool of your choose to get a feel for what this little server can do.