In this exercise, you will add Customers
to Incidents
to specify who created an incident.
Customer data is available in SAP S/4HANA Cloud as part of the Business Partners Service. You will connect to this service from the Incidents Management application.
To give you a consistent start for the upcoming tasks, there is a start version of the application available. It basically matches to what you did in the last exercise plus has some UI bits and pieces.
We recommend to start from this branch. You can save your previous work by pushing it to a Github repository, for example.
👉 Clone this repository and checkout the start
branch:
cd /home/user/projects
git clone -b start https://github.com/SAP-samples/teched2023-AD264
cd teched2023-AD264
npm ci # installs app's dependencies
👉 Then open the new folder teched2023-AD264
in a new window:
Alternatively, you may use the command SAP Business Application Studio: Git Clone
Luckily, you don't need to implement the integration to SAP S/4HANA from scratch, but you can use an integration package.
Such packages could come from any provider: SAP, partners, a team in your company etc. They can be a published to npmjs.com or provided as simple tar files from a remote file server, or a local folder.
For expediency, we use a git
dependency to a branch in this repo as source of the package.
👉 In the terminal, run this to download the package:
npm add git+https://github.com/SAP-samples/teched2023-AD264#bupa-integration-package
👉 Let's see what got installed. Expand the folder node_modules/s4-bupa-integration
(in the file explorer or in the terminal):
node_modules/s4-bupa-integration
├── bupa
│ ├── API_BUSINESS_PARTNER.cds
│ ├── API_BUSINESS_PARTNER.csn
│ ├── API_BUSINESS_PARTNER.edmx
│ ├── API_BUSINESS_PARTNER.js
│ ├── data
│ │ └── API_BUSINESS_PARTNER-A_BusinessPartner.csv
│ └── index.cds
└── package.json
👉 Open file API_BUSINESS_PARTNER.cds
(not the .csn
file)
-
Find the outline view in the lower left corner of the window. Alternatively press F1>, type outline and select Explorer: Focus on Outline View.
-
Use the view to make yourself familiar with which entities there are.
Quite an API, right? Don't worry, we will restrict it soon to what we need in the application.
👉 First, to make the application's CDS model use the package, add this line to db/data-model.cds
:
using { API_BUSINESS_PARTNER as S4 } from 's4-bupa-integration/bupa';
Note how the path in
from 's4-bupa-integration/bupa'
matches to the file path innode_modules
.
👉 Register the package in the application configuration. Add this top-level to package.json
(pay attention to JSON syntax errors):
"cds": {
"requires": {
"API_BUSINESS_PARTNER": {
"kind": "odata-v2",
"model": "s4-bupa-integration/bupa"
}
}
}
For the first version of the application, you only need two fields from the A_BusinessPartner
entity. To do this, you create a projection on the external service. Since in this example, you are interested in business partners in a role as customer, you use the name Customers
for your projection.
👉 Add Customers
:
- Create a
Customers
entity as a projection to theA_BusinessPartner
entity that you have just imported. It shall have two fieldsID
for the remoteBusinessPartner
name
for the remoteBusinessPartnerFullName
- Add an association from
Incidents
to (one)Customer
- Expose the
Customers
entity similar toIncidents
This is how it's done:
Add this to db/data-model.cds
:
entity Customers as projection on S4.A_BusinessPartner {
key BusinessPartner as ID,
BusinessPartnerFullName as name
}
Then add:
extend Incidents with {
customer : Association to Customers;
}
In srv/processor-service.cds
, add this line:
extend service ProcessorService with {
entity Customers as projection on mgt.Customers;
}
Again, you could have added these new fields and entities to the original definitions. This way though, it's easier for you to copy. Also, it shows you how to add things in a 'modification free' way.
👉 Run cds watch
again and check its ouput. You find the information about what's going on:
...
> init from node_modules/s4-bupa-integration/bupa/data/API_BUSINESS_PARTNER-A_BusinessPartner.csv
...
[cds] - mocking API_BUSINESS_PARTNER {
path: '/odata/v4/api-business-partner',
impl: 'node_modules/s4-bupa-integration/bupa/API_BUSINESS_PARTNER.js'
}
You see that
- The external
API_BUSINESS_PARTNER
is mocked, i.e. served in the application although in production it would come from remote. This is because we haven't specified yet how to connect it to a real remote data source. - A CSV file
.../data/API_BUSINESS_PARTNER-A_BusinessPartner.csv
with mock data got deployed.
Where does it come from? Yes, the integration package. See the file tree from the beginning where it's listed.
cds watch
runs in a 'mock mode' by default. In production, this won't happen, as the application is started withcds-serve
. See the documentation for howcds watch
binds to services.
👉 Go the home page of the application (the one listing all the service endpoints).
You can see the /odata/v4/api-business-partner
service with all its entities under Service Endpoints.
Data is available at /odata/v4/api-business-partner/A_BusinessPartner
.
To make requests for Customers
work for real, you need to redirect them to the remote system.
👉 In file srv/processor-service.js
, add this content to the init
function:
// connect to S4 backend
const S4bupa = await cds.connect.to('API_BUSINESS_PARTNER')
// delegate reads for Customers to remote service
this.on('READ', 'Customers', async (req) => {
console.log(`>> delegating '${req.target.name}' to S4 service...`, req.query)
const result = await S4bupa.run(req.query)
return result
})
Note how you don't need to code against any low-level layer here. It's just the service name
API_BUSINESS_PARTNER
that is relevant. The rest is wired up behind the scenes or outside of the application code. How? Keep on reading!
👉 Open /odata/v4/processor/Customers
to see the mock data from the BusinessPartner
service.
Let's change this and configured a remote system.
As a ready-to-use stand-in for an SAP S4/HANA system, we use the sandbox system of SAP Business Accelerator Hub.
To use your own SAP S/4HANA Cloud system, see this tutorial. You don't need it for this tutorial though.
👉 Create a new file .env
in the root folder and add environment variables that hold the URL of the sandbox as well as a personal API Key:
DEBUG=remote
cds.requires.API_BUSINESS_PARTNER.[sandbox].credentials.url=https://sandbox.api.sap.com/s4hanacloud/sap/opu/odata/sap/API_BUSINESS_PARTNER/
cds.requires.API_BUSINESS_PARTNER.[sandbox].credentials.headers.APIKey=<Copied API Key>
Note the [sandbox]
segment which denotes a configuration profile named sandbox
. The name has no special meaning. You will see below how to use it.
👉 Get an API key for your TechEd user: for the sake of this TechEd session, you can use this key from here (it will not be available after TechEd).
Alternatively, get an API key for your personal user:
To get an API key for you personal user for SAP Business Accelerator Hub :
-
Go to SAP Business Accelerator Hub.
-
On the top right corner, expand the Hi ... dropdown. Choose Settings.
-
Click on Show API Key. Choose Copy Key and Close.
👉 Add the key to the .env
file
By putting the key in a separate file, you can exclude it from the Git repository (see the .gitignore
file).
Note how the
cds.requires.API_BUSINESS_PARTNER
structure in the.env file
matches to thepackage.json
configuration.
To learn about more configuration options for CAP Node.js applications, see the documentation.
👉 Now kill the server with Ctrl+C and run again with the sandbox
profile activated:
cds watch --profile sandbox
In the server log, you can see that the configuration is effective:
...
[cds] - connect to API_BUSINESS_PARTNER > odata-v2 {
url: 'https://sandbox.api.sap.com/s4hanacloud/sap/opu/odata/sap/API_BUSINESS_PARTNER/',
headers: { APIKey: '...' }
}
...
On the application's index page, the mocked service is gone, because it is no longer served in the application. Instead, it is assumed to be running in a remote system. Through the configuration above, the system knows how to connect to it.
👉 Open /odata/v4/processor/Customers
to see the data coming from the remote system.
If you get a
401
error instead, check your API key in the.env
file. After a change in the configuration, kill the server with Ctrl+C and start it again.
You can also see something like this in the log (due to the DEBUG=remote
variable from the .env
file above):
[remote] - GET https://.../API_BUSINESS_PARTNER/A_BusinessPartner
?$select=BusinessPartner,BusinessPartnerFullName&$inlinecount=allpages&$top=74&$orderby=BusinessPartner%20asc
...
This is the remote request sent by the framework when S4bupa.run(req.query)
is executed. The req.query
object is transparently translated to an OData query $select=BusinessPartner,BusinessPartnerFullName&$top=...&$orderby=...
. The entire HTTP request (completed by the sandbox URL configuration) is then sent to the remote system with the help of SAP Cloud SDK.
Note how simple the execution of remote queries is. No manual OData query construction needed, no HTTP client configuration like authentication, no response parsing, error handling, nor issues with hard-wired host names etc.
See the documentation on CQN for more on such queries in general. The service consumption guide details out how they are translated to remote requests.
CAP applications use the SAP Cloud SDK for HTTP connectivity. SAP Cloud SDK abstracts authentication flows and communication with SAP BTPs connectivity, destination, and authentication. It doesn't matter whether you want to connect against cloud or on-premises systems.
The UI needs some more annotations to show the changed data.
👉 First, some basic annotations that refer to Customers
itself. Add it to app/incidents/annotations.cds
:
annotate service.Customers with @UI.Identification : [{ Value:name }];
annotate service.Customers with @cds.odata.valuelist;
annotate service.Customers with {
ID @title : 'Customer ID';
name @title : 'Customer Name';
};
👉 Also in app/incidents/annotations.cds
, add annotations that refer to Incidents
and its association to Customers
:
annotate service.Incidents with @(
UI: {
// insert table column
LineItem : [
...up to { Value: title },
{ Value: customer.name, Label: 'Customer' },
...
],
// insert customer to field group
FieldGroup #GeneralInformation : {
Data: [
...,
{ Value: customer_ID, Label: 'Customer'}
]
},
}
);
// for an incident's customer, show both name and ID
annotate service.Incidents:customer with @Common: {
Text: customer.name,
TextArrangement: #TextFirst
};
Don't change the ellipsis
...
in thecds
code above. It's a special syntax for refering to the 'remaining values' of array-valued annotations. The advantage of this syntax is that you do not have to repeat the other table columns. See the documentation for more.
👉 Now click on the /incidents/webapp/index.html
link on the index page.
This file is part of the SAP Fiori Elements app in folder app/incidents/webapp/
.
For more on SAP Fiori elements, see session AD161 - Build Full-Stack Applications with SAP Build Code Tools. There, you can also learn about the dedicated tools for the UI annotations. You don't need to type them manually.
👉 Create a new incident and select a customer using the value help. When pressing Save, watch the console output of the application and see the >> delegating to S4 service...
message.
You have added basic capabilities to call out to a remote service.
Continue to exercise 3 to see how this can be enhanced.