External OData Service
cap2UI5 apps have full access to the CAP connection pool. You can consume any external OData service — the call goes inside your main() via the normal cds.connect.to(...) API.
Configuration
In package.json:
{
"cds": {
"requires": {
"northwind": {
"kind": "odata-v2",
"model": "srv/external/northwind",
"credentials": {
"url": "https://services.odata.org/V2/Northwind/Northwind.svc/"
}
}
}
}
}The CSN model is generated as usual with cds import https://services.odata.org/V2/Northwind/Northwind.svc/ and saved at srv/external/northwind.csn.
App code
// srv/app/read_odata.js
const cds = require("@sap/cds");
const z2ui5_if_app = require("abap2UI5/z2ui5_if_app");
const z2ui5_cl_ui5_view_builder = require("abap2UI5/z2ui5_cl_ui5_view_builder");
class read_odata extends z2ui5_if_app {
customers = [];
async main(client) {
if (client.check_on_init()) {
const northwind = await cds.connect.to("northwind");
this.customers = await northwind.run(SELECT.from("Customers").limit(50));
const view = z2ui5_cl_ui5_view_builder.factory()
.ele({ n: `View`, ns: `mvc` })
.a({ n: `xmlns`, v: `sap.m` })
.a({ n: `xmlns:mvc`, v: `sap.ui.core.mvc` });
const tab = view.ele(`Shell`).ele(`Page`)
.a({ n: `title`, v: `Northwind - Customers` })
.ele(`Table`)
.a({ n: `items`, v: client._bind_edit(this.customers) });
const cols = tab.ele(`columns`);
cols.ele(`Column`).tag(`Text`).a({ n: `text`, v: `CompanyName` });
cols.ele(`Column`).tag(`Text`).a({ n: `text`, v: `ContactName` });
cols.ele(`Column`).tag(`Text`).a({ n: `text`, v: `Country` });
tab.ele(`items`).ele(`ColumnListItem`).ele(`cells`)
.tag(`Input`).a({ n: `value`, v: `{COMPANYNAME}` }).a({ n: `enabled`, b: true })
.tag(`Input`).a({ n: `value`, v: `{CONTACTNAME}` }).a({ n: `enabled`, b: true })
.tag(`Text`).a({ n: `text`, v: `{COUNTRY}` });
client.view_display(view.stringify());
} else if (client.check_on_event("SAVE_BACK")) {
const northwind = await cds.connect.to("northwind");
// … this.customers contains the user edits thanks to two-way binding
// … run an UPDATE on the service for each row
}
}
}
module.exports = read_odata;What's new here
1. CDS connection inline
const northwind = await cds.connect.to("northwind");
this.customers = await northwind.run(SELECT.from("Customers").limit(50));The same code you would write in a srv/z2ui5-service.js handler. Anything Node.js allows is allowed inside main() — fetch, OData, file system, Redis, MQ.
2. Two-way on a list
const tab = page.ele(`Table`).a({ n: `items`, v: client._bind_edit(this.customers) });
tab.ele(`items`).ele(`ColumnListItem`).ele(`cells`)
.tag(`Input`).a({ n: `value`, v: `{COMPANYNAME}` }).a({ n: `enabled`, b: true });Because the array is two-way bound via _bind_edit, UI5 writes user edits on every item property back into the XX delta. On the next roundtrip this.customers holds the modified state. The item-relative paths are uppercase ({COMPANYNAME}, not {CompanyName}): the model is written with uppercase names and mapped back onto your properties case-insensitively.
3. Persistence caveat
The entire this.customers array is serialized and deserialized between roundtrips. With 50 rows: no problem. With 50,000 rows: noticeable. Rules of thumb:
- Reload fresh in
check_on_init()instead of holding the array as long-lived app state. - For read-heavy lists with sort/filter/paging: the
set_odata_modelpattern (see Events) — then the array lives in the frontend driver, not the app instance.
Example with an OData-backed table:
async main(client) {
if (client.check_on_init()) {
client.set_odata_model("/odata/v4/admin/NorthwindCustomers");
const view = z2ui5_cl_ui5_view_builder.factory()
.ele({ n: `View`, ns: `mvc` })
.a({ n: `xmlns`, v: `sap.m` })
.a({ n: `xmlns:mvc`, v: `sap.ui.core.mvc` });
view.ele(`Shell`).ele(`Page`).a({ n: `title`, v: `Customers (OData)` })
.ele(`Table`)
.a({ n: `items`, v: `{/NorthwindCustomers}` })
// ↑ no _bind_edit, but a static OData path binding
.ele(`columns`).ele(`Column`).tag(`Text`).a({ n: `text`, v: `Company` });
client.view_display(view.stringify());
}
}You then need your own CAP service action NorthwindCustomers in z2ui5-service.js:
srv.on("READ", "NorthwindCustomers", async (req) => {
const northwind = await cds.connect.to("northwind");
return northwind.run(req.query);
});→ Continue with Static XML View.