Http Server in Clojure

Here’s the translation of the HTTP server example from Go to Clojure, formatted in Markdown for Hugo:

(ns http-server
  (:require [ring.adapter.jetty :as jetty]
            [ring.util.response :as response]))

;; A fundamental concept in HTTP servers is handlers. A handler is a function
;; that takes a request map and returns a response map. This is similar to
;; the http.Handler interface in other languages.

(defn hello [request]
  ;; Functions serving as handlers take a request map as an argument.
  ;; The response is a map containing the response body and any headers.
  ;; Here our simple response is just "hello\n".
  (-> (response/response "hello\n")
      (response/content-type "text/plain")))

(defn headers [request]
  ;; This handler does something a little more sophisticated by reading
  ;; all the HTTP request headers and echoing them into the response body.
  (let [headers (:headers request)
        header-strings (for [[name value] headers]
                         (str name ": " value))]
    (-> (response/response (clojure.string/join "\n" header-strings))
        (response/content-type "text/plain"))))

(defn -main []
  ;; We define our routes using a map where the keys are the routes
  ;; and the values are the corresponding handler functions.
  (let [routes {"/" hello
                "/headers" headers}
        handler (fn [request]
                  (if-let [handler (routes (:uri request))]
                    (handler request)
                    {:status 404
                     :body "Not Found"}))]
    ;; Finally, we start the server using ring-jetty-adapter.
    ;; We pass it our handler function and the port to listen on.
    (jetty/run-jetty handler {:port 8090})))

To run this Clojure HTTP server:

  1. Make sure you have Clojure and Leiningen installed.
  2. Create a new Clojure project:
$ lein new app http-server
$ cd http-server
  1. Replace the contents of src/http_server/core.clj with the code above.

  2. Add the following dependencies to your project.clj:

:dependencies [[org.clojure/clojure "1.10.1"]
               [ring/ring-core "1.9.5"]
               [ring/ring-jetty-adapter "1.9.5"]]
  1. Run the server:
$ lein run

The server will start and listen on port 8090.

You can then access the routes:

$ curl localhost:8090/hello
hello

$ curl localhost:8090/headers
User-Agent: curl/7.64.1
Accept: */*

This Clojure version uses the Ring library, which is a popular choice for building web applications in Clojure. It provides a similar abstraction to the net/http package, with handlers being simple functions that take a request map and return a response map.

The structure is similar to the original example, with two handler functions (hello and headers) and a main function that sets up the routes and starts the server. The main differences are in the syntax and the way routes are defined and matched, which is more idiomatic to Clojure.