| CARVIEW |
Select Language
HTTP/2 200
server: GitHub.com
content-type: text/html; charset=utf-8
last-modified: Sat, 07 May 2022 16:41:03 GMT
access-control-allow-origin: *
etag: W/"6276a11f-1d75"
expires: Mon, 29 Dec 2025 22:41:53 GMT
cache-control: max-age=600
content-encoding: gzip
x-proxy-cache: MISS
x-github-request-id: F27E:2D64E0:951849:A76885:69530159
accept-ranges: bytes
age: 0
date: Mon, 29 Dec 2025 22:31:53 GMT
via: 1.1 varnish
x-served-by: cache-bom-vanm7210089-BOM
x-cache: MISS
x-cache-hits: 0
x-timer: S1767047513.448610,VS0,VE211
vary: Accept-Encoding
x-fastly-request-id: c0e137e8149a4da50dc18e74af86e75a44a5cce1
content-length: 2180
Joy Framework
Joy
A maximalist web framework for lisp aficionados
Use the janet programming language to build web apps faster with less code and very low memory usage.
(import joy :prefix "")
(route :get "/" :home)
(defn home [request]
(text/plain "You found joy!"))
(def app (app))
(server app 9001)Installation on macOS
Janet can be installed with homebrew:
brew install janet
Then to install joy:
jpm install joy
More installation options for janet here
HTML is data
Joy uses hiccup syntax to render html. There is no separate template language to learn! You have all of janet's power when writing html!
[:form
[:input {:type "text" :placeholder "Your name"}]
[:input {:type "email" :placeholder "Your email"}]
[:input {:type "submit" :value "Submit"}]]
<form>
<input type="text" placeholder="Your name" />
<input type="email" placeholder="Your email" />
<input type="submit" value="Submit" />
</form>
Use html inside of janet, not the other way around
(let [groceries [{:name "eggs"}
{:name "milk"}
{:name "tomatoes"}]]
[:ul
(foreach [g groceries]
[:li (g :name)])])
<ul>
<li>eggs</li>
<li>milk</li>
<li>tomatoes</li>
</ul>There is a shorthand for css classes too! Great for atomic css!
[:h1.text-2xl.text-gray-400
"You found joy!"]
<h1 class="text-2xl text-gray-400">You found joy!</h1>The real beauty of having a regular old data structure represent your html is that you can assign it to a variable and create your own names without changing the rendered html!
(def h1 :h1.text-2xl.text-gray-400)
[h1 "You found joy!"]<h1 class="text-2xl text-gray-400">You found joy!</h1>Everything is a function
Joy doesn't uses objects or classes. Everything is a function that takes a request and outputs a response
(use joy)
(route :get "/posts" :index)
(route :get "/posts/new" :new)
(route :post "/posts" :create)
(def body
(body :posts
(validates [:title :body] :required true)
(permit :title :body)))
(defn index [request]
(let [posts (db/from :posts)]
[:ul
(foreach [p posts]
[:li
[:h1 (p :title)]
[:p (p :body)]])]))
(defn new [request &opt errors]
(let [post (body request)]
[:form {:method :post :action "/posts"}
[:input {:type "text" :name "name" :value (post :name)}]
[:div
(errors :name)]
[:textarea {:name "body"}
(post :body)]
[:div
(errors :body)]
[:input {:type "submit" :value "Save"}]]))
(defn create [request]
(let [post (-> (body request)
(db/save))]
(if (saved? post)
(redirect-to :home)
(new request (errors post)))))
