crud is written in Clojure, a functional and dynamically typed language. It was choosen because of its philosophy around data manipulation (highlights: dynamic typing, simple data structures, nil-punning) and its great developer experience.
To persist the data crud connects to a MongoDB. Its hands-off approach to the structuring of data made it a great fit with what crud is trying to provide. Besides MongoDB, there is also a second implementation of the persistence layer which uses Clojure Atoms to store data in-memory.
Clojure being a JVM hosted language opens up a lot of options when it comes to hosting and http servers. As of right now Clojure's http-kit was choosen, as it was packaged with the Luminus framework. Though it makes sense to switch to Jetty once performance trumps development velocity in terms of priority.
Currently there are many different ways to deploy crud. With Docker being the recommended way to self-host, as it's the quickest.
In the future an SQL implementation would be great as it would allow to embed a SQLite, thus providing persistence with improved protability.
If you want to look at the code or have ideas on how to improve crud further feel free to checkout our repo.
The major namespaces the following:
Name | Purpose |
---|---|
crud.logic.core |
Business Logic |
crud.entrypoint.core |
Glue routes, wrappers and logic together |
crud.persistence.core |
Protocol and implementation for persistence |
Also important is the crud.config
namespace which provides a summary of all configurations for easy consumption. The application itself is started in crud.core
.
crud has the usual layers of a Web API:
Name | Purpose |
---|---|
entrypoint.core |
Glue everything together |
entrypoint.wrappers |
Setup, parse, reject request/response etc. |
entrypoint.routes |
Route request to destination |
logic.core |
Consum request |
persistence.protocol |
Provide basic functions to access data |
To take advantage of Clojure's nil-punning and the REPL-driven development everything returned by each layer is in form of a [data error]
tuple. This both encapsulates the error- and succes-case. If an error occurs data
will be nil
and a :message
key will be present inside of error
. If the action was sucessful error
will be nil
.
This blog post talks more about the [data error]
tuple.
Last Edited: 2023.01.09; crud:1.2.0