Learn SAP from the Experts | The SAP PRESS Blog

Introduction to OData in SAP

Written by SAP PRESS | Jun 19, 2023 1:00:00 PM

The OData protocol describes the accesses to REST application programming interfaces (APIs) and defines what the responses should look like.

 

REST provides a uniform concept for communication interfaces in web architectures and is fundamentally based on HTTP requests. In this context, you should always keep in mind that these requests are stateless. Stateless, in this case, means that there is no connection establishment or termination. Each request-response cycle must contain all the necessary information so that this communication isn’t dependent on any further information.

 

Requests sent to an OData interface must conform to a specific Uniform Resource Identifier (URI) syntax. This syntax is defined by OData, as shown in this figure.

 

 

All sections of this syntax up to the resource automatically result from which server the OData service is running and how it can be reached. This part of the request is also called the service root URI. For example, such a service root URI may look like the following:

 

https://services.odata.org/OData/OData.svc

3

The other elements of the request vary depending on what information you want to request and how it should be formatted, filtered, and sorted.

 

Another part of the URI syntax is the specification of which resources are accessed. For this purpose, special requests have been defined for certain resources, which can be specified in the URI syntax at the position of the respective resource. If the resource is omitted completely, that is, if only the root URI service is called, the OData service must return a service document. In this document, you get all possible resources with their URIs and the names of these resources. As an example, the figure below shows the response of the service root URI listed previously.

 

 

In most cases, it’s not enough to know only the names of these resources, which are also called entities. You also need to know how they are structured and what attributes and navigation attributes or relationships they have. For these purposes, the service metadata document will be returned when you add the /$metadata URI option to the service root URI. For example, our request would look like this:

 

https://services.odata.org/OData/OData.svc/$metadata

 

You can see an excerpt from the response in the next figure.

 

 

To be able to read this document—and more generally to understand the concept of OData—you have to get rid of the principles of classical database modeling and start to think with entities. You can think of entities as objects. They have certain properties and relationships among each other (also called navigation properties).

 

An entity is always described by an entity type (also called entity data model), which can be taken from the service metadata document. As an example, look at the entity type (EntityType) below, and try to extract the relevant information.

 

<EntityType Name="Product">

   <Key>

       <PropertyRef Name="ID"/>

   </Key>

   <Property Name="ID" Type="Edm.Int32" Nullable="false" />

   <Property Name="Name" Type="Edm.String" />

   <Property Name="Description" Type="Edm.String" />

   <Property Name="ReleaseDate" Type="Edm.DateTime" Nullable="false"/>

   <Property Name="DiscontinuedDate" Type="Edm.DateTime"/>

   <Property Name="Rating" Type="Edm.Int16" Nullable="false"/>

   <Property Name="Price" Type="Edm.Double" Nullable="false"/>

   <NavigationProperty Name="Categories"

       Relationship="ODataDemo.Product_Categories_Category_Products"

       ToRole="Category_Products" FromRole="Product_Categories"/>

   <NavigationProperty Name="Supplier"

       Relationship="ODataDemo.Product_Supplier_Supplier_Products"

       ToRole="Supplier_Products" FromRole="Product_Supplier"/>

   <NavigationProperty Name="ProductDetail"

       Relationship="ODataDemo.Product_ProductDetail_ProductDetail_Product"

       ToRole="ProductDetail_Product" FromRole="Product_ProductDetail"/>

   </EntityType>

 

The Product entity type has several attributes here, including the ID attribute, which is also the (primary) key of the entity. Besides the ID of type Edm.Int32, there are also the attributes Name and Description of type Edm.String and some others.

 

The NavigationProperty hints at whether this product entity has relationships to other entities. However, you can’t read the cardinalities of these relationships at this point. They are listed separately further down in the service metadata document.

 

In the prior listing, you can easily see that all attributes have their own specific type. These types are defined in the abstract type system. All primitive types that can be used by properties are defined there. For example, you can see the type Edm.Int32. There are many such primitive types, which we won’t discuss in detail in this chapter. They are described in the official OData documentation.

 

With an open standard, you must ensure that the interfaces can exchange and process data even without knowing which products will ever communicate with each other via these interfaces. Therefore, all data provided by an OData interface must have one of these predefined types.

 

To display several entities in a bundle, EntitySets are used. These can be compared to lists or arrays in object-oriented programming. For each query, a set of entities is returned. This set can also be empty. The entity sets can be found at the end of the service metadata document in the EntityContainer section (see below).

 

<EntityContainer Name="DemoService" m:IsDefaultEntityContainer="true">

   <EntitySet Name="Products" EntityType="ODataDemo.Product"/>

   <EntitySet Name="ProductDetails" EntityType="ODataDemo.ProductDetail"/>

   <EntitySet Name="Categories" EntityType="ODataDemo.Category"/>

   <EntitySet Name="Suppliers" EntityType="ODataDemo.Supplier"/>

   <EntitySet Name="Persons" EntityType="ODataDemo.Person"/>

   <EntitySet Name="PersonDetails" EntityType="ODataDemo.PersonDetail"/>

   <EntitySet Name="Advertisements" EntityType="ODataDemo.Advertisement"/>

   <FunctionImport Name="GetProductsByRating"

       ReturnType="Collection(ODataDemo.Product)"

       EntitySet="Products" m:HttpMethod="GET">

        <Parameter Name="rating" Type="Edm.Int16" Nullable="false"/>

   </FunctionImport>

</EntityContainer>

 

The architecture of OData allows multiple entity sets with different names to exist for one entity type. This allows different lists of data to be offered to interface consumers without them having to explicitly filter or perform other functions. This concept could be compared to a product catalog, where not only a set of products exists, but also a set of favorite products, a product ranking, and so on.

 

Editor’s note: This post has been adapted from a section of the book SAP Fiori Elements: Development and Extensibility by Rene Glavanovits, Martin Koch, Daniel Krancz, and Maximilian Olzinger.