HTTP Protocol
One endpoint, one POST per interaction, JSON both ways. The protocol is abap2UI5's own — cap2UI5 does not define it, translate it or version it independently, because the backend answering it is abap2UI5.
This page used to carry a warning. It no longer needs to.
It used to say that the page described what cap2UI5 emitted and not what abap2UI5 emitted — the two had drifted apart, and a hand-maintained port was still writing a superseded envelope. That cannot happen now: the backend and the frontend come from one upstream commit. The measurements below are from a running server rather than from a specification.
The endpoint
POST /rest/root/z2ui5 | a roundtrip |
POST /sap/bc/z2ui5 | the same door, under its ABAP-side name |
GET /rest/root/z2ui5?app_start=<APP> | the HTML page that embeds the whole UI5 component — every module, view and stylesheet — boots UI5 and starts an app |
There is no static frontend route: the browser needs no files from the server other than that page (UI5 itself comes from the CDN). Both paths are configurable — see Configuration.
Request
{
"value": {
"S_FRONT": {
"ID": "<the draft id of the previous roundtrip, empty on a start>",
"APP": "ZCL_JS_HELLO",
"EVENT": "GO",
"T_EVENT_ARG": ["red"],
"SEARCH": "?app_start=ZCL_JS_HELLO",
"PATHNAME": "/rest/root/z2ui5",
"ORIGIN": "http://localhost:4004",
"HASH": "",
"CONFIG": {}
},
"XX": {},
"MODEL": { "NAME": "Ada" }
}
}ID | which draft to continue. Empty starts a new app |
EVENT, T_EVENT_ARG | what the user did, and the arguments the control carried — client.get_event() and client.get_event_arg(i) |
MODEL | the bound data as the browser has it; applied to the app instance before main runs |
Response
Measured against the example, a start of ZCL_JS_HELLO:
{
"S_FRONT": {
"APP": "ZCL_JS_HELLO",
"ID": "D46139087B1241DBBD701D4DC02F13AA",
"PROTOCOL": 2,
"S_ACTION": { "T_SYSTEM": [["VIEW_SLOTS", "display", "<mvc:View …>"]] }
},
"MODEL": { "NAME": "" }
}ID | the new draft id — every roundtrip writes a new one and the browser carries it forward |
PROTOCOL | the wire version, see below |
S_ACTION.T_SYSTEM | ordered framework actions: render a view, open a popup, show a message box, navigate |
S_ACTION.T_CUSTOM | app-issued frontend actions |
MODEL | the bound data as the server has it after main |
S_ACTION is an ordered list, which is why two client.message_toast_display() calls arrive in the order you wrote them.
PROTOCOL — the wire carries its own version
S_FRONT.PROTOCOL is stamped from z2ui5_if_ui5_types=>c_protocol and the shell compares it against its own before reading anything else. It is not the product version and does not move with a release; it moves when a response can no longer be read by a frontend written for the previous number.
It exists because of exactly the failure this project hit: the S_ACTION envelope replaced an older S_FRONT.PARAMS shape, and a frontend written for the old one looked for a key the backend no longer wrote — then rendered its empty result, silently. A mismatch is now reported to the user.
A response without the field is let through: a backend older than the field cannot be told apart from one that is merely older.
For a cap2UI5 project the check is belt and braces — both halves come from one @abap2ui5/node-runtime — but it protects anyone pairing them by hand.
Errors
An unhandled error answers 500 with roundtrip failed (<cds.context.id>). The detail goes to the server log under the same id; see Configuration. An app module that fails to load does not get that far: it fails the server's start.
Authentication is decided before the body is read: an unauthenticated caller gets 401 with the auth strategy's login challenge, an authenticated user who lacks the configured role 403, both without the server buffering the payload. A body over the limit gets 413. These three are answered by CAP's error middleware, in CAP's error format.
Next
- Architecture — what sits behind the endpoint
- Configuration — routes and authentication