Building Middleware

This page is very incomplete and a work in progress.


This part of the documentation aims to guide you in the process of implementing nREPL middleware. We’ll cover the basics, the best practices and some of the common pitfalls you might encounter.

This page complements the middleware design documentation. Make sure you’re familiar with it before proceeding to implement any middleware.



Best Practices

In this section we’ll go over some of the best practices for implementing nREPL middleware.

Naming conventions

It’s recommended to prefix middleware names with wrap - e.g. wrap-complete, wrap-lookup, etc. This naming convention came from Ring middleware, which was a major influence on the design of nREPL.

nREPL itself breaks this convention with names like add-stdin and interruptible-eval, but those names are historical and hard to change at this point.

When it comes to ops, ideally their names should be verbs - e.g. complete, lookup, test, etc. Related ops can be grouped under some common prefix - e.g. test-var, test-ns, test-all.

It’s also prudent to prefix op names with some "namespace"-like prefix to avoid conflicts between different middlewares - e.g. project-name/op-name.

That’s the reason why nREPL’s completion op is named completion instead of complete. cider-nrepl already has an op named complete and adding such an op to nREPL would have introduced some non-deterministic behaviour when it comes to the ordering of the two competing completion middlewares. As a result, in some cases you’d be invoking nREPL’s op and in other cases cider-nrepl’s op. If `cider-nrepl had named the op cider/complete instead, that would have prevented this unfortunate situation.

Additional Resources