URL dispatching in Racket without continuations
The tutorial for the web server in Racket can be difficult to follow because it jumps rather quickly into the subject of continuations. Continuations are a powerful concept in programming that comes from Racket's Scheme background. But they're difficult to wrap your head around. Racket is great, but do you really need to know about continuations just to make a simple web application? Since the subject appears so early in the discussion, it's easy to conclude that, yes, you do need to know about this somewhat advanced concept.
And then give up.
The good news is that you don't need to know about continuations. The web server module and its various submodules are all great, and it would be a shame to ignore them, or conclude that you need to build up your own thing from scratch. And it would really be a shame if you had to give up on Racket entirely.
Despite appearances, you can them to build a conventional URL-based dispatching web application.
Here's some starter code to get you going. Before diving in, let's orient ourselves. Here's what we'll build:
- A single route (URL) with a template file attached to it. It will behave one way when dealing with a GET request, and another way when dealing with all other HTTP methods.
- A fallback that handles everything else (which will result in an 404 HTTP response). There will be an HTML template attached to this fallback, too.
The idea is that by showing you how you can handle a single URL using a traditional dispatch style, without a continuation in sight, you'll gain the confidence to keep going with your Racket web adventures.
Here's the starter code. There's only a single Racket source file,
hello.rkt, and four HTML template files:
- Complain that one is using a disallowed HTTP method
- When a route could not be found.
- The main view. Uses
- Prints a description list of all the query parameters.
Here's the code:
We are using a number of bits from the web-server module, but the most interesting is
dispatch-rules. As the name suggests, this function gives us a way of defining our dispatch function. For us, there are three rules:
- how to handle GET requests for /hello,
- how to handle any other request for /hello (that's what the
#:methodbit is all about), and finally
- a fallback in case neither the first nor the second rule apply.
To get started, run Racket and evaluate
(serve/servlet dispatcher #:servlet-regexp #rx"" #:launch-browser? #f)
The main thing is to use the
Make sure to include the
#:servlet-regexp keyword, with the value
#f. That ensures that our servlet handles every request whatsoever, with no magic default fallbacks. (The trick here is to exploit the fact that every string matches the empty string, when the empty string is viewed as a regular expression.) It doesn't have to be that way, of course. If, for instance, you want to serve some static files, that's fine. I prefer to define all possible behavior of my servlets, which is on display here. Your HTTP coding taste may vary.
#:launch-browser #f bit ensures that Racket doesn't open my web browser. By default, it will.
This application is, clearly, rather thin. It doesn't even really do anything. My hope, though, is that this starter code helps you to explore the possibilities in making web applications in Racket without getting confounded by continuations.