Coast is a full stack web framework written in Clojure for small teams or solo developers. It uses a relational database and renders html on the server without javascript which allows you to ship your web applications faster
(ns my-project
(:require [coast]))
(def routes [[:get "/" :home]])
(defn home [req]
[:h1 "You're coasting on clojure!"])
(def app (coast/app {:routes routes}))
(coast/server app {:port 1337})
- Make sure clojure is installed first
brew install clojure
- Install the coast cli script
curl -o /usr/local/bin/coast https://raw.githubusercontent.com/coast-framework/coast/master/coast && chmod a+x /usr/local/bin/coast
- Create a new coast project
coast new myapp && cd myapp
- Make sure you have bash, curl, rlwrap, and Java installed
curl -O https://download.clojure.org/install/linux-install-1.9.0.391.sh
chmod +x linux-install-1.9.0.391.sh
sudo ./linux-install-1.9.0.391.sh
- Install the coast cli script
sudo curl -o /usr/local/bin/coast https://raw.githubusercontent.com/coast-framework/coast/master/coast && sudo chmod a+x /usr/local/bin/coast
- Create a new coast project
coast new myapp && cd myapp
You should be greeted with the text "You're coasting on clojure!"
when you visit http://localhost:1337
This doc will take you from a fresh coast installation to a working todo list.
The first thing you do when you start a coast project? coast new
in your terminal:
coast new todos
This will make a new folder in the current directory named "todos". Let's get in there and see what's up:
cd todos
tree .
This will show you the layout of a default coast project:
.
├── Makefile
├── README.md
├── bin
│ └── repl.clj
├── deps.edn
├── resources
│ ├── assets.edn
│ └── public
│ ├── css
│ │ └── app.css
│ └── js
│ └── app.js
├── src
│ ├── components.clj
│ ├── error
│ │ ├── not_found.clj
│ │ └── server_error.clj
│ ├── home
│ │ └── index.clj
│ ├── routes.clj
│ └── server.clj
└── test
└── server_test.clj
9 directories, 14 file
For the sake of this tutorial, we want to show a list of todos as the first thing people see when they come to our site. In coast, that means making a place for these todos to live, in this case (and in every case): the database. Assuming your postgres server is up and running, you can make a database with a handy shortcut that coast gives you:
make db/create
# clj -A\:db/create
# Database todos_dev created successfully
This will create a database with the name of your project and whatever COAST_ENV
is set to, which by default is dev
. So the database name will be todos_dev
.
Now that the database is created, let's generate a migration:
coast gen migration add-todos
# resources/migrations/20180926190239_add_todos.edn created
This will create a file in resources/migrations
with a timestamp and whatever name you gave it, in this case: add_todos
. Let's fill it in with our first migration:
[{:db/col :todo/name
:db/type "text"}
{:db/col :todo/completed-at
:db/type "timestamptz"}]
This is edn, not sql, although sql migrations would work, in coast it's cooler if you use edn migrations for the sweet query power you'll have later. The left side of the /
is the name of the table, and the right side is the name of the column. Or in coast terms: :<resource>/<prop>
Let's apply this migration to the database
make db/migrate
# clj -A\:db/migrate
#
# -- Migrating: 20180926160239_add_todos ---------------------
#
# [#:db{:col :todo/name, :type text} #:db{:col :todo/completed-at, :type timestamptz}]
#
# -- 20180926160239_add_todos ---------------------
#
# 20180926160239_add_todos migrated successfully
This updates the database and creates a resources/schema.edn
file to keep track of relationships and things that don't normally fit in the database schema.
Now that the database has been migrated and we have a place to store the todos we want to show them too. This is where coast generators come in. Rather than you having to type everything out, generators are a way to get you started and you can customize from there.
This will create a file in the src
directory with the name of an action
. Coast is a pretty humble web framework, there's no FRP or graph query languages or anything. There are just five actions: create
, read
, update
, delete
, and list
. You can specify an action to generate or you can generate all five. Lets just generate the list file for now:
coast gen action todo:list
# src/todo/list.clj created successfully
This is specifying which resource (table) to generate and it puts a file in src/todo/list.clj
which looks like this:
(ns todo.list
(:require [coast :refer [pull q url-for validate]]))
(defn view [request]
(let [rows (q '[:pull [:todo/name :todo/completed-at]])]
[:table
[:thead
[:tr
[:th "name"]
[:th "completed-at"]]]
[:tbody
(for [row rows]
[:tr
[:td (:todo/name row)]
[:td (:todo/completed-at row)]])]]))
One thing coast doesn't do yet is update the routes file, let's do that now:
(ns routes)
(def routes [[:get "/" :home.index/view :home]
[:get "/404" :error.not-found/view :404]
[:get "/500" :error.server-error/view :500]
[:get "/todo/list" :todo.list/view]])
Now we can check it out in the browser, there's no styling or anything so it's not going to look amazing, start up a repl with make repl
and run (server/-main)
then go to http://localhost:1337/todo/list
to check out your handiwork.
Example projects and more coming soon...
The docs are still under construction, but there should be enough there to get a production-ready website off the ground
Any contribution is welcome! Submit a PR and let's get it merged in!
Coast on Clojure is released under the MIT License.