Consume the External Service in the UI of Your Application
- How to add supplier to
Risks
entity - How to handle expands to remote entities
- How to add supplier information to the Risks UI
- How to add value help to select a supplier
- Step 1
-
Open
db/schema.cds
and add the supplier to theRisks
entity using an association to theSuppliers
entity:entity Risks : managed { key ID : UUID @(Core.Computed : true); title : String(100); prio : String(5); descr : String; miti : Association to Mitigations; impact : Integer; criticality : Integer; supplier : Association to Suppliers; }
This managed association adds a property
supplier_ID
to theRisks
entity under the hood, so that the key and the ID field of the supplier can be stored. -
Copy the file
tutorial/templates/ext-service-consume-ui/db/data/sap.ui.riskmanagement-Risks.csv
todb/data
folder of your app, overwriting the existing file. -
Run
cds watch
with the sandbox profile:Shell/BashCopycds watch --profile sandbox
-
Open the CAP application’s URL and access the
Risks
service: http://localhost:4004/service/risk/Risks?$top=11You can see the new field
supplier_ID
filled from the updated mock data file: -
Try to show additional supplier information as well by expanding the
supplier
association: http://localhost:4004/service/risk/Risks?$top=11&$expand=supplier.You can see that this is not possible, although the property
&$expand=supplier
is part of the URL above. The reason for this is you now have a mixture of local and remote entities. Such requests can be sent by a UI to access supplier data for a risk. The code introduced in the previous tutorial doesn’t help here. You need to implement additional code for it.
Which command runs "cds watch" with the sandbox profile?
-
- Step 2
Add the following code to your
srv/risk-service.js
file to handle the expands for supplier data ofRisks
:JavaScriptCopythis.after('READ', 'Risks', risksData => { const risks = Array.isArray(risksData) ? risksData : [risksData]; risks.forEach(risk => { if (risk.impact >= 100000) { risk.criticality = 1; } else { risk.criticality = 2; } }); }); // Risks?$expand=supplier this.on("READ", 'Risks', async (req, next) => { if (!req.query.SELECT.columns) return next(); const expandIndex = req.query.SELECT.columns.findIndex( ({ expand, ref }) => expand && ref[0] === "supplier" ); if (expandIndex < 0) return next(); // Remove expand from query req.query.SELECT.columns.splice(expandIndex, 1); // Make sure supplier_ID will be returned if (!req.query.SELECT.columns.indexOf('*') >= 0 && !req.query.SELECT.columns.find( column => column.ref && column.ref.find((ref) => ref == "supplier_ID")) ) { req.query.SELECT.columns.push({ ref: ["supplier_ID"] }); } const risks = await next(); const asArray = x => Array.isArray(x) ? x : [ x ]; // Request all associated suppliers const supplierIds = asArray(risks).map(risk => risk.supplier_ID); const suppliers = await bupa.run(SELECT.from('RiskService.Suppliers').where({ ID: supplierIds })); // Convert in a map for easier lookup const suppliersMap = {}; for (const supplier of suppliers) suppliersMap[supplier.ID] = supplier; // Add suppliers to result for (const note of asArray(risks)) { note.supplier = suppliersMap[note.supplier_ID]; } return risks; }); });
The code first makes sure an expand for a supplier is requested. Then, the expand is removed from the query because it can’t be handled by the CAP server generically.
To identify the suppliers that are needed, the risks are read by calling
next()
. This way, all following handlers are called, including the built-in CAP handler that reads the risks from the database and returns them. The code makes sure that the requiredsupplier_ID
field is returned.All the required suppliers are read with one request from
API_BUSINESS_PARTNER
service and added to the respective risks.The code would not work for a large number of risks at the same time, because the URL produced to read the suppliers might get too long.
- Step 3
Next, you add the name of the supplier and the blocked status to the
Risks
UI.-
Open the
srv/risks-service-ui.cds
file. -
Add the
supplier
annotations:SwiftCopyannotate RiskService.Risks with { title @title: 'Title'; prio @title: 'Priority'; descr @title: 'Description'; miti @title: 'Mitigation'; impact @title: 'Impact'; supplier @( title: 'Supplier', Common.Text: supplier.fullName, Common.TextArrangement: #TextOnly ) }
-
Add the
supplier
fields to theRisks
object page:SwiftCopyannotate RiskService.Risks with @( UI: { ... FieldGroup#Main: { Data: [ {Value: miti_ID}, { Value: prio, Criticality: criticality }, { Value: impact, Criticality: criticality }, {Value: supplier_ID}, {Value: supplier.isBlocked}, ] } }, ) { };
-
Add the annotation for the
Suppliers
entity:SwiftCopyannotate RiskService.Suppliers with { isBlocked @title: 'Supplier Blocked'; }
-
Run
cds watch
with the sandbox profile:Shell/BashCopycds watch --profile sandbox
-
Open the Risks application: http://localhost:4004/launchpage.html#risks-app
-
Choose Go.
-
Choose the first entry.
You see now the name of the supplier and its blocked status.
In business terms, suppliers can receive status Supplier Blocked in case of high risks associated with them. When a supplier is blocked, it cannot be used in any purchasing requests.
-
- Step 4
The last thing you add is the value help to select a supplier from the remote system.
-
Open the
srv/risks-service-ui.cds
file. -
Add the following annotations to the end of the file:
SwiftCopy// Annotations for value help annotate RiskService.Risks with { supplier @( Common.ValueList: { Label: 'Suppliers', CollectionPath: 'Suppliers', Parameters: [ { $Type: 'Common.ValueListParameterInOut', LocalDataProperty: supplier_ID, ValueListProperty: 'ID' }, { $Type: 'Common.ValueListParameterDisplayOnly', ValueListProperty: 'fullName' } ] } ); } annotate RiskService.Suppliers with { ID @( title: 'ID', Common.Text: fullName ); fullName @title: 'Name'; } annotate RiskService.Suppliers with @Capabilities.SearchRestrictions.Searchable : false;
-
Run
cds watch
with the sandbox profile:Shell/BashCopycds watch --profile sandbox
-
Open the Risks application: http://localhost:4004/launchpage.html#risks-app
-
Choose Go.
-
Choose the first entry.
-
Choose Edit.
-
Choose the value list icon for the Supplier field.
You can select another value for the Supplier from the value list.
The result of this tutorial can be found in the
ext-service-consume-ui
branch. -