Context API
The shell context endpoint returns everything an app needs to bootstrap inside LeanShell: who the actor is, their ability snapshot, the navigation tree, the app's Weave links, and more. It is one half of the shell wire contract — the PHP backend assembles context.json, and the ui5-core-lib LaravelUi5 facade consumes it.
The endpoint
GET /ui5/shell/{slug}/context.json{slug} is the artifact slug of the app being loaded. Authentication and the SdkContext binding come from the host-composed middleware.
The fixed schema
context.json carries a fixed set of keys — ContextServiceInterface::KEYS:
| Key | Holds |
|---|---|
actor | the acting partner |
principal | the authenticated partner (≠ actor under impersonation) |
client | client / installation info — no default contributor |
abilities | the actor's act ability snapshot |
settings | every setting of the app, personalized for the actor — {setting, value, value_type} per key |
actions | available actions |
navigation | the visibility-projected navigation tree |
weave | the outbound Weave links of the current app's Concept |
The schema is fixed and validated: contributors fill keys, they never change the schema, and an unknown configured key throws. A key without a configured contributor is simply absent from the response. Out of the box that applies to client. This is what lets the frontend program against a stable shape.
How the context is assembled
ContextService runs a chain of context contributors, each filling one key. Contributors are declared in config('ui5.context') and resolved generically — a new one is config plus a class, no pipeline rewrite. The defaults:
| Contributor | Fills | Purpose |
|---|---|---|
IdentityContextContributor (which: actor) | actor | the acting partner's identity |
IdentityContextContributor (which: principal) | principal | the authenticated partner's identity |
SnapshotAbilitiesContributor | abilities | the actor's act grants |
discovery.context (a container binding) | actions | the available actions |
NavigationContextContributor | navigation | the navigation tree, projected by the actor's abilities |
SettingsContextContributor | settings | every setting of the app, scope-resolved for the actor (Reading & Writing); the SDK registers it itself |
WeaveContextContributor | weave | the Concept's outbound links the actor may open; the SDK registers it itself, so it need not be listed in config |
Response shape (sketch)
{
"actor": { "id": 42, "name": "Alice Brand", "first_name": "Alice", "avatar_path": null, "gender": null },
"principal": { "id": 42, "name": "Alice Brand", "first_name": "Alice", "avatar_path": null, "gender": null },
"abilities": {
"act": { "closePeriod": true, "deleteCompany": false }
},
"settings": {
"pageSize": { "setting": "pageSize", "value": 50, "value_type": "Integer" }
},
"actions": { },
"navigation": { "branding": { }, "body": [ ], "identity": { }, "footer": { } },
"weave": [
{ "concept": "acme.customer", "target": "com.acme.orders", "key": "id", "label": "Orders", "icon": "sap-icon://sales-order" }
]
}The abilities snapshot carries a single bucket, act: operation guards the client uses as UX hints, backed by server-side enforcement. See visibility is not sent here. It is applied server-side, by rewriting the app manifest's sap.ui.viewModifications for the acting partner (see Per-actor manifest extensions). The snapshot is not an enforcement boundary; see Resolution Engine.
Public vs internal
ContextContributorInterface (the contributor seam) and the fixed-key schema are public. The concrete ContextService and the built-in contributors are internal — a consumer that needs a new key declares a contributor in config, it does not re-wire the service.
See also
- Navigation — the
navigationkey's{branding, body, identity, footer}shape - Resolution Engine — what fills
abilities - Settings Scope Precedence — how a setting's value resolves