Schema

XTDB (the database Biff uses) does not enforce schema on its own. Biff provides schema enforcement with Malli. Here's a Malli crash course.

Say we want to save a user document like this:

{:xt/id #uuid "..."
 :user/email "bob@example.com"
 :user/favorite-color :blue
 :user/age 132}

We could model it in our Malli schema like so:

(def schema
  {:user/id :uuid
   :user [:map {:closed true}
          [:xt/id                     :user/id]
          [:user/email                :string]
          [:user/joined-at            inst?]
          [:user/foo {:optional true} :string]
          [:user/bar {:optional true} :string]]
   ...})

For the attribute types, Malli has a handful of type schemas like :uuid and :string above, and it also supports predicate schemas like inst? above.

For compactness, most of the attributes (like :user/email and :user/joined-at) are defined inside the document schema. But for the :xt/id key, it often makes sense to create an alias (:user/id in this example) so that it can be used in other documents. For example, the :msg document below includes a :msg/user key which has a value of type :uuid, and the :user/id key makes it clear that this key is meant to refer to a :user document:

(def schema
  {:user/id :uuid
   ...

   :msg/id :uuid
   :msg [:map {:closed true}
         [:xt/id       :msg/id]
         [:msg/user    :user/id]
         ...]})

Note however that Biff doesn't enforce that the :msg/user key actually points to a user document. As long as the key is a UUID, it will pass the schema check.

For mild convenience, your schema can be defined with the biff/doc-schema helper function:

(ns com.example.schema
  (:require [com.biffweb :refer [doc-schema] :rename {doc-schema doc}]))

(def schema
  {:user/id :uuid
   :user (doc {:required [[:xt/id          :user/id]
                          [:user/email     :string]
                          [:user/joined-at inst?]]
               :optional [[:user/foo       :string]
                          [:user/bar       :string]]})
   ...})

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.