5-minute tutorial to understand Atlas basics.
A simple user management system with:
Add Atlas to your deps.edn:
{:deps {com.github.semantic-namespace/atlas {:mvn/version "0.0.1-SNAPSHOT"}}
Start a REPL:
clojure -M:repl
(require '[atlas.registry :as registry])
(require '[atlas.ontology :as ont])
;; Register built-in entity types
(ont/register-entity-types!)
The registry is a global atom that holds all your semantic entities.
Components are foundational building blocks (databases, caches, external services):
(registry/register!
:component/user-db ; dev-id: human-readable identifier
:atlas/structure-component ; type: what kind of entity
#{:tier/foundation ; aspects: semantic tags
:domain/users}
{:component/provides [:db/find-user ; what this component offers
:db/save-user]})
What happened?
#{:atlas/structure-component :tier/foundation :domain/users}:domain/users aspect links it semantically to user-related entitiesFunctions contain business logic and declare their data flow:
(registry/register!
:fn/get-user-by-id
:atlas/execution-function
#{:tier/service
:domain/users
:operation/read}
{:execution-function/context [:user/id] ; data this function needs
:execution-function/response [:user/data] ; data this function produces
:execution-function/deps #{:component/user-db}}) ; dependencies
Key insight: The function declares:
:user/id):user/data)Endpoints expose functions via HTTP:
(registry/register!
:endpoint/get-user
:atlas/interface-endpoint
#{:tier/api
:domain/users
:http/get}
{:endpoint/context [:http/path-params]
:endpoint/response [:http/json-response]
:endpoint/deps #{:fn/get-user-by-id}})
Now the powerful part - querying your architecture:
(require '[atlas.query :as query])
;; Find all entities in the users domain
(query/find-by-aspect @registry/registry :domain/users)
;; => Returns all three entities we registered
;; Find only service-tier entities
(query/find-by-aspect @registry/registry #{:tier/service :domain/users})
;; => Returns just :fn/get-user-by-id
;; Get an entity's full semantic identity
(registry/identity-for :fn/get-user-by-id)
;; => #{:atlas/execution-function :tier/service :domain/users :operation/read}
Atlas can validate your architecture:
(require '[atlas.invariant :as inv])
;; Check all invariants
(inv/check-all)
;; => {:valid? true, :violations []}
;; Get a readable report
(println (inv/report))
What gets checked:
For a visual view of your registry:
(require '[atlas.atlas-ui.server :as ui])
(ui/start!)
;; Opens browser at http://localhost:8082
Q: Why not just use namespaces?
Namespaces give you one dimension (where code lives). Compound identities give you N dimensions (what code means). You can query by domain, tier, operation type, etc. - all at once.
Q: Do I need to use the UI?
No. The core value is in the registry and query APIs. The UI is a bonus for exploration.
Q: Can I define custom entity types?
Yes! Register them with :atlas/type:
(registry/register!
:my-project/workflow
:atlas/type
#{}
{:registry-definition/keys [:workflow/steps :workflow/transitions]})
Q: What about actual function implementations?
Atlas describes architecture, not implementations. Your actual functions live in regular Clojure namespaces. Atlas tells you what they mean and how they relate.
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |