{"id":23070174,"url":"https://github.com/strojure/ring-undertow","last_synced_at":"2025-08-15T13:32:49.969Z","repository":{"id":64991122,"uuid":"579091205","full_name":"strojure/ring-undertow","owner":"strojure","description":" Clojure ring adapter to Undertow web server.","archived":false,"fork":false,"pushed_at":"2023-04-27T12:59:48.000Z","size":89,"stargazers_count":13,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"default","last_synced_at":"2024-08-09T21:27:03.306Z","etag":null,"topics":["clojure","http-handler","ring-adapter","undertow"],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/strojure.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-12-16T16:28:41.000Z","updated_at":"2023-11-20T01:00:33.000Z","dependencies_parsed_at":"2023-02-13T02:45:35.387Z","dependency_job_id":null,"html_url":"https://github.com/strojure/ring-undertow","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strojure%2Fring-undertow","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strojure%2Fring-undertow/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strojure%2Fring-undertow/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strojure%2Fring-undertow/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/strojure","download_url":"https://codeload.github.com/strojure/ring-undertow/tar.gz/refs/heads/default","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":229916377,"owners_count":18144131,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clojure","http-handler","ring-adapter","undertow"],"created_at":"2024-12-16T06:20:02.266Z","updated_at":"2024-12-16T06:20:02.837Z","avatar_url":"https://github.com/strojure.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ring-undertow\n\nClojure ring adapter to Undertow web server.\n\n[![Clojars Project](https://img.shields.io/clojars/v/com.github.strojure/ring-undertow.svg)](https://clojars.org/com.github.strojure/ring-undertow)\n\n[![cljdoc badge](https://cljdoc.org/badge/com.github.strojure/ring-undertow)](https://cljdoc.org/d/com.github.strojure/ring-undertow)\n[![tests](https://github.com/strojure/ring-undertow/actions/workflows/tests.yml/badge.svg)](https://github.com/strojure/ring-undertow/actions/workflows/tests.yml)\n\n## Motivation\n\n- Performant implementation of the Ring handler concept.\n- Lazy evaluation of request keys which are slow to compute but probably never\n  used.\n- Adopt features provided by underlying Undertow server, like sessions,\n  websockets or multiple handlers on single server instance.\n\n## Features\n\n- The handler implementation is decoupled\n  from [Undertow server API][github_undertow].\n\n- Ring [request map][ring_requests]:\n\n    - Does not contain deprecated keys.\n\n    - `:headers` is a persistent map proxy interface over Undertow header map.\n      Header names are case-insensitive. The proxy is converted to Clojure map\n      on updates.\n\n    - The request map itself is a [lazy map][github_zmap] with some values\n      delayed.\n\n    - Sessions work without additional middleware, only proper configuration of\n      the Undertow server is required.\n\n    - Does not contain rarely used keys like `:websocket?`. But this data can be\n      got from request using functions from the `strojure.ring-undertow.request`\n      namespace.\n\n- Ring [response][ring_response] allows `HttpHandler` in the `:body`, this\n  allows to easily initiate processing like websocket handshake.\n\n## Usage\n\n### Server\n\nThe library provides its own [functions][cljdoc_server] to start and stop\nserver. The [start][cljdoc_server_start] function enables ring handler adapter\n(sync or async) for all functions specified as handlers in server configuration.\n\n```clojure\n(ns usage.server\n  (:require [java-http-clj.core :as http]\n            [strojure.ring-undertow.server :as server]\n            [strojure.undertow.api.types :as types]))\n\n(defn ring-handler\n  \"The ring handler function, both sync and async.\"\n  ([request]\n   {:body (str \"Hello from \" (:server-name request) \" (sync)\")})\n  ([request respond raise]\n   (future\n     (try\n       (respond {:body (str \"Hello from \" (:server-name request) \" (async)\")})\n       (catch Throwable t\n         (raise t))))))\n\n(defn- run\n  \"Helper function to execute GET request, stop `server`, return response body.\"\n  [server]\n  (with-open [_ server]\n    (let [port (-\u003e server types/bean* :listenerInfo first :address :port)]\n      (:body (http/send {:uri (str \"http://localhost:\" port \"/\")})))))\n\n;; Synchronous ring handler\n(run (server/start {:port 0\n                    :handler ring-handler}))\n;; or\n(run (server/start {:port 0\n                    :handler ring-handler\n                    :ring-handler-type :sync}))\n\n;; Asynchronous ring handler\n(run (server/start {:port 0\n                    :handler ring-handler\n                    :ring-handler-type :async}))\n```\n\n### Handlers\n\nUndertow server allow to use multiple handler functions in various contexts.\nThis library provides [functions to create server handlers][cljdoc_handler] from\nClojure functions. For server configuration documentation\nsee [Undertow server API][github_undertow].\n\n```clojure\n(ns usage.handlers\n  (:require [java-http-clj.core :as http]\n            [strojure.ring-undertow.handler :as ring.handler]\n            [strojure.undertow.api.types :as types]\n            [strojure.undertow.server :as server]))\n\n(defn ring-handler\n  \"The ring handler function, both sync and async.\"\n  ([request]\n   {:body (str \"Hello from \" (:server-name request) \" (sync)\")})\n  ([request respond raise]\n   (future\n     (try\n       (respond {:body (str \"Hello from \" (:server-name request) \" (async)\")})\n       (catch Throwable t\n         (raise t))))))\n\n(defn- run\n  \"Helper function to start server with `config`, execute HTTP request, stop\n  server, return response body.\"\n  [config]\n  (with-open [server (server/start (assoc config :port 0))]\n    (:body (http/send {:uri (str \"http://localhost:\"\n                                 (-\u003e server types/bean* :listenerInfo first :address :port)\n                                 \"/\")}))))\n\n;; ## Explicit invocation of handler function\n\n;; Synchronous ring handler - explicitly\n(run {:handler (ring.handler/sync ring-handler)})\n;=\u003e \"Hello from localhost (sync)\"\n\n;; Asynchronous ring handler - explicitly\n(run {:handler (ring.handler/async ring-handler)})\n;=\u003e \"Hello from localhost (async)\"\n\n;; ## Using adapter configuration option\n\n;; Synchronous ring handler - adapter in configuration\n(run {:handler ring-handler, :handler-fn-adapter ring.handler/sync})\n;=\u003e \"Hello from localhost (sync)\"\n\n;; Asynchronous ring handler - adapter in configuration\n(run {:handler ring-handler, :handler-fn-adapter ring.handler/async})\n;=\u003e \"Hello from localhost (async)\"\n\n;; ## Using declarative handler configuration\n;;\n;; NOTE: The `strojure.ring-undertow.handler` namespace need to be imported.\n\n;; Synchronous ring handler - declarative\n(run {:handler {:type ring.handler/ring :ring-handler ring-handler}})\n;=\u003e \"Hello from localhost (sync)\"\n\n;; Asynchronous ring handler - declarative\n(run {:handler {:type ::ring.handler/ring :ring-handler ring-handler\n                :ring-handler-type :async}})\n;=\u003e \"Hello from localhost (async)\"\n\n;; ## Setting adapter globally before server start\n\n;; Synchronous ring handler - global assignment\n(do (server/set-handler-fn-adapter ring.handler/sync)\n    (run {:handler ring-handler}))\n;=\u003e \"Hello from localhost (sync)\"\n\n;; Asynchronous ring handler - global assignment\n(do (server/set-handler-fn-adapter ring.handler/async)\n    (run {:handler ring-handler}))\n;=\u003e \"Hello from localhost (async)\"\n```\n\n### Websockets\n\nWebsocket server handler can be setup without involving ring handlers like\ndescribed in [Undertow server API][github_undertow].\n\nBut it is also possible to return websocket handler in response `:body` to\nestablish websocket connection.\n\n```clojure\n(ns usage.websockets\n  (:require\n    [strojure.ring-undertow.request :as request]\n    [strojure.undertow.handler :as handler]\n    [strojure.undertow.websocket.channel :as channel]))\n\n(defn on-message\n  \"Websocket callback.\"\n  [{:keys [channel text]}]\n  (channel/send-text (str \"Received: \" text) channel nil))\n\n(defn ring-handler\n  \"Ring handler initiating websocket connection.\"\n  [request]\n  (if (request/websocket? request)\n    {:body (handler/websocket {:on-message on-message})}\n    {:status 400}))\n```\n\n### Request utility\n\nThere are [some utility functions][cljdoc_request] to get information from ring\nrequests which is not presented as request map keys.\n\n```clojure\n(ns usage.request\n  (:require [strojure.ring-undertow.request :as request]))\n\n;; Check if sessions are enabled in Undertow server configuration.\n\n(request/sessions-enabled? {})\n;=\u003e nil\n\n;; Check if request is websocket upgrade request.\n\n(request/websocket? {})\n;=\u003e nil\n\n(request/websocket? {:headers {\"upgrade\" \"unknown\"}})\n;=\u003e false\n\n(request/websocket? {:headers {\"upgrade\" \"websocket\"}})\n;=\u003e true\n```\n\n## Compatibility\n\nThere are another implementations of ring adapter for Undertow. This library\nprovides “adapters for adapters” for some of them:\n\n- The [server.luminus-adapter][cljdoc_server_luminus] namespace for the\n  [ring-undertow-adapter][github_luminus] in the Luminus framework.\n\n## Benchmarks\n\n- [request](doc/benchmark/ring_request.clj)\n- [headers](doc/benchmark/ring_request_headers.clj)\n\n---\n\n[github_undertow]:\nhttps://github.com/strojure/undertow\n\n[ring_requests]:\nhttps://github.com/ring-clojure/ring/wiki/Concepts#requests\n\n[ring_response]:\nhttps://github.com/ring-clojure/ring/wiki/Concepts#responses\n\n[github_zmap]:\nhttps://github.com/strojure/zmap\n\n[github_luminus]:\nhttps://github.com/luminus-framework/ring-undertow-adapter\n\n[cljdoc_server]:\nhttps://cljdoc.org/d/com.github.strojure/ring-undertow/CURRENT/api/strojure.ring-undertow.server\n\n[cljdoc_server_start]:\nhttps://cljdoc.org/d/com.github.strojure/ring-undertow/CURRENT/api/strojure.ring-undertow.server#start\n\n[cljdoc_request]:\nhttps://cljdoc.org/d/com.github.strojure/ring-undertow/CURRENT/api/strojure.ring-undertow.request\n\n[cljdoc_handler]:\nhttps://cljdoc.org/d/com.github.strojure/ring-undertow/CURRENT/api/strojure.ring-undertow.handler\n\n[cljdoc_server_luminus]:\nhttps://cljdoc.org/d/com.github.strojure/ring-undertow/CURRENT/api/strojure.ring-undertow.server.luminus-adapter\n\n[handler/dispatch]:\nhttps://cljdoc.org/d/com.github.strojure/undertow/CURRENT/api/strojure.undertow.handler#dispatch\n\n[handler/session]:\nhttps://cljdoc.org/d/com.github.strojure/undertow/CURRENT/api/strojure.undertow.handler#session\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstrojure%2Fring-undertow","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstrojure%2Fring-undertow","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstrojure%2Fring-undertow/lists"}