Views, zones, actions, and lookups
The endpoints of a resource, which read data, change data, and supply options.
Views, actions, and lookups are the endpoints of a resource. Each one has an address, runs your code on the server for each request, and returns a protocol response. A zone is a part of a view that the client can request separately. Together they replace the routes and the controllers of an admin API.
This introduction explains what each endpoint does and how they work together. The page for each endpoint has the full API.
| Endpoint | Purpose | Request |
|---|---|---|
| View | Reads data and returns the blocks of one screen | GET |
| Zone | Returns one part of a view again | GET, partial |
| Action | Validates a payload and changes data | POST |
| Lookup | Supplies records to a search or an options input | GET |
Addresses, params, and args
You register each endpoint on a resource with a name, so the resource name and the
endpoint name identify it. An endpoint can also declare params, which are ordered
names such as ['id']. The values that a request supplies for the params are the
args.
type ViewAddress = { resource: string; view: string; args: string[] }
An address is not a URL. The host converts an address to a URL, so your URL
structure stays under your control. In your code, you do not write addresses as
strings. You pass the definition that resource.view or resource.action returns,
and TypeScript checks the args.
Views
A view is one screen. Its callback reads the data and returns one block or an array of blocks. It can also return a redirect, or an error for a failure that you expect, such as a record that does not exist.
const orderDetail = orders.view('detail', ['id'], async (ctx, view) => {
const order = await db.orders.find(ctx.paramValues.id)
if (!order) {
return ctx.fail('This order does not exist.')
}
view.setTitle(`Order ${order.reference}`)
return datalist(order).setFields(orders.pick('reference', 'customer', 'total'))
})
A view can also register search state, which is the filters, the sorter, and the paginator of the screen. See Search state.
Actions
An action is one operation that changes data. It has a schema and a handler. The SDK
validates the payload against the schema before the handler runs, so the handler
reads typed data from ctx.data. The schema can be from any validator that
implements Standard Schema, such as Zod.
The handler returns the next state of the interface and not only a status. It can redirect to a view, refresh the current view or some of its zones, show a notification, or fail with a message.
const updateOrder = orders.action('update', ['id'], updateOrderSchema, async (ctx) => {
const saved = await db.orders.update(ctx.paramValues.id, ctx.data)
if (!saved) {
return ctx.fail('This order no longer exists.')
}
return ctx.redirectTo(orderList).notify({ text: 'Order saved.', tone: 'success' })
})
An action does not belong to one form. A form, a row action of a table, and an agent tool can all call the same action, and each call gets the same validation.
Zones
A view callback runs again for each request for the view. For most screens this is correct. A zone is for the part of a screen that must load again separately, such as a table that changes after a row action when the rest of the page stays the same.
A zone has a name and its own callback, and you put it in the content of a view like
a block. An action refreshes it by name with ctx.refreshZones(['items']). For a
zone request, the server runs the view callback to find the zone, then runs the
callback of that zone only, and skips the other zones. Thus put the expensive queries
inside the zone callbacks and not in the view callback.
Lookups
A lookup supplies records to an input that selects a related record, such as the customer of an order. The input sends the text that the user types, and the lookup callback runs your search and returns the fields and the rows. Backlit does not search your data. You connect an input to a lookup with a lookup target.
How the endpoints connect
Blocks reach endpoints through targets. A link on a table row opens a view, a form submits to an action, and a select input reads from a lookup. The response of an action then decides the next screen. This cycle is a complete create and edit flow:
- The
listview returns a table. Each row has a link target to theeditview. - The
editview returns a form that submits to theupdateaction. - The
updateaction saves the record and returns a redirect to thelistview with a notification.