Data shaping (SDA)
A focused view-shaping tool, so pages don't fill up with nested transform logic.
The problem
API responses almost never arrive in the shape a page wants. The list is nested two levels down, the field names are wrong, you need the newest five sorted by a timestamp, and half the keys should be dropped before the data reaches the template.
Two bad answers: push every adaptation into a backend endpoint (and grow a page-specific adapter for every view), or push it into the template (and grow unreadable nested loops and conditionals).
SDA is the third answer: a small declarative expression that turns one input value into exactly the shape you need.
The @shape directive
@call orders = data.orders_list({ customer: user.id })
@shape recent = orders.value with "
[ .items
| sort_by(-created)
| take(5)
| { id, total, placed: created } ]
"
@for (o of recent) {
<li>{{= o.placed }} — {{= o.total }}</li>
}
The binding on the left is an ordinary value afterwards. The string on the right is the SDA query. It runs deterministically over the input and produces either a shaped value or one stable failure — it never partially mutates state and never reaches outside the value you gave it.
What the language does
- Selectors instead of implicit dot traversal —
.items,.user.name,.[0]. - Optional and required extraction — distinguish "missing is fine" from "missing is an error".
- Carrier-preserving comprehensions — map and filter over arrays and objects without losing the container type.
- A modest predicate language for the filter step.
- Pipe composition —
select | filter | project. - A small helper surface for normalisation and cleaning up keyed bags.
What it deliberately is not
SDA is a view-shaping tool, not a general query or programming language. It has no mutation, no ambient I/O, no way to call back into a page or a capability. When a transformation is genuinely business logic, it belongs in your data service, not in a shaping expression.
Server-to-client handoff
The most common use is handing a browser exactly the data it needs and nothing more:
<script id="bootstrap" type="application/json">
{{~ sda(page.data, "{ user: .me | {name, avatar}, flags }") | json }}
</script>
Full contract: the SDA reference.