Skip to content

Recipes

Each recipe on this page reaches one goal that people often ask about. The recipes combine the commands described on the Command reference and buildzr.yaml pages, and the documentation tests run every command and every file on this page.

Words used on this page

Word Meaning
workspace A Workspace(...) that you write in Python, and what readers open at /<name>/.
workspaces folder The folder of Python files that create your workspaces, workspaces/ by default.
built workspace The folder that buildzr build writes for one workspace: the viewer, the model data and build.json.
data-only workspace A built workspace without the viewer, only the model data.

The model used by the recipes

The recipes use this small model. Save it as workspaces/shop.py:

from buildzr.dsl import Workspace, Person, SoftwareSystem

with Workspace("Shop") as w:
    customer = Person("Customer")
    shop = SoftwareSystem("Shop")
    customer >> "Buys from" >> shop

A workspace for programs only

Goal: serve the model to scripts, CI jobs, dashboards and AI assistants, without the viewer.

Build data-only workspaces with --no-viewer, into a build output of their own, and serve that folder:

$ buildzr build --no-viewer -o .buildzr/data
built .buildzr/data/shop (data only; 2 elements, 1 relationship, 0 views; modelHash sha256:d784397d7419…)

$ buildzr serve .buildzr/data
Serving .buildzr/data at http://127.0.0.1:8000/ (Ctrl+C to stop)
  http://127.0.0.1:8000/shop/api/v1/ (data only, no viewer)
Workspace list at http://127.0.0.1:8000/_buildzr/v1/workspaces

serve builds nothing here, because .buildzr/data already holds built workspaces. To make every build of the project data-only, set viewer: false in the build section of buildzr.yaml instead.

A data-only workspace has no index.html, so /shop/ answers 404, and the Model API at /shop/api/v1/ works as usual. serve prints that address, and its index page at / links to it. One field changes: viewerUrl, the link in every answer that opens an element in the viewer. There is no viewer to link to, so viewerUrl is null in every answer, with or without --public-url. The orientation document of the API says so in its notes field, and the list of workspaces shows "viewerUrl": null.

The request below shows such an answer. It was sent to a data-only build of the larger example model examples/buildzr_models_example.py from the buildzr repository, because the small shop model has no element that matches mongo:

GET /microservices-example/api/v1/elements?q=mongo
{
  "apiVersion": "1",
  "modelHash": "sha256:1e2b294431af70f6e5e43dbc369f543289ebdcc373d65f9b4fdeb4fcb3c53df6",
  "total": 3,
  "items": [
    {
      "id": "e-commerce-system/database",
      "name": "Database",
      "type": "Container",
      "parent": "e-commerce-system",
      "description": null,
      "technology": "MongoDB",
      "tags": [
        "Element",
        "Container"
      ],
      "childCount": 0,
      "viewerUrl": null,
      "matched": "technology"
    },
    {
      "id": "deploy/production/aws/documentdb",
      "name": "DocumentDB",
      "type": "DeploymentNode",
      "parent": "deploy/production/aws",
      "description": null,
      "technology": "MongoDB-compatible",
      "tags": [
        "Element",
        "Deployment Node"
      ],
      "childCount": 1,
      "viewerUrl": null,
      "matched": "technology"
    },
    {
      "id": "deploy/production/aws/documentdb/database",
      "name": "Database",
      "type": "ContainerInstance",
      "parent": "deploy/production/aws/documentdb",
      "description": null,
      "technology": "MongoDB",
      "tags": [
        "Container Instance"
      ],
      "childCount": 0,
      "viewerUrl": null,
      "matched": "technology"
    }
  ],
  "next": null,
  "truncated": false
}

Several workspaces in one folder

Goal: keep the models of several systems in one repository and serve them together.

Put one model file per system in the workspaces folder, in subfolders if you like. One file may also create more than one workspace. Save this as workspaces/support.py:

from buildzr.dsl import Workspace, Person, SoftwareSystem

with Workspace("CRM") as crm_ws:
    agent = Person("Support Agent")
    crm = SoftwareSystem("CRM")
    agent >> "Looks up customers in" >> crm

with Workspace("Help Desk") as desk_ws:
    customer = Person("Customer")
    desk = SoftwareSystem("Help Desk")
    customer >> "Opens tickets in" >> desk

Build all of them:

$ buildzr build
built .buildzr/build/shop (2 elements, 1 relationship, 0 views; modelHash sha256:d784397d7419…)
built .buildzr/build/crm (2 elements, 1 relationship, 0 views; modelHash sha256:a77bf728e3a0…)
built .buildzr/build/help-desk (2 elements, 1 relationship, 0 views; modelHash sha256:a6a0ab691312…)

Each workspace has its own folder and its own address: /shop/, /crm/ and /help-desk/. buildzr serve lists all three at /. If two workspaces end up with the same name, build stops before it writes anything and names both, so you can rename one.

Goal: send a colleague a link, or put one in a ticket, that opens the viewer at one element.

The viewer keeps the state of the screen in the part of the address after #, the hash. A link with a hash therefore opens the same element at the same level. You can write the hash by hand:

To open… Write
The landscape (every person and software system of the model) #/m
A box that contains other boxes, expanded #/m/billing?sel=billing
One element inside a box, selected #/m/billing?sel=billing/api
A view that the authors drew #/v/billing-containers
A box with a search and a tag filter on #/m/billing?q=pay&tags=PCI
#/m
#/m/billing?sel=billing
#/m/billing?sel=billing/api
#/v/billing-containers
#/m/billing?q=pay&tags=PCI

Put the hash after the address of the workspace: http://127.0.0.1:8000/shop/#/m/billing?sel=billing/api. Viewer links describes the full grammar.

You can also take the link from the Model API instead of writing it. Every element in an answer carries its link in the field viewerUrl. Ask for the element and use that field. This example asks the API of the workspace built from examples/buildzr_models_example.py, which buildzr serve serves at /microservices-example/:

GET /microservices-example/api/v1/elements?q=repository
{
  "apiVersion": "1",
  "modelHash": "sha256:1e2b294431af70f6e5e43dbc369f543289ebdcc373d65f9b4fdeb4fcb3c53df6",
  "total": 1,
  "items": [
    {
      "id": "e-commerce-system/order-service/order-repository",
      "name": "Order Repository",
      "type": "Component",
      "parent": "e-commerce-system/order-service",
      "description": null,
      "technology": null,
      "tags": [
        "Element",
        "Component"
      ],
      "childCount": 0,
      "viewerUrl": "/microservices-example/#/m/e-commerce-system/order-service?sel=e-commerce-system/order-service/order-repository",
      "matched": "name"
    }
  ],
  "next": null,
  "truncated": false
}

The link starts with / because buildzr serve ran without --public-url. When you start it with --public-url https://architecture.example.com, the links are complete: https://architecture.example.com/microservices-example/#/m/.... One option covers every workspace that serve serves. buildzr serve never guesses the address from the request.

Links follow names. The id of an element is made from the names of its parents and its own name. Renaming an element changes its id: an old link then opens the nearest box that still exists, and the viewer says so. Two siblings with the same name get -2, -3 in model order. Adding an earlier sibling with the same name can therefore make an old link open a different element. See Viewer links.