Biff uses Ring and Reitit for handling HTTP requests. Reitit has a lot of features, but you can go far with just a few basics.

Multiple routes:

(defn foo [request]
  {:status 200
   :headers {"content-type" "text/plain"}
   :body "foo response"})

(defn bar ...)

(def module
  {:routes [["/foo" {:get foo}]
            ["/bar" {:post bar}]]})

Path parameters:

(defn click [{:keys [path-params] :as request}]
  (println (:token path-params))

(def module
  {:routes [["/click/:token" {:get click}]]})

Nested routes:

(def module
  {:routes [["/auth/"
             ["send" {:post send-token}]
             ["verify/:token" {:get verify-token}]]]})

With middleware:

(defn wrap-signed-in [handler]
  (fn [{:keys [session] :as req}]
    (if (some? (:uid session))
      (handler req)
      {:status 303
       :headers {"location" "/"}})))

(def module
  {:routes [["/app" {:middleware [wrap-signed-in]}
             ["" {:get app}]
             ["/set-foo" {:post set-foo}]]]})

If you need to provide a public API, you can use :api-routes to disable CSRF protection (this is a feature of Biff, not Reitit):

(defn echo [{:keys [params]}]
  {:status 200
   :headers {"content-type" "application/json"}
   :body params})

(def module
  {:api-routes [["/echo" {:post echo}]]})

Biff includes some middleware (biff/wrap-render-rum) which will treat vector responses as Rum. The following handlers are equivalent:

(require '[rum.core :as rum])

(defn my-handler [request]
  {:status 200
   :headers {"content-type" "text/html"}
   :body (rum/render-static-markup
             [:p "I'll gladly pay you Tuesday for a hamburger on Tuesday"]]])})

(defn my-handler [request]
    [:p "I'll gladly pay you Tuesday for a hamburger on Tuesday"]]])

See also:

Have a question? Join the #biff channel on Clojurians Slack, or ask on GitHub.

Sign up for Biff: The Newsletter
Announcements, blog posts, et cetera et cetera.
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.