Liking cljdoc? Tell your friends :D
All platforms.

koine.server

Inbound HTTP, portable. One path, one handler fn, every host.

Deliberately minimal. The use case is a JSON-RPC endpoint (toolnexus SPEC §7B/§7C): a request comes in on ONE path, a string body goes in, a string body comes out. There is no routing table, no middleware, no static files, no websockets, no TLS — every one of those multiplies the surface that has to agree across both hosts, and none of them is needed.

(def h (server/serve (fn [req] {:status 200 :body (:body req)})
                     {:port 0}))
(server/port h)   ; => 54321
(server/stop! h)  ; => nil, idempotent

handler : request-map -> response-map request {:method :post :path "/" :headers {"content-type" "…"} :body "…"} response {:status 200 :headers {…} :body "…"} ; :status defaults to 200, ; :headers to {}, :body to ""

Normalised across hosts: :method is always a lower-case keyword, :headers keys are always lower-case strings with a single string value (first value wins on repeats), :body is always a string — never nil.

Host support (measured 2026-07-27, see the porting notes at the bottom):

hostserve:port 0stop!:host
jvmyesyesyesyes
cljgoyesyesyesno

Where a host cannot do something it throws a named, actionable error at the point of use rather than pretending.

Inbound HTTP, portable. One path, one handler fn, every host.

Deliberately minimal. The use case is a JSON-RPC endpoint (toolnexus
SPEC §7B/§7C): a request comes in on ONE path, a string body goes in, a
string body comes out. There is no routing table, no middleware, no
static files, no websockets, no TLS — every one of those multiplies the
surface that has to agree across both hosts, and none of them is needed.

    (def h (server/serve (fn [req] {:status 200 :body (:body req)})
                         {:port 0}))
    (server/port h)   ; => 54321
    (server/stop! h)  ; => nil, idempotent

handler : request-map -> response-map
  request  {:method :post :path "/" :headers {"content-type" "…"} :body "…"}
  response {:status 200 :headers {…} :body "…"}   ; :status defaults to 200,
                                                    ; :headers to {}, :body to ""

Normalised across hosts: `:method` is always a lower-case keyword,
`:headers` keys are always lower-case strings with a single string value
(first value wins on repeats), `:body` is always a string — never nil.

Host support (measured 2026-07-27, see the porting notes at the bottom):

| host    | serve | :port 0 | stop! | :host |
|---------|-------|---------|-------|-------|
| jvm     | yes   | yes     | yes   | yes   |
| cljgo   | yes   | yes     | yes   | no    |

Where a host cannot do something it throws a named, actionable error at
the point of use rather than pretending.
raw docstring

portclj/s

(port handle)

The port the server is actually bound to. The reason :port 0 is worth having: on the JVM and cljgo this is the OS-assigned port.

The port the server is actually bound to. The reason `:port 0` is worth
having: on the JVM and cljgo this is the OS-assigned port.
sourceraw docstring

serveclj/s

(serve handler {:keys [port host path] :or {port 0 host "127.0.0.1" path "/"}})

Start an HTTP server that sends every request on path to handler.

opts: {:port 8080 ; 0 = pick a free port, where the host allows it :host "127.0.0.1" :path "/"} ; catch-all; see the caveat below

Returns an opaque handle for port and stop!.

The default :path of "/" is a prefix/catch-all on both hosts and is the only value that behaves identically everywhere — cljgo's serve takes no pattern at all, so a non-"/" path is NOT enforced there. The handler always receives :path, so filter in the handler if it matters.

Start an HTTP server that sends every request on `path` to `handler`.

opts: {:port 8080          ; 0 = pick a free port, where the host allows it
       :host "127.0.0.1"
       :path "/"}          ; catch-all; see the caveat below

Returns an opaque handle for `port` and `stop!`.

The default `:path` of "/" is a prefix/catch-all on both hosts and is
the only value that behaves identically everywhere — cljgo's `serve`
takes no pattern at all, so a non-"/" path is NOT enforced there. The
handler always receives `:path`, so filter in the handler if it matters.
sourceraw docstring

stop!clj/s

(stop! handle)

Shut the server down. Returns nil. Idempotent — the second call is a no-op, so teardown can be unconditional.

Shut the server down. Returns nil. Idempotent — the second call is a
no-op, so teardown can be unconditional.
sourceraw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close