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 todos
This will create two migration files inside the resources/migrations directory. Both file names will be prefixed by the timestamp value of the file creation.
Put the following SQL code inside of 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]
(xiana.core/ok 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]
(xiana.core/ok (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}]
(xiana.core/ok (assoc state :response {:status 200
:body (mapv :todos/label db-data)})))
(defn fetch
[state]
(xiana.core/ok (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 databse. 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:
Yacobh & IainEdit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close