Questions to the audience: How many know React? GraphQL? Redux? Web dev? Heard of Clojure?
The purpose of this workshop is to bring the lessons from the Clojure web framework Fulcro to the general public. You are most likely never going to use Fulcro itself but you can still seek or apply its ideas elsewhere.
In one word: productivity
First a personal story. My love affair with Fulcro started with suffering. I worked with a React & Redux FE app and was horrified at the amount of work, boilerplate code, and number of changed files it took to get a piece of data from the BE onto the screen. Then I discovered Fulcro. There it takes 2-3 changes: write the new UI component, include it in a parent component, and possibly add a backend function to fetch the data.
How is this possible?
Thanks to:
- focus on sustainable webapp development (
explain!
), which leads to
- locality of code
- navigability of code
- being data-driven and REPL-able
- awesome dev tooling
- (and generally to eliminating accidental complexity and boilerplate)
- not shying away from the question how do I deal with data? (fetch, store, change) and providing a full-stack, *integrated answer* (many UI frameworks pretend it is not their problem)
- leveraging a Graph API instead of REST (since UI/props is a tree, using a Graph API makes perfect sense)
(Being conservative about features baked into the framework and providing numerous extension points to customize it - important but not discussed in this workshop)
You will be looking at some Clojure code and data so let's spend few minutes learning to understand the syntax. Fortunately it is very simple!
Fulcro is a full-stack web framework for a graph API. Let's unpack that:
- Full-stack = both frontend and backend
- On the frontend we have a UI tree composed of React components
- It talks to a graph API on the backend to query for data and to effect mutations (changes)
- A single endpoint (x REST)
- Frontend describes what data it wants using EDN Query Language (EQL) and backend fills them in, returning a data tree
- On the backend we have Pathom - Fulcro's twin library (cljc) that parses EQL and answers with data
- You code resolvers that provide parts of the answer
- Your Pathom resolvers typically talk to a DB such as Datomic and PostgreSQL or remote REST APIs
- Note: Pathom can also run in the browser and it can work as an adapter of a REST API, as demonstrated on the Twitter v1 API in Wilker Lucio's talk "Data Navigation with Pathom 3"
Let's zoom in on the Frontend. It has:
- the UI component tree
- a client-side state, called client DB, and storing data mostly in a normalized form
- an asynchronous transaction subsystem (Tx) for triggering local and remote mutations and data loads from the components
Let's zoom in even more, on the UI tree and its rendering:
- Fulcro asks the
Root
component for its query, which composes the queries of its children (and so forth) - Fulcro fulfills the query using the data in the client DB, producing a tree of data, also known as props (= properties)
- Fulcro invokes the Root's render function passing it the props tree; Root in turn renders its children, passing them the relevant sub-trees
Simplicity: UI = Root(data) - no side-channel data grabbing by components
What is a Fulcro component anyway?
(defsc <Name> [this props]
{<config options>} ; :query, :ident, ...
(dom/div
(dom/h1 "Hello" (:name props) "!")
(some-child-component (:some-child props))))
- Data Navigation with Pathom 3 by Wilker Lucio is a great explanation of the problem with REST and multiple clients (e.g. UI components) with varying data needs and why an attribute-centric approach - such as implemented by Pathom - is a better solution. You will see Pathom in action and learn about some of its super-powers. all of this in just 45 minutes.