Ring

Ring - самая распространенная абстракция web сервера в clojure. Вдохновлен ruby rack, python wsgi.

Обработчик запроса - простая функция, принимающая запрос, и возвращающая ответ. И запрос и ответ - простые clojure структуры:

(defn handler [req]
  {:status 200
   :headers {}
   :body (:uri req)})

В этом примере всегда отвечаем 200, а в теле ответа будет Uri.

Для добавления различного функционала мы можем использовать функции обертки - middleware:

(def app (-> handler
             (wrap-content-type "text/html")
             (wrap-keyword-params)
             (wrap-params)))

Middleware устроена следующим образом:

(defn wrap-example [handler some-args]
  (fn [req]
    (let [req  (change-req req]
          resp (handler req)
          resp (change-resp resp)]
      resp)))

Т.е. middleware должна принять обработчик, некоторые параметры и вернуть новый обработчик.

Подробнее про структуру запросов и ответов, обработчики и middleware можно почитать в wiki проекта.

Server

Ring - абстракция над веб-сервером, а их может быть много, например:

Мы будем использовать jetty. Для этого нужно подключить 2 зависимости:

  • ring/ring-core {:mvn/version "1.6.2"}
  • ring/ring-jetty-adapter {:mvn/version "1.6.2"}
(ns app.app
  (:require
   [clojure.pprint :as pp]
   [ring.adapter.jetty :as jetty]))

(defn handler [req]
  {:status 200
   :headers {"Content-Type" "text/plain"}
   :body (with-out-str (pp/pprint req))})

(jetty/run-jetty handler {:port 4445})

Этот пример запускает http сервер на 4445 порту. В ответ на любой запрос тело ответа будет содержать красиво распечатанный запрос.

Другие проекты

Есть и другие, несовместимые с ring, проекты: