Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
florian_moritz
Advisor
Advisor

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.

Example Scenario

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:

blog-example-scenario.png
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.

Example Setup

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.

(1) Setting up Graph and SAP Integration Suite

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.

(2) Setting up the SAP S/4HANA Sandbox Destination

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.

(3) Setting up the demo CAP Extension Service Destination

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.

(4) Preparing a Business Data Graph for the Example Scenario

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.

Custom Entity Modeling

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).

1.jpeg
No Model Extensions exist

2.jpeg
Create a new Model Extension dialog

 

Creating a Custom Entity

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.

3.jpeg
Empty Model Extension

4.jpeg
Custom Entity creation dialog

6.jpeg
Source entities definition step

5.jpeg
Additional source entity definition

7.jpeg
Main source attribute selection

8.jpeg
Additional source attribute selection

9.jpeg
Model Extension with the newly created Custom Entity

10.jpeg
Custom Entity attributes

 

Applying Transform Functions

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.

11.jpeg
Details of the applied negation transform

 

Adding a new Association

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.

12.jpegAdd Association dialog

13.jpeg
Complete demo.FrequentFlyer Custom Entity definition

 

Applying the Model Extension to the Business Data Graph

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.

Creating new BDGs with Model Extensions

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.

14.jpeg
Selecting an existing Model Extension during BDG creation

Adding Model Extensions to existing BDGs

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

 

Finally, we activate the BDG with the included model extension to try it out. Once the BDG was updated we can open the Graph Navigator in SAP API Business Hub Enterprise (see also this blog). There we can see that our updated demo-bdg now has a demo.FrequentFlyer entity with the schema we previously modeled. In the "Try Out" we can also see that we can follow the new _loyaltyStatus association via $expand or semantic navigation.
navigator-schema.jpeg
Custom Entity schema in Graph Navigator
 
navigator-tryout.jpeg

Custom Entity Try Out in Graph Navigator

 

Summary

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.

 

Reference Materials

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

1 Comment