Http Server in Lisp
Here’s the translation of the HTTP Server example from Go to Lisp (Common Lisp), formatted in Markdown suitable for Hugo:
(ql:quickload '(:hunchentoot :cl-who))
(defpackage :http-server
(:use :cl :hunchentoot :cl-who))
(in-package :http-server)
;; A fundamental concept in web servers is handlers. In Hunchentoot,
;; we define handlers using the define-easy-handler macro.
(define-easy-handler (hello :uri "/hello") ()
;; This handler simply returns "hello" as the response.
"hello")
(define-easy-handler (headers :uri "/headers") ()
;; This handler does something a little more sophisticated
;; by reading all the HTTP request headers and echoing them
;; into the response body.
(with-html-output-to-string (s)
(loop for (key . value) in (hunchentoot:headers-in*)
do (format s "~A: ~A~%" key value))))
(defun main ()
;; We create a new Hunchentoot server instance
(let ((server (make-instance 'easy-acceptor :port 8090)))
;; Start the server
(start server)
;; Keep the program running
(loop (sleep 1))))
;; To run the server, evaluate (main) in your Lisp REPLThis Lisp code creates a simple HTTP server using the Hunchentoot web server library. Here’s a breakdown of what’s happening:
We load the necessary libraries: Hunchentoot for the web server and CL-WHO for HTML generation (although we don’t use it in this example, it’s often useful for web development in Common Lisp).
We define two handlers:
- The
hellohandler simply returns “hello” when accessed at the “/hello” URI. - The
headershandler reads all the HTTP request headers and returns them as the response when accessed at the “/headers” URI.
- The
In the
mainfunction, we create a new Hunchentoot server instance listening on port 8090 and start it.The server runs indefinitely due to the infinite loop at the end of
main.
To run the server, you would evaluate (main) in your Lisp REPL. Then you can access it like this:
$ curl localhost:8090/hello
hello
$ curl localhost:8090/headers
Host: localhost:8090
User-Agent: curl/7.68.0
Accept: */*Note that in Lisp, we don’t typically compile to standalone executables as often as in some other languages. Instead, it’s common to load the code into a Lisp image and run it from there. However, it is possible to create standalone executables from Lisp programs if needed, using tools like ASDF and your Lisp implementation’s saving facilities.