Run the following code in your terminal
lein new xiana todo-app
This will create a directory todo-app containing project scaffold.
Run the following command from the newly created project directory to fetch frontend dependencies
lein shadow npm-deps
You need to have docker and docker-compose installed on your machine for the following command to work. Run the following from the root directory of your project.
docker-compose up -d
This should spin up a PostgreSQL database on port 5433. Name of the DB is todo_app You can verify that the database is running by connecting to it. Value of username and password is postgres.
docker exec -it todo-app_db_1 psql -U postgres -d todo_app
which should open a PostgreSQL shell if successful.
On application start, the framework will look for database migrations located in the configured location. By default, this location is set to resources/migrations directory*.*
It is possible to create migrations by running from the project directory
lein migrate create -n todos -d resources/migrations/common/
This will create two migration files inside the resources/migrations/common directory. Both file names will be prefixed by the timestamp value of the file creation.
Put the following SQL code inside the todos-up.sql file
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
--;;
CREATE TABLE todos
(
    id uuid NOT NULL DEFAULT uuid_generate_v4() PRIMARY KEY,
    label varchar(2048) NOT NULL,
    done boolean NOT NULL DEFAULT false,
    created_at timestamptz NOT NULL DEFAULT now()
);
--;;
INSERT INTO todos (label) values ('example label from DB');
and this one into the todos-down.sql file.
DROP TABLE todos;
Routes definition can be found in the src/backend/todo_app/core.clj file. Replace the routes definition with following code.
(def routes
  [["/api/todos" {:action #'fetch}]])
define a function to be called when the endpoint is hit.
(defn fetch
  [state]
  state)
Now you need to reload the changed files to REPL and restart the application by executing start-dev-system function once again. Now opening http://localhost:3000/api/todos in your browser returns a blank page.
Change the implementation of fetch function to display "Hello World!" every time our endpoint is hit.
(defn fetch
  [state]
  (assoc state :response {:status 200
                          :body "Hello World!"}))
Reload the modified function and restart the application.
Change the implementation of function fetch once again and create a new view function.
Function:
(defn view
  [{{db-data :db-data} :response-data :as state}]
  (assoc state :response {:status 200
                          :body (map :todos/label db-data)}))
(defn fetch
  [state]
  (assoc state
         :view view
         :query {:select [:*] :from [:todos]}))
Again, reload the modified function and restart the application.
After running following curl command from your shell, live data from your database should appear on your screen.
curl http://localhost:3000/api/todos
Add following dependencies into project.clj file.
(defproject
  ...
  :dependencies [
    ...
    [cljs-ajax "0.8.4"]
    [day8.re-frame/http-fx "0.2.3"]
    ...
    ]
  ...
  )
File src/frontend/todo_app/db.cljs contains initial value of re-frame database. Inside of this file replace value of default-db to following:
(def default-db
  {:todos []})
Replace contents of src/frontend/todo_app/events.cljs file with the following code:
(ns todo-app.events
  (:require
   [re-frame.core :as re-frame]
   [ajax.core :as ajax]
   [day8.re-frame.http-fx]
   [todo-app.db :as db]
   ))
(defn url [tail] (str "http://localhost:3000" tail))
(re-frame/reg-event-db
 ::initialize-db
 (fn [_ _]
   db/default-db))
(re-frame/reg-event-db
 ::add-todos->db
 (fn [db [_ response]]
   (assoc db :todos response)))
(re-frame/reg-event-db
 ::failure
 (fn [db _]
   (js/console.error "Something is wrong!")
   db))
(re-frame/reg-event-fx
 ::fetch-todos!
 (fn [_ [_]]
   (js/console.info "Fetching todos!")
   {:http-xhrio {:uri (url "/api/todos")
                 :response-format (ajax/json-response-format {:keywords? true})
                 :format (ajax/json-request-format)
                 :on-success [::add-todos->db]
                 :on-failure [::failure]}}))
Replace contents of src/frontend/todo_app/subs.cljs file with the following code:
(ns todo-app.subs
  (:require
   [re-frame.core :as re-frame]))
(re-frame/reg-sub
  ::todos
  (fn [db]
    (:todos db)))
Replace contents of src/frontend/todo_app/views.cljs file with the following code:
(ns todo-app.views
  (:require
   [re-frame.core :as re-frame]
   [todo-app.events :as events]
   [todo-app.subs :as subs]))
(defn main-panel []
  (re-frame/dispatch [::events/fetch-todos!])
  (let [todos (re-frame/subscribe [::subs/todos])]
    [:div
      (map #(identity [:ul  %])
           @todos)]))
Update routes definition in file src/backend/todo_app/core.clj to following:
(def routes
  [["/todos" {:action #'re-frame/handle-index}]
   ["/assets/*" (ring/create-resource-handler {:path "/"})]
   ["/api" {}
    ["/todos" {:get {:action #'fetch}}]]])
Again, reload the modified code and restart the application. After opening http://localhost:3000/todos in your browser, it returns a page containing the data from our database that looks like this:

Left as an exercise for the reader.
Can you improve this documentation? These fine people already did:
Frankline Apiyo, Grigory Glushko, Stas Makarov, Krisztian Gulyas, Yacobh & IainEdit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs | 
| ← | Move to previous article | 
| → | Move to next article | 
| Ctrl+/ | Jump to the search field |