C.W.K.
Stream
Lesson 01 of 04 · published

API-First: the UI Is a Client

~12 min · api-first, headless, boundary, bonfire-pattern

Level 0Blank Page
0 XP0/35 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"The web page you use isn't the product. It's the first customer of the product, standing in the same line as everyone else."

The Engine Is the Product

Loomis's product is the analysis engine and the HTTP API that fronts it. The web UI you click around in is not the thing itself — it's the first client of that API, and it holds no special privileges. When you analyze a portrait in the browser, the UI is making the same HTTP call any other client would make. This ordering — engine and API first, UI as a consumer — is the single most important structural decision in how the whole thing is built.

No Client Imports Internals

One rule enforces API-first and keeps it honest: no client reaches into the engine's internals. The UI cannot shortcut past the API to poke at engine state directly; it goes through the same public surface as everyone else. This matters because the moment one client gets privileged backdoor access, the API quietly becomes a second-class citizen — under-tested, under-designed, and eventually wrong. Forbidding the shortcut is what keeps the API the real, load-bearing interface rather than a decorative one.

The Test of API-First

Here's the clean test you can apply to any tool: could it lose its entire UI and still be fully usable through its API? If yes, it's genuinely API-first; if no, the UI is secretly holding logic hostage. Loomis passes cleanly. Its command-line tools analyze a portrait, a pose, a hand, or an object with no UI in the loop at all, and the future Cinder panel will consume the very same engine. The web interface is a convenience on top, never a dependency underneath.

Why This Beats UI-First

A UI-first tool hides its logic inside the interface, which feels faster to build and then charges interest forever. The instant you want a second client — a script, a CLI, another app — you have to perform extraction surgery to pry the logic out of the UI it was tangled into. API-first pays a small upfront cost (design the boundary deliberately) and buys multi-client support, testability, and scriptability from day one, at no later cost. It's the Bonfire pattern — engine owns the model, UI is the first client — and it's the family's default precisely because the cheap-feeling alternative is the expensive one.

Code

One API, many clients, no privileged shortcut·python
# The engine owns the model and exposes an HTTP API. THAT API is the product.
# Every client calls it the SAME way -- none reaches past it into internals:
#
#   POST /api/v1/portrait/analyze   <- the web UI calls this
#   POST /api/v1/portrait/analyze   <- the `loomis overlay` CLI calls this
#   POST /api/v1/portrait/analyze   <- the future Cinder panel will call this

# The test of API-first: delete the UI and the engine is STILL fully usable.
#   $ loomis overlay reference.jpg --json     # no UI involved at all

# UI-first would hide the logic INSIDE the interface -- and then a second client
# costs you extraction surgery. API-first pays the boundary cost once, up front.

External links

Exercise

Pick a tool or feature you've built (or use) where the logic lives inside the UI. Imagine you now need a second client for it — a CLI, a cron script, another app. Estimate the extraction surgery required to pull the logic out of the interface. Then describe what designing it API-first from the start would have cost up front, and everything it would have saved.
Hint
The surgery is usually large and risky: logic entangled with UI event handlers, state, and rendering has to be carefully separated without breaking behavior, often long after anyone remembers how it works. API-first front-loads a small, cheap decision — put the logic behind a boundary — and in exchange makes every future client a phone call instead of an operation. The 'slower' path was the fast one all along.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.