Hello!
in this part of the tutorial series we will have a look at how to use Graph for composing APIs and customizing business data graphs with model extensions. We will walk through an example of how to create a custom entity with a custom association.
For an overview of other parts of this series, check out the Information Map.
---
API Composition helps organizations to customize their API surface and combine multiple data sources into a single unified API. With Graph, as part of SAP Integration Suite, API administrators can create a single API using a customized connected graph data model either for their whole landscape or for specialized use cases.
API administrators can customize Business Data Graphs with the help of Model Extensions. These are packages that define several Custom Entities. All customizations in Graph are virtual: custom entity definitions are projections using mirrored entities as sources. Custom entities can have one or multiple source entities from possibly different data sources.
In this blog we will walk through an example of composing and customizing an API from two separate services. An SAP S/4HANA Service and a service based on a custom CAP extension. Here is an overview of the example scenario:
Example scenario diagram
We will compose a demo.FrequentFlyer Custom Entity out of two sources: the sap.s4.A_BusinessPartner from an SAP S/4HANA data source and a my.custom.LoyaltyAccount entity from a custom CAP Extension on BTP. In addition, we will model an association from the custom entity demo.FrequentFlyer to the my.custom.LoyaltyStatus mirrored entity from the custom CAP Extension.
In this example we will be using the SAP S/4HANA sandbox provided on SAP Business Accelerator Hub and a simple CAP Extension service which we will be deploying in Cloud Foundry. The following steps will guide you through the required setup.
First we need a BTP subaccount with an SAP Integration Suite instance with Graph activated. Follow the steps outlined in this previous blog post if you have not done so already. As a result you have a running SAP Integration Suite instance with Graph.
For demo data we will be using the SAP S/4HANA BusinessPartner sandbox service available on SAP Business Accelerator Hub. Create a destination named demo-s4-bupa in your BTP subaccount for this service with the following URL:
https://sandbox.api.sap.com/s4hanacloud/sap/opu/odata/sap/API_BUSINESS_PARTNER
You will also have to configure an API key for sandbox access as described in this previous blog post.
For the custom extension service, we will be deploying a small CAP-service in Cloud Foundry for demo purposes. We prepared this service here. Note that this example is only for demo puposes and would not fulfill requirements for any productive use cases.
To deploy the example CAP-service, make sure your BTP subaccount has the Cloud Foundry runtime enabled and a Cloud Foundry space exists (see also this tutorial). Note that this minimal demo service only serves a few example records and does not require a database.
Clone the example service repository and copy the contents of .cdsrc.json.template to a new file .cdsrc.json and add a password for the configured Basic Authentication. In this demo we use Basic Authentication, to learn more about authenticating against Graph see here.
git clone https://github.com/SAP-samples/graph-example-apps.git
cd graph-example-apps/blog-series/API-composition/graph-demo-service
cp .cdsrc.json.template .cdsrc.json
Make sure you have installed the prerequisites (Node.js, CAP, MBT) listed here. Then install and build the project:
npm ci
npm run build
Next, deploy the service, for example using the Cloud Foundry CLI (see also here)
cf login --sso
cf deploy gen/mta.tar
After the deployment is finished you can access the example Loyalty service under <CF-application-route-URL>/graph-demo/.
Finally, we need to create a BTP destination for this service. In the BTP Cockpit under Connectivity > Destinations create a new Destination demo-loyalty with the following URL: <CF-application-route-URL>/graph-demo/ (<CF-application-route-URL> depends on your Cloud Foundry deployment). Select "BasicAuthentication" for Authentication and add the user name and password you previously configured.
Now that we have created two destinations with our demo services, we can create a business data graph which we will extend with a model extension in the next section. In SAP Integration Suite open Design > Graph and create a new business data graph demo-bdg. Select the two destinations demo-s4-bupa and demo-loyalty. Leave the model extension input empty for now, this is what we are about to create. Activate the BDG in the final step. By default, Graph will use the namespace my.custom for destinations with services of unknown type, such as demo-loyalty in this case. When the business data graph is active we can start to model an extension for it.
Graph allows to customize business data graphs with model extensions. A model extension is a package that contains one or more custom entity definitions. To customize a business data graph, we create a new model extension for it and then add it to the BDG configuration.
Start in SAP Integration Suite under Design > Graph and open the Model Extensions tab. Create a new model extension called demo-extension and select the demo-bdg as modeling metadata BDG (this is only for retrieving metadata while modeling, the extension itself is independent).
No Model Extensions exist
Create a new Model Extension dialog
We will now create our custom entity demo.FrequentFlyer by composing it from two source entities. In the dialog select sap.s4.A_BusinessPartner as the main source entity. This is the entity that defines the identity of data-objects and is the source of the primary key for our custom entity. Then add my.custom.LoyaltyAccount as an additional source entity. Here, we need to define the join condition that defines how data objects from both entities are matched. For that we select which attributes from both entities are matching. When the complete primary key of the additional source attribute is matched, Graph infers that there exists a cardinality-relationship of 0 or 1 between the data objects of both entities, as is the case in our example.
In the other case where only a partial primary key is matched, a many-cardinality will be assumed. In that case, for each data object of the main source entity there could be any number of additional source data objects. Graph will treat that case as a composition, where an entity contains an array of sub-entities.
With the source entities defined, we continue by selecting which attributes of each source we want to project into our custom entity demo.FrequentFlyer. Here, we select the primary key attribute BusinessPartner of our main source entity in addition to other attributes from both sources (see below). Graph will suggest new names according to the Graph attribute naming best practices. Having selected some attributes we finalize the dialog via Create. We can then open our newly created custom entity and continue modeling the details.
Empty Model Extension
Custom Entity creation dialog
Source entities definition step
Additional source entity definition
Main source attribute selection
Additional source attribute selection
Model Extension with the newly created Custom Entity
Custom Entity attributes
When defining custom entities, graph allows to apply transform functions as part of the definition. When adding attributes from a source entity to the custom entity this is plainly called a rename transform (as was done in the entity creation dialog).
In our example, we want to change our data model and invert the boolean source attribute isMarkedForArchiving, which denotes whether an object was archived, and instead call the inverse isActive. For that we use the negation transform. We select the isMarkedForArchiving attribute and change the transform in the right-side panel to negation, rename the attribute and apply our changes.
Details of the applied negation transform
Graph allows to customize the graph structure of a business data graph with the help of custom associations in custom entities. For example, foreign-key relationships that are present in mirrored entities, can be converted into semantic associations between custom entities.
In our example, the additional source entity my.custom.LoyaltyAccount has an atttribute loyaltyProgramStatusId that references my.custom.LoyaltyStatus data objects by their ID. We turn this foreign-key relationship into an association as follows: in the dialog under Add > Association select the type of association. Here, it is a to-one association, as each LoyaltyAccount references only one LoyaltyStatus via ID.
Next, select the target of the association: my.custom.LoyaltyStatus. Graph will suggest a name according to the Graph modeling best practices.
Then define how these two entities are related by matching attributes from the source entity (foreign key) to the primary key attributes of the target entity. In our example we only map the LoyaltyAccount attribute loyaltyProgramStatusId to the single LoyaltyStatus key attribute statusId and then add the association to the custom entity.
This completes our example. Now we can apply the changes to our custom entity and save the extension.
Add Association dialog
Complete demo.FrequentFlyer Custom Entity definition
Now that we have created a model extension for our example scenario with the demo.FrequentFlyer custom entity we want to see it in action. For that we will apply the model extension to a BDG.
With an existing model extension, we can simply create a new BDG and select the extension during the BDG-creation dialog. Graph will then generate a BDG configuration with locating policy rules for all custom entities.
Selecting an existing Model Extension during BDG creation
Alternatively, we can also manually add a model extension to an existing BDG. Here we need to add the name of the extension to the top-level extensions array (see below), and add locating policy rules for all custom entities.
"extensions": [
"demo-extension"
],
BDG configuration extensions snippet
In our example we add a single custom entity that is based on two source entities which requires two entries in the BDG locating policy rules, one for each source entity (see also here). Add the following snippet to the BDG configuration under locatingPolicy.rules (adapt the name of the leading data sources to match the ones in your BDG).
{
"name": "demo.FrequentFlyer",
"leading": "s4",
"local": []
},
{
"name": "demo.FrequentFlyer",
"leading": "my.custom",
"local": [],
"sourceEntity": "my.custom.LoyaltyAccount"
}
BDG configuration locatingPolicy.rules snippet
Custom Entity Try Out in Graph Navigator
This small blog example illustrates how Graph can be used to compose APIs and customize the API surface with the help of a business data graph.
We used Graph to compose two different service APIs into a single connected business data graph: an SAP S/4HANA service and a custom CAP-extension service. We created a model extension containing a custom entity demo.FrequentFlyer with a custom association to another entity and a negation transform function.
To learn more about the full Graph modeling capabilities find the documentation here with more infomation on modeling topics such as all supported transform functions, creating compositions and adding to-many associations to your model.
Find the full BDG configuration JSON and custom entity definition JSON files used in the example demo below.
Custom Entity definition JSON file:
{
"entity": "demo.FrequentFlyer",
"version": "1.0.0",
"sourceEntities": [
{
"name": "sap.s4.A_BusinessPartner"
},
{
"name": "my.custom.LoyaltyAccount",
"join": [["BusinessPartner", "userId"]]
}
],
"attributes": [
{
"name": "id",
"source": ["BusinessPartner"],
"key": true
},
{
"name": "businessPartnerFullName",
"source": ["BusinessPartnerFullName"]
},
{
"name": "loyaltyProgramName",
"source": ["loyaltyProgramName"],
"sourceEntity": "my.custom.LoyaltyAccount"
},
{
"name": "loyaltyPoints",
"source": ["loyaltyPoints"],
"sourceEntity": "my.custom.LoyaltyAccount"
},
{
"name": "isActive",
"source": ["isMarkedForArchiving"],
"sourceEntity": "my.custom.LoyaltyAccount",
"transform": "negation",
"type": "Boolean"
},
{
"name": "_loyaltyStatus",
"type": "Association",
"associationTarget": "my.custom.LoyaltyStatus"
},
{
"name": "_loyaltyStatus.statusId",
"source": ["loyaltyProgramStatusId"],
"sourceEntity": "my.custom.LoyaltyAccount"
}
],
"annotations": {
"description": "",
"readonly": false
}
}
BDG configuration JSON:
{
"businessDataGraphIdentifier": "demo-bdg",
"graphModelVersion": "^v3",
"schemaVersion": "1.2.1",
"dataSources": [
{
"name": "my.custom",
"services": [
{
"destinationName": "demo-loyalty",
"path": ""
}
],
"namespace": "my.custom"
},
{
"name": "s4",
"services": [
{
"destinationName": "demo-s4-bupa",
"path": ""
}
],
"namespace": null
}
],
"locatingPolicy": {
"cues": [],
"rules": [
{
"name": "sap.s4.*",
"leading": "s4",
"local": [],
"cues": [],
"sourceEntity": null
},
{
"name": "sap.graph.*",
"leading": "s4",
"local": [],
"cues": [],
"sourceEntity": null
},
{
"name": "my.custom.*",
"leading": "my.custom",
"local": [],
"cues": [],
"sourceEntity": null
},
{
"name": "demo.FrequentFlyer",
"leading": "s4",
"local": [],
"cues": [],
"sourceEntity": null
},
{
"name": "demo.FrequentFlyer",
"leading": "my.custom",
"local": [],
"sourceEntity": "my.custom.LoyaltyAccount",
"cues": []
}
],
"description": "",
"keyMapping": []
},
"effectiveGraphModelVersion": "3.1.0",
"description": "",
"exclude": [],
"extensions": ["demo-extension"]
}
---
Florian Moritz
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
22 | |
13 | |
10 | |
10 | |
8 | |
7 | |
6 | |
6 | |
5 | |
5 |