{"id":31546400,"url":"https://github.com/brettatoms/zodiac","last_synced_at":"2025-10-04T15:11:08.435Z","repository":{"id":257811751,"uuid":"867361625","full_name":"brettatoms/zodiac","owner":"brettatoms","description":"A simple web framework for Clojure","archived":false,"fork":false,"pushed_at":"2025-08-18T12:49:49.000Z","size":85,"stargazers_count":101,"open_issues_count":1,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-09-21T06:11:31.959Z","etag":null,"topics":["clojure","web"],"latest_commit_sha":null,"homepage":"https://cljdoc.org/d/com.github.brettatoms/zodiac","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/brettatoms.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-10-03T23:19:30.000Z","updated_at":"2025-09-06T20:24:06.000Z","dependencies_parsed_at":null,"dependency_job_id":"b2894412-a6d4-49f3-baea-f09f9bf61d64","html_url":"https://github.com/brettatoms/zodiac","commit_stats":null,"previous_names":["brettatoms/zodiac"],"tags_count":23,"template":false,"template_full_name":null,"purl":"pkg:github/brettatoms/zodiac","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brettatoms%2Fzodiac","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brettatoms%2Fzodiac/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brettatoms%2Fzodiac/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brettatoms%2Fzodiac/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/brettatoms","download_url":"https://codeload.github.com/brettatoms/zodiac/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brettatoms%2Fzodiac/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278329221,"owners_count":25969104,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-04T02:00:05.491Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clojure","web"],"created_at":"2025-10-04T15:11:04.220Z","updated_at":"2025-10-04T15:11:08.422Z","avatar_url":"https://github.com/brettatoms.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Zodiac\n\n[![Clojars Project](https://img.shields.io/clojars/v/com.github.brettatoms/zodiac.svg)](https://clojars.org/com.github.brettatoms/zodiac)\n\nCome chat in [#zodiac](https://clojurians.slack.com/archives/C07V6RVUN7J)\n\nZodiac is a small web framework for Clojure that provides a reasonable set of defaults while also being easily extensible.  Zodiac stands on the shoulders of giants rather than being innovative.  At its core Zodiac is mostly just a preconfigured Ring app and not more that a few hundred lines of code.\n\nZodiac tries to fill a similar niche as the [Flask](https://flask.palletsprojects.com) framework with defaults that make it quick to start a new Clojure based web app without being heavy-handed.\n\nWhat Zodiac includes by default:\n\n - Routing and middleware.  We use [Reitit](https://github.com/metosin/reitit)\n - Request and response handing with [Ring](https://github.com/ring-clojure/ring).\n - A Jetty server (though Jetty can be turned off)\n - Automatic Hiccup-based HTML rendering using [Chassis](https://github.com/onionpancakes/chassis).\n - Websocket support\n - File streaming\n - Flash messages\n - Cookies and secure session handler\n - Form and JSON request parsing\n - Extensible, see [Zodiac Assets](https://github.com/brettatoms/zodiac-assets) and  [Zodiac SQL](https://github.com/brettatoms/zodiac-sql)\n - Convenience\n   - Helpers to lookup routes\n   - Helpers to return hiccup and JSON responses\n   - A request context\n   - Variables dynamically bound to the current request, router and session\n\n What Zodiac doesn't do:\n - Dictate a file structure with generators or scaffolding.\n - No configuration over code\n - No path based routing, etc.\n - Expect a certain database - (see [Zodiac SQL](https://github.com/brettatoms/zodiac-sql))\n - Asset bundling (see [Zodiac Assets](https://github.com/brettatoms/zodiac-assets))\n\nAnd that's about it.  Zodiac is mostly feature complete although you can expect plenty of bug fixes and polish before a 1.0.x release.\n\nRead the [docs](https://cljdoc.org/d/com.github.brettatoms/zodiac).\n\n### Getting started\n\n``` clojure\n(ns myapp\n  (:require [zodiac.core :as z]))\n\n(defn routes []\n  ;; routes use the reitit route syntax\n  [\"/\" {:handler (constantly {:status 200\n                              :body \"ok\"})}])\n\n(z/start {:routes #'routes})\n```\n\n### Options\n\nThe `zodiac.core/start` function takes a single options map with the following keys:\n\n- `:routes`: The route definition using the reitit route syntax\n- `:extensions`: A sequence of functions that accept an integrant system configuration map and return a modified integrant system configuration app.\n- `:request-context`: A map of values values to add to the `::z/context` map in the request map.\n- `:cookie-secret`: The secret used to encrypt the cookie\n- `:cookie-attrs`: Override the code settings.  Defaults to `{:http-only true :same-site :lax}`.\n- `:jetty`: A map of options to pass to `run-jetty` function of the embedded [ring-jetty-adapter](https://ring-clojure.github.io/ring/ring.adapter.jetty.html)\n- `:port`: The port to listen for connections.  If the port is also specified in the `:jetty` map then this value will be ignored.  The default is `3000`.\n- `:error-handlers`: A map of types to error handler functions\n- `:anti-forgery-whitelist`: A sequence or strings or regular expressions to bypass anti-forgery/csrf checking for matching routes.\n- `:reload-per-request?`: Reload the routes on every request. For this to work you will need to pass the var of the routes function, e.g. `#'routes`.\n- `:print-request-diffs?`: Print a diff of each request between each middleware.\n- `:start-server?`: Set to `false` to disable the embedded jetty server.\n- `:middleware`: A list of ring middleware. Wraps, not replaces, the default middleware.\n- `:default-handler`: Add a handler that gets called if a requested route doesn't match. Zodiac already includes a default handler created with [create-default-handler](https://cljdoc.org/d/metosin/reitit/0.9.1/api/reitit.ring?q=create-default-#create-default-handler).  This option allows a handler to be called before the regular default handler gets called. For more information see the [Default handler](https://cljdoc.org/d/metosin/reitit/0.9.1/doc/ring/default-handler?q=create-default-#default-handler) section in the Reitit docs.\n\n\n### Render HTML\n\nReturn a vector from the response handler to  automatically convert the vector to an html response.\n\n``` clojure\n(ns myapp\n  (:require [zodiac.core :as z]))\n\n(defn routes []\n  ;; Returns a text/html response with \u003cdiv\u003ehi\u003c/div\u003e for the body.\n  [\"/\" {:handler (fn [_] [:div \"hi\"])}])\n\n(z/start {:routes #'routes})\n```\n\n### Render JSON\n\nUse the `zodiac.core/json-response` function to encode Clojure maps to JSON and return `application/json` HTTP responses.\n\n``` clojure\n(ns myapp\n  (:require [zodiac.core :as z]))\n\n(defn routes []\n  ;; Returns an application/json response with {\"hello\": \"world\"} for the body.\n  [\"/\" {:handler (fn [_] (z/json-response {:hello \"world\"}))}])\n\n(z/start {:routes #'routes})\n```\n\n### Extending\n\nZodiac can be extended using a sequence of functions that take an integrant system map and return a modified integrant system map.\n\n``` clojure\n(defn service-ext [cfg]\n  (-\u003e cfg\n      ;; Add a ::service component to the config map\n      (assoc ::service {:value \"hi\"})\n      ;; Put an instance of the service in the request context\n      (assoc-in [::z/middleware :context :service] (ig/ref ::service))))\n\n(defn routes []\n  ;; routes use the reitit route syntax\n  [\"/\" {:handler (fn [{:keys [::z/context]}]\n                   {:status 200\n                    :body (-\u003e context :service :value)})}])\n\n(z/start {:routes #'routes\n          :extensions [service-ext]})\n```\n\n### Examples\n - [Clojure Land](https://clojure.land): Discover open-source Clojure libraries and frameworks.\n - [Zodiac Todo App](https://github.com/brettatoms/zodiac-todo-example): A very basic todo app build with Zodiac, Zodiac Assets, Zodiac SQL, Sqlite, AlpineJS, Htmx, Tailwind and Vite.\n - [Websocket example](/examples/websocket):  An example of how to uses websockets with Zodiac\n\n### Extensions\n\n- [Zodiac Assets](https://github.com/brettatoms/zodiac-assets): Static asset\n  building and url lookup with [Vite](https://vite.dev/).\n\n- [Zodiac SQL](https://github.com/brettatoms/zodiac-sql): Helper for connecting\n  to SQL database and running\n  [HoneySQL](https://github.com/seancorfield/honeysql) queries.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrettatoms%2Fzodiac","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbrettatoms%2Fzodiac","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrettatoms%2Fzodiac/lists"}