Improve README (finally)

This commit is contained in:
2026-02-01 15:16:11 +01:00
parent 449a4a7d75
commit a569c30771

View File

@@ -9,6 +9,9 @@ endpoints :
* `POST /items`: creates an item
* `GET /items`: returns the list of items
This was a great opportunity for me to learn more about Clojure. Whatever the
result of the recruitment process, it was really fun working on this assignment!
## Running and testing
This project uses Leiningen. Assuming you already have Leiningen installed,
@@ -31,13 +34,85 @@ The source code lies in `/src/yohoho` and is structured as follows:
* `routes.clj`: API routes
* `schemas.cls`: Malli schemas used for validation
## Library choices
## Library/tools choices
* `reitit`: for handling routes
* `jetty`: web server
* `muuntaja`: JSON handling
* `next.jdbc`: database interface (SQLite)
* `malli`: validation
Since this is just a small assignment, I sticked to simple and proven tools:
* SQLite for the database (easy to setup, easy to use with `next.jdbc`)
* Leiningen for managing the project (it seems to be getting outdated in favor
of Clojure CLI Tools, but is still widely used and I could find more
documentation)
* Libraries : `reitit` for route handling + `malli` for validation + `muuntaja`
for handling json content. Thanks for the suggestions in the assignment! I
chose `reitit` because it seemed more complete/integrated than Compojure.
However, in the context of this simple assignment, Compojure may have been a
better choice (would have probably been easier to learn)
* Web server: `jetty` (seems to be pretty standard)
## Comments
Respect of the assignment:
* The API features the `POST /items` and `GET /items` endpoints
* `POST /items` accepts a JSON payload, validates it and returns HTTP 400 is
validation fails
* `POST /items` persists data in SQLite
* `GET /items` returns the list of all items as JSON.
* The structure of the items is respected, although it just includes the bare
minimum (id, name, email).
* A data validation library is used (`malli`)
* Unit tests were written (although generated with the help of Claude Code)
* Integration tests were written (although generated with the help of Claude
Code too)
* The API is documented (OpenAPI `/openapi.json` + Swagger UI at `/doc`)
Divergences from the assignment:
* The `POST /items` do not take the id in the input. Instead, I prefer to let
the database generate a new id on its own.
* As a consequence, the `id` of an item is an integer, not a string. SQLite can
autogenerate/autoincrement only on a integer id.
What was not part of the assignment:
* `GET /ahoy` health check endpoint. As you may guess, this was my very first
endpoint as I was learning how to use `reitit`. I decided to keep it, because
a health check endpoint cannot hurt.
* `GET /item/:id` was included. This was quite easy to add, and also makes sense
since the `POST /items` endpoint follows standard practice of returning a
`Location` header for the newly created item.
Security:
* SQL injections: we should be ok since we are not using raw SQL statements in
`db.clj` (`next.jdbc` will use parametrized statements under the hood)
* `POST /items` input has validation
* See the "Desirable improvement" section for some missing security features
## Desirable improvements
This project is voluntarily kept simple. If it were to get deployed in
production, the following should be dealt with, in no particular order:
* `GET /items`: add pagination
* Security: Add rate limiting
* Security: Add authentication/authorization
* Security: Add and configure CORS middleware
* Add logging
* TLS: it's fine that the API is accessible only through http, but it should be
deployed behind a reverse proxy to add TLS/https support. This is quite easy
to do with Apache, Nginx or Caddy.
* Database: use a migration system. This was definitely unnecessary for this
assignment, but should be used for a more serious project. Migratus seems to
be the de-facto library for this.
* Database: switch to a more serious database (PostgreSQL comes to mind), add
connection pooling, use transactions.
* Add metrics (request rate, response time, database connection
pool stats, etc.) and monitoring (eg. using Datadog).
* Configuration: add the ability to override deffault configuration using a
dotenv file and/or environment variables.
* Add a supervisor to ensure the API keeps running (could be as easy as using
systemd, or as complex as deploying with kubernetes)
## Documentation links