Appearance
Object and Link API contract
This guide describes panel projections and Object and Link API integration.
Attribute projections
Read requests accept an attributeList containing only the attributes needed by the caller:
json
{
"attributeList": [
"name",
"state|name",
"state|create_user|name"
]
}Use | between levels of an aggregated attribute. Always send the property; the panel request adapter sends attributeList: [] when no projection is configured.
Read an entity by GUID
Use the projection-aware POST endpoints:
POST /Object/getObjectByGuidPOST /Link/getLinkByGuid
Both accept the same body:
json
{
"objGuid": "019f8a7a-90a0-7239-be99-957a138669f0",
"attributeList": [
"name",
"state|name"
]
}Do not use the obsolete GET /Object/{guid} or GET /Link/{guid} endpoints.
Find objects or links
POST /Object/find and POST /Link/find use the current filter and projection shape:
json
{
"typeName": "work_order",
"attributeList": [
"name",
"state|name"
],
"findAttributes": [
{
"field": "state|name",
"compareType": "EQUAL",
"value": "Active"
}
],
"sortParams": [
{
"attribute": "state|name",
"sortDirection": "Asc"
}
],
"pagination": {
"offset": 0,
"limit": 50
}
}Nested attribute paths also use | in filters and sort rules.
Find linked objects
POST /Object/getLinkedObjects accepts the selected object GUID, canonical link name, direction, projection, filters, sort rules, and optional pagination:
json
{
"objGuid": "019f8a7a-90a0-7239-be99-957a138669f0",
"linkName": "work_order_operation",
"reverse": false,
"attributeList": [
"name",
"link:position"
],
"findAttributes": [
{
"field": "obj:name",
"compareType": "EQUAL",
"value": "Cutting"
},
{
"field": "link:position",
"compareType": "EQUAL",
"value": 10
}
],
"sortParams": [
{
"attribute": "obj:name",
"sortDirection": "Asc"
}
],
"pagination": {
"offset": 0,
"limit": 50
}
}Prefix object filter and sort fields with obj: and link fields with link:. Nested paths remain valid after the prefix, for example obj:state|create_user|name. linkName is required; typeName is not a replacement for it.
Panel configuration keeps its existing filter and sort model. The request adapter converts it to the API fields shown above, including obj: and link: prefixes for linked-object requests.
Create and update responses
POST /Object and POST /Link return an array of created GUID strings:
json
[
"019f8a7a-90a0-7239-be99-957a138669f0"
]The response does not contain a full entity. Read or refresh the affected data after creation when the UI needs it.
PUT /Object and PUT /Link return only the attributes included in the update payload, together with response metadata such as objectGuid and attrCount. Treat this response as a partial update result, not as a replacement for the full cached entity. Each mutation owner decides how to refresh its data: the main editor invalidates or reloads its panel/tree data, file flows reload linked objects, and Tiptap/BPMN update their own state without a universal entity refetch.
If a required write fails, the editor remains open with its pending values. When object creation succeeds but dependent link creation fails, retrying reuses the created object GUID.
Editor detail loading
The object editor requests its configured fields by GUID instead of relying on the source table projection. Object fields and link.* fields are loaded separately through the corresponding Object and Link endpoints.
After a detail response is loaded, it is authoritative for field values and metadata. A failed or mismatched detail response keeps the editor unavailable; missing projected fields do not fall back to potentially stale list data.
Verification
Run the focused contract checks from the panel app:
bash
pnpm -C apps/panel test:object-api-contractThe local-object-api-contract-demo fixture provides an interactive surface for Object projection/create/update, editor detail loading, and linked-object reads. Direct Link create/update/by-GUID handlers are fixture support, not interactive demo coverage. The focused command covers request serialization, response parsing, projection behavior, mutation lifecycle policy, and fixture helpers; it is not a full route-level or store integration test.