Tutorial: 5-minute blog

Last edited: April 18, 2019
Time commitment: about an hour.
The simplest full app you can make in Hyperfiddle is a blog. Here is the final result, which has:
  • Three Datomic queries
  • One Reagent view
It takes me about 300 seconds to run through this demo. The equivalent as a proper Clojure project boilerplate involves the following:
  • git,
  • compilers,
  • build tools,
  • setup Datomic,
  • code http web service,
  • code browser entrypoint,
  • code routing,
  • code client/server data sync,
  • code asynchronous http requests,
  • code error handling
  • code node server rendering,
  • deal with deploys,
  • etc.

Go to http://tank.hyperfiddle.net, login, and make your first fiddle

Please namespace your fiddles with your username since the tank is a shared environment.
If it's read-only, you aren't logged in.
Read the tooltip on :fiddle/ident to see the docstring and that it is a keyword

Click stage to redirect to your newly created fiddle

  • All fiddles are URL addressable, the fiddle/ident is in the URL.
  • We provide a default query for you to modify.
  • Note your fiddle edits are in the IDE stage.
  • Stage state is backed by browser localstorage until you click transact.
  • Stage state syncs across tabs and sessions.

Change the :fiddle/query: add :dustingetz.post/title to the where clause.

  • Press alt-enter to refresh
  • By convention, all schema attributes should be namespaced to the responsible maintainer.
  • This tutorial is coded against :dustingetz.post schema because it has some existing sample data.

Forms and tables are automatically driven by your query and Datomic schema

The tooltip shows us that :published-date is an :instant, which is why the default cell renderer is a datepicker.
The schema editor is linked, follow the link.

Schema editor

  • The dustingetz.post schema is already installed into $.
  • You can make new attributes here (please namespace with username)
  • No need to make new attributes for this tutorial.
  • Press the browser back button to go back to the query.
  • Hyperfiddle doesn't break the web. Links work, back button works.

Specify the pull columns, these drive the table

  • The table has three columns because the pull specifies three columns.
  • Table cell widget types are reflected from Datomic schema (you can inspect schema in the label tooltip).

Staging area

  • Nobody else can see your changes until you transact them.
  • The stage is backed by browser localstorage.
  • You can edit the stage by hand, including clear it out or paste any valid Datomic transaction.

ClojureScript renderer

  • Copy/paste this for your renderer.
  • Auto-indent a codemirror with Cmd-A Shift-Tab
  • To restore the default renderer, you can delete your :fiddle/renderer and then blur the field.
  • ctx is in lexical scope. This managed value contains Datomic metadata (e.g. schema, query)
  • hypercrud.browser.context/data returns the result subtree value for "where I am focused".
  • In the happy path you only ever call context/data
  • No (ns (:require ...)) yet, so you must fully qualify all namespaces e.g. cljs.pprint/pprint.

Better renderer

  • Auto-indent a codemirror with Cmd-A Shift-Tab
  • Destructuring [e] on line 6 corresponds with the shape of the tupled Datomic resultset.
  • Don't forget to turn your date into a string, and handle nil dates!
Copy/paste this for your renderer

:fiddle/cljs-ns lets us defn

  • All fiddles have a ClojureScript namespace available inside your :fiddle/renderer as user.
  • This is available at the "cljs" tab
  • No :require or deps.edn yet.

EDN view

EDN view lets us see the Datomic resultset directly.

Data view

  • This disables any custom renderer to see what's really going on
  • Useful if the renderer breaks and for administration

Link editor

  • Links in Hyperfiddle are like links in HTML.
  • Hyperfiddle has three kinds of link:
    • anchors
    • forms (buttons)
    • iframes

We want to link to an individual post

  • The first thing we need is an anchor-attribute. This is the value which will appear in the URL.
  • You generally don't want :db/id in the URL and :db/id is a very bad attribute for links since it occurs everywhere!
  • Change the query to add :dustingetz.post/slug, which is :db.unique/identity
  • This stable identity is suitable for URLs

Make a link using ::slug as the anchor-attribute

  • Navigate to the link editor
  • Make a new link at path :dustingetz.post/slug
  • Press alt-enter to recompute

Two things happened

  1. It's invalid because we haven't set a link target-fiddle yet
  2. The link showed up in two places!
That will make sense in a minute, first lets make it valid.

In the link editor, create the target-fiddle

Don't forget to recompute with alt-enter

Now the links are working

Hover a link to see how it evaluated

:db/id has canonicalized to use the slug

  • Hyperfiddle understands your intent to link to an entity
  • Links appear anywhere they are valid

Links appear anywhere they are valid ("identity fallback")

  • If ::slug is not set or pulled, it will fallback to whatever other identity is available (:db/id in this case)
  • Manually stage the following transaction to see this in action
  • The link must always work if it is possible to satisfy the dependency!

A real life example of :db/id fallback is the Hyperfiddle docs app

Remove :db/id from your pulls if you don't want this behavior.

  • You only need one way to identify an entity
  • Hyperfiddle will figure it out and use the best one
  • We support :db.unique/identity, :db/ident, and :db/id
Whack the staging area to make :automatic-crud-links happy again.

Navigate your new ::view-post link

Set an explicit pull

  • Explicit pulls are used to render a blank form and you should set them.
  • Splat * is generally an anti-pattern in Hyperfiddle (it contains no information about data shape)
  • It's good for exploration though

Manually edit the URL to a tempid and see a blank form

  • Whack this stage, don't transact it unless you want to

Why does this example use :fiddle/markdown in userland?

  • :fiddle/markdown is from the hyperfiddle schema on the right hand side
  • We are setting ourselves up to do something clever in the future
  • If you are curious, see: http://www.dustingetz.com/:importance-of-namespaced-keywords/
  • For now just ignore it. Reuse existing schema if the semantics make sense for what you want to do.

Toggle back to :view and render the post markdown

Press back button to go back to the blog index and wire up the links in the :fiddle/renderer

  • The Context API is responsible for interpreting your resultset in terms of the Datomic :find spec
  • (E.g. FindRel / FindColl / FindTuple / FindScalar, :db.cardinality/many, :db.unique/identity)
  • It can individually identify each position in a table/form in an attribute/identity centric way

:fiddle/css

Tighten up the CSS if you want

New blog post button

  • Data mode
  • Make a new link at :dustingetz.post/slug, with :class [:hf/new] (:link/class is :db.cardinality/many which renders as vector here)
  • Make a new fiddle to model the "new post" form

Alt-click any pink-box to drill down (navigate deeper in a new tab)

Specify the pull

Close the tab to go back, and try it out

Transactions: Automatically add today's date to all new blog posts:

1. (defmethod hyperfiddle.api/tx)

2. Wire your txfn by name from the :link/tx-fn

  • Your txfn will be called whenever the popover "stage" button is clicked.
  • The result is concat'ed with the form

Try it, make sure it works!

You can always look at the stage to see what Datomic transactions were generated.

Transact both stages to save.

  • Until you transact, all of our work is still in localstorage, nobody else can see it
  • Make sure you transact both stages – your fiddle edits, and your data edits

Production – edit your URL "hyperfiddle.net" to "hyperfiddle.com"

  • Prod is server rendered progressive web app
  • SSR is happening in AWS Lambda
  • Hyperfiddle regularly withstands hackernews traffic, it's hosted all of our web properties for 18 months now
  • Prod has a 5min cache window, check the headers in the browser devtool
  • Immutable database gives lots of fun opportunities for caching. All XHR requests have a time-basis and are cache-control: immutable

Done!

That's almost everything. Topics not covered:
  • :hf/remove
  • iframes & picklists
  • dependent picklists