This is a simple web application using Component, Ring, Compojure, and Selmer connected to a local SQLite database.
Clojure beginners often ask for a "complete" example that they can look at to see how these common libraries fit together so this is a self-contained repo containing a fully-functional web app example.
On this branch, it has been migrated to the Polylith architecture:
Following Polylith's Transitioning to Polylith guide, steps 1 & 2 were:
- The entire application was moved to
bases/webwithout any renaming, workspace.ednwas added,- A development
deps.ednfile was added at the root, - The application can be built in
projects/usermanager, - The application can be run in
:devmode, - The tests can all be run via the
polytool.
Step 3 was:
- The application was split into
bases/webandcomponents/usermanager, namespaces were updated to reflect the full split (usermanager.web.mainandusermanager.usermanager.apiwere the two entry points; the oldusermanager.model.user-managerbecameusermanager.usermanager.modelto implement theapi).
Step 4, over several iterations, was:
- In preparation for adding more
componentsas I refactored the code, I switched back to the more standardinterfacenaming convention fromapi(which worked for the somewhat monolithic component identified in Step 2). Sousermanager.usermanager.interfacebecame the main component entry point andusermanager.usermanager.modelimplemented thatinterface. - Then I refactored the monolithic
usermanagercomponent intoapp-state,database,department,schema,schema-fixture(test-only),user, andweb-servercomponents. schemahas a subinterface for each table, so that new tables can be added and they are created and populated on the first run of the application without affecting previously created tables.- You still start the application with
clojure -M:dev -m usermanager.web.main(with an optional port number). - You still build the uberjar with
(cd projects/usermanager && clojure -X:uberjar) - You still run the uberjar with
java -jar projects/usermanager/usermanager.jar(with an optional port number). - You can run tests for code that has changed since the last stable tag with
clojure -M:poly test(optionally with:projectto also run project tests). You can run the entire suite of tests withclojure -M:poly test :all :dev.
A variant of the non-Polylith version of this example application, using Integrant and Reitit (instead of Component and Compojure), can be found in Michaël Salihi's repo.
This example assumes that you have a recent version of the Clojure CLI installed (at least 1.10.1.727), and provides a deps.edn file.
Clojure 1.10 (or later) is required. The "model" of this example app uses namespace-qualified keys in hash maps. It uses next.jdbc -- the "next generation" JDBC library for Clojure -- which produces namespace-qualified hash maps from result sets.
Clone the repo, cd into it, change to the polylith branch git checkout polylith and then see below to run the application (from the command-line or in a REPL), run the tests, build an uberjar, and run the uberjar.
You can run the application from the root of the workspace:
clojure -M:dev -m usermanager.web.main
It should create a SQLite database (usermanager_db) and populate two tables (department and addressbook) and start a Jetty instance on port 8080.
If that port is in use, start it on a different port. For example, port 8100:
clojure -M:dev -m usermanager.web.main 8100
Start REPL
$ clj -M:dev
Once REPL starts, start the server on port 8888, for example:
user=> (require 'usermanager.web.main) ; load the code
user=> (in-ns 'usermanager.web.main) ; move to the namesapce
usermanager.web.main=> (def system (new-system 8888)) ; specify port
usermanager.web.main=> (alter-var-root #'system component/start) ; start the serverWhen you exit the REPL, the server will shutdown. You can shut it down in the REPL like this:
usermanager.web.main=> (alter-var-root #'system component/stop) ; stop the serverYou can run all the tests via Polylith's poly tool:
clojure -M:poly test :all :dev
Normally you would just use clojure -M:poly test or clojure -M:poly test :dev to run tests that depend on code that has changed since your last stable commit (see the Polylith documentation for more details).
To build a compiled, runnable JAR file:
(cd projects/usermanager && clojure -T:build uber)
This uses tools.build under the hood to AOT-compile usermanager.web.main and build usermanager-standalone.jar in the projects/usermanager/target folder.
To run that uberjar:
java -jar projects/usermanager/target/usermanager-standalone.jar
As with running the application from the Clojure CLI or the REPL above, this should create a SQLite database (usermanager_db) and populate two tables (department and addressbook) and start a Jetty instance on port 8080.
If that port is in use, start it on a different port. For example, port 8100:
java -jar projects/usermanager/target/usermanager-standalone.jar 8100
Stop the application with ctrl-C (^C) on Linux/macOS or ctrl-Z (^Z) on Windows.
Copyright (c) 2015-2023 Sean Corfield.
Distributed under the Apache Source License 2.0.
