Skip to Content
Technical Articles
Author's profile photo Florian Moritz

Part 4: The SAP Graph data protocol

What you will learn: use SAP Graph with OData to fetch data and explore the structure of the unified data model exposed by SAP Graph.

Hello!

In this fourth part of the tutorial on SAP Graph – the unified API for SAP’s Integrated Intelligent Suite – we will focus on the data protocol that SAP Graph uses, OData, to explore the structure of the unified data model exposed by SAP Graph. Please refer to the information map to see all parts of this tutorial series.

OData – the protocol used by SAP Graph

SAP Graph is built on open standards and technologies. Clients communicate with SAP Graph using the Open Data Protocol (OData). This is a standardized RESTful HTTP protocol with defined semantics that help promote interoperability between services. SAP Graph follows the OData V4 protocol.

OData is centered around resources (data entities), which are identified by URLs. In SAP Graph, there are for example the Customer, Product or CustomerQuote entities. The structure of these entities is defined in an Entity Data Model (EDM) which can be inspected by clients. OData provides many operations to filter or search in entity collections, to navigate between associated entities and to adapt the response format.

With OData, SAP Graph exposes a single unified API with defined semantics and a unified data model, for all SAP-managed data.

We will now look at examples on how to formulate OData requests for SAP Graph.

Tutorial setup

To keep things simple, we will be using the SAP Graph sandbox endpoint. All you need to use this endpoint is your favorite HTTP tool, for example Postman, and your API key from SAP API Hub. To retrieve your API key, log into SAP API Business Hub, go to one of the SAP Graph resources and copy your API key from the Show API Key button.

To make requests against the SAP Graph sandbox, add your API key as an HTTP header in your requests: apiKey: <your API key>. Then you can use the SAP Graph sandbox through the following endpoint:

https://sandbox.api.sap.com/sapgraph/

 

Alternatively, you could make requests against the SAP Graph sandbox in a web browser using the lightweight app you configured in part 2 of this tutorial series.

Note: The API key is just used for the purposes of this sandbox endpoint and not relevant in the context of OData requests or productive SAP Graph instances.

Also note, that the URL of the SAP Graph sandbox differs from the productive URL of SAP Graph: https://eu30.graph.sap/api.

Exploring the OData data model

OData defines an Entity Data Model that describes the structure of all known entities. This helps developers and clients alike to reason about the available entities and their structure. The data model and further metadata can be inspected through a special $metadata endpoint. SAP Graph makes metadata available for each namespace, like sap.odm.sales or sap.odm.product.

To retrieve the metadata of the sales domain in SAP Graph, make the following request, which will return an EDMX specification (an XML dialect for describing OData Entity Data Models):

https://sandbox.api.sap.com/sapgraph/sap.odm.sales/$metadata

In the response, we can inspect the structure of all the entities (and sub-entities) that are described as EntityType entries as well as other metadata. Let’s have a closer look at the definition of the CustomerQuote entity type in this extract from the sales domain metadata:

  ...
  <EntityType Name="CustomerQuote">
      <Key>
          <PropertyRef Name="id"/>
      </Key>
      <Property Name="id" Type="Edm.String" MaxLength="256" Nullable="false"/>
      <Property Name="text" Type="Edm.String" MaxLength="40"/>
      <Property Name="requestedFulfillmentDate" Type="Edm.DateTimeOffset"/>
      <Property Name="totalAmount" Type="Edm.Decimal" Scale="6" Precision="22"/>
      <Property Name="currency" Type="sap.odm.sales.api.CustomerQuote_currency"/>
      <NavigationProperty Name="items" Type="Collection(sap.odm.sales.api.CustomerQuote_items)" Partner="up_" ContainsTarget="true"/>
      ...
  </EntityType>
  ...

We can see that a CustomerQuote has several properties of different types, such as String or Decimal, but also more complex structured types like the items property, which is a collection of several sap.odm.sales.api.CustomerQuote_items, that are also defined in the same data model. Furthermore, we see that the id property is referenced as key for this entity type. Navigation Properties allow for navigation to a related entity. The items property is a navigation property because the sap.odm.sales.api.CustomerQuote_items is modeled as a separate entity type in the metadata.

Let’s look at an example. Add the following query path to the sandbox endpoint to make the request. This will retrieve one CustomerQuote entity (here we add $top=1 to limit the result set to one entity):

/sap.odm.sales/CustomerQuote?$top=1

From inspecting the metadata, we have learned that CustomerQuotes have items, however when comparing with the response from the example, no items are included in the response.

The reason for this is that OData has a mechanism for the client to control which navigation properties are included as part of the response. This is called expanding a property. By default, SAP Graph returns responses non-expanded if not specified by the client. In addition to expanding the response, OData also allows for restricting it to requested values only. We will have a look at these mechanisms next.

Expanding and restricting the response

OData allows clients to adapt the response format in two ways. Clients can restrict the response to a set of specified properties via $select. And they can expand the response by including referenced entities inline as part of the response via $expand.

If we only require the totalAmount of a CustomerQuote, we can restrict the response by adding it to the $select query parameter:

/sap.odm.sales/CustomerQuote?$top=1&$select=totalAmount

This will return only the totalAmount property along with the id, as it is the key and therefore always included.

If we also require the items of a CustomerQuote, we need to expand the response (as it is a navigation property) by adding it to the $expand query parameter:

/sap.odm.sales/CustomerQuote?$top=1&$select=totalAmount&$expand=items

This will result in the items array being returned as part of the CustomerQuote response as illustrated here:

Expand%20Items%20Illustration

If we have a look at a response snippet, this is what is being returned:

{
    "@odata.context": "$metadata#CustomerQuote(totalAmount,id,items())",
    "value": [
        {
            "id": "C4C~1",
            "items": [
                {
                    "text": "Green Emission Calculator",
                    "product": {
                        "id": "C4C~P300100"
                    },
                    "quantity": 1,
                    "quantityUnit": {
                        "code": "EA"
                    },
                    "id": "10"
                }
            ],
            "totalAmount": 890
        }
    ]
}

Note that we do not have to specify expanded properties explicitly as part of $select.

We see that the item in the example above has a property product that references an id. When we inspect the metadata of the items by searching for the EntityType CustomerQuote_items. We see that the product navigation property references an sap.odm.product.api.Product.

  ...
  <EntityType Name="CustomerQuote_items">
      <Key>
          <PropertyRef Name="id" >
      </Key>
      <Property Name="id" Type="Edm.String" MaxLength="6" Nullable="false"/>
      <Property Name="text" Type="Edm.String" MaxLength="40"/>
      <NavigationProperty Name="product" Type="sap.odm.product.api.Product"/>
      ...
  </EntityType>
  ...

To also include this product as part of the response, we can expand it inside the already expanded items: a nested expand.

/sap.odm.sales/CustomerQuote?$top=1&$select=totalAmount&$expand=items($expand=product)

Which will include the product response inline in the item of the CustomerQuote response.

Nested%20Expand%20Illustration

If we also want to adapt the format of the expanded product we can nest a $select query parameter in parentheses after the product. To restrict the nested product to the displayId, for example:

/sap.odm.sales/CustomerQuote?$top=1&$select=totalAmount&$expand=items($expand=product($select=displayId))

If we also want to select more properties, such as currency, we can just add them to the $select query parameter targeting the CustomerQuote, separating by commas:

/sap.odm.sales/CustomerQuote?$top=1&$select=totalAmount,currency&$expand=items($expand=product($select=displayId))

The response for the CustomerQuote with included currency, items and product now looks like this:

{
    "id": "C4C~1",
    "currency": {
        "code": "USD"
    },
    "items": [
        {
            "text": "Green Emission Calculator",
            "product": {
                "id": "C4C~P300100",
                "displayId": "P300100"
            },
            "quantity": 1,
            "quantityUnit": {
                "code": "EA"
            },
            "id": "10"
        }
    ],
    "totalAmount": 890
}

Working with collections: filtering, ordering and pagination

When working with collections of entities, we typically want to filter the entities by some criteria or arrange them in a specific order. In OData this is supported via the $filter and $order query parameters. With $top and $skip we can additionally define a sliding window over the result to implement pagination.

To continue with our example above, let’s remove the $top=1 we added initially to retrieve a collection of CustomerQuotes. Say we want to retrieve all CustomerQuotes with a value greater than 100 U.S. Dollars.

The value condition can be formulated with the greater equal operator: totalAmount ge 100. For the currency condition we need to access the code inside the currency property and compare it with a string (enclosed in single quotes): currency/code eq ‘USD’. We then combine these conditions with a logical and expression and add it to the example query below. We also define an ordering on the totalAmount property with the $orderby query parameter, which is ascending by default.

Note: OData operators are lower-case and space-separated. This requires URL encoding. If you are using Postman for this tutorial you don’t need to worry as Postman automatically applies URL encoding.

/sap.odm.sales/CustomerQuote?$select=totalAmount,currency&$expand=items($expand=product($select=displayId))&$filter=totalAmount ge 100 and currency/code eq 'USD'&$orderby=totalAmount

Note: OData only supports writing filter expressions using a small vocabulary of filter operators. See here for a full list.

As a last step, we will now define a paging-window over all results. This can be achieved with the query parameters $top, which specifies how many result entities should be returned: the page size, and $skip, which defines how many result entities should be skipped from the beginning of the ordering. Hence, we describe the page size with $top and index the single pages with multiples of the page size in $skip. For the second page of five entities each, this would translate to our example as follows:

/sap.odm.sales/CustomerQuote?$select=totalAmount,currency&$expand=items($expand=product($select=displayId))&$filter=totalAmount ge 100 and currency/code eq 'USD'&$orderby=totalAmount&$top=5&$skip=5

Summary

In this tutorial we had a look at OData, the data protocol used by SAP Graph. We covered all the features that you as a developer working with SAP Graph need to know, like how to:

  • formulate complex queries
  • inspect the metadata and structure of the unified data model
  • expand and restrict responses
  • work with collections

OData itself offers much more than what we showed in this tutorial. You can read more about it in the standard.

With SAP Graph, you as a developer now have one data protocol you can use together with one API to retrieve data in one unified format, no matter the source system.


Florian Moritz, User Experience Developer – SAP Graph

Visit the SAP Graph website at http://explore.graph.sap/

Contact us at sap.graph@sap.com


 

Assigned tags

      1 Comment
      You must be Logged on to comment or reply to a post.
      Author's profile photo DJ Adams
      DJ Adams

      A great post, thanks Florian.

      For those folks wanting to learn more about OData, might I suggest this Mission in our SAP Developers Tutorial Navigator:

      Take a Deep Dive into OData

      and in particular the first tutorial of the first group:

      Learn about OData Fundamentals

      This tutorial gives some background on OData, where it came from, and will hopefully help folks better understand the design and mechanics of this open standard.

      cheers!

      dj