Handlers
Handlers are functions that accept a single incoming message as an argument. An nREPL server is started with a single handler function, which will be used to process messages for the lifetime of the server. Note that handler return values are ignored; results of performing operations should be sent back to the client via the transport in use (which will be explained shortly). This may seem peculiar, but is motivated by two factors:
-
Many operations — including something as simple as code evaluation — is fundamentally asynchronous with respect to the nREPL server
-
Many operations can produce multiple results (e.g. evaluating a snippet of code like
"(+ 1 2) (def a 6)"
).
Thus, messages provided to nREPL handlers are guaranteed to contain a
:transport
entry containing the transports that should be used
to send all responses precipitated by a given message. (This slot is added by
the nREPL server itself, thus, if a client sends any message containing a
"transport"
entry, it will be bashed out by the Transport
that was the
source of the message.) Further, all messages provided to nREPL handlers have
keyword keys (as per clojure.walk/keywordize-keys
).
Depending on its :op
, a message might be required to contain other slots, and
might optionally contain others. It is generally the case that request
messages should contain a globally-unique :id
.
Every request must provoke at least one and potentially many response messages,
each of which should contain an :id
slot echoing that of the provoking
request.
Once a handler has completely processed a message, a response
containing a :status
of :done
must be sent. Some operations necessitate
that additional responses related to the processing of a request are sent after
a :done
:status
is reported (e.g. delivering content written to out
by
evaluated code that started a future
).
Other statuses are possible, depending upon the semantics of the :op
being
handled; in particular, if the message is malformed or incomplete for a
particular :op
, then a response with an :error
:status
should be sent,
potentially with additional information about the nature of the problem.
It is possible for an nREPL server to send messages to a client that are not a
direct response to a request (e.g. streaming content written to System/out
might be started/stopped by requests, but messages containing such content
can’t be considered responses to those requests).
If the handler being used by an nREPL server does not recognize or cannot
perform the operation indicated by a request message’s :op
, then it should
respond with a message containing a :status
of "unknown-op"
.
It is currently the case that the handler provided as the :handler
to
nrepl.server/start-server
is generally built up as a result of
composing multiple pieces of middleware.