Rehan Zaidi explains the essential concepts for developing on the SAP Mobile Platform and, in particular, how to work with OData.
Key Concept
Open Data (OData) Protocol is a protocol based on HTTP, XML, and Atom (the combination of the Atom Syndication Protocol and the Atom Publishing Protocol). OData is proprietary to Microsoft but is extensible. SAP has come up with OData for SAP that provides additional information on the exposed data.
The new release of the SAP Mobile Platform emphasizes the use of Open Data (OData) Protocol/services for exposing SAP data consumed by mobile applications. The OData approach was used for online applications. However, from SAP Mobile Platform 3.0 on, there is now support for offline applications. In addition, it can be used in the development of both hybrid as well as native applications. This makes OData an important topic for SAP mobility development.
The aim of this article is to give you an understanding of the OData Protocol and what you need to know about OData before starting mobile application development in an SAP system. I use the Firefox browser and the Representational State Transfer (REST) Client Add-on for illustrating Create, Read, Update, and Delete (CRUD) operations. Throughout the article, examples are included from the products and categories collections exposed at the sample services on the OData.org web site.
OData Backgrounder
OData Protocol allows RESTful access to resources in the form of a service via CRUD operations through a web address. It is based on HTTP, XML, and Atom.
Note
ATOM is the combination of Atom Syndication Format and Atom Publishing
Protocol.Atom Syndication Format is an XML-based language that defines
the format for the returned data in the form of feeds that are comprised
of entries. Each entry is a record (identified by a key) pertaining to a
particular item or object (e.g., the set Categories contains a number
of Category entries). Atom Publishing Protocol defines how to read and
maintain web resources. It is an HTTP-based protocol that uses GET,
POST, PUT, and DELETE HTTP verbs.
Note
In this article, the terms URI and URL are used interchangeably.
An OData service uses the Entity Data Model (EDM) as the underlying data model. Within the EDM, you may have a number of entities that are linked together via associations. An entity can be defined as an instance of entity type; the entire set of these entities forms the entity set. An entity type represents the business object for a given scenario and can consist of a number of properties. Each entity type has a key based on one or more entity properties. For example, you have an entity type Category that has properties CategoryID, CategoryName, and Description, from which the CategoryID is the key property. Each entity can support CRUD operations. For example, you can display all categories or a particular category, create new categories, update the description of a particular category, or delete a given category.
There can be links or associations between two entity types. In addition to the other properties, an entity may have a special property known as a Navigation Property representing the link or association to another entity type. Via Navigation Properties, OData allows dynamic navigation between entities. For example, within the Category entity type, a navigation property called Products lets you link each Category entry with a collection of products (an example of this is in the upcoming section).
Service Document and Metadata Document
Two important documents exist for every OData service: the service document and the metadata document. I show how to access these documents via Uniform Resource Identifiers (URIs).
Each service has a service root URI. For example, say you have a Northwind OData service at the URI
https://services.odata.org/V2/Northwind/Northwind.svc. When you write the root URI in the browser or in a RESTClient using the GET method, it returns the service document listing the entity collections that are exposed by the service.
Note
Northwind Service is a freely accessible sample service at the odata.org
web site provided to allow developers to test the OData concepts
without creating it themselves.
Figure1

Figure 1
Service document of a sample Northwind service
To view this document, use /$metadata at the end of the service root URI. For example, for the Northwind service, the metadata URI is https://services.odata.org/V2/Northwind/Northwind.svc/$metadata. The returned EDMX document looks like the one shown in Figure 2 (partial view).

Figure 2
Metadata document of Northwind service
In the case of service and metadata document retrievals, execute a GET HTTP request. As you can see, the Categories collection related to the Entity type Category has a number of Properties, namely CategoryID, CategoryName, and Description. The CategoryID is the key property of the Category entity type. There is also a NavigationProperty Products linking Products and Categories.
The EDMX document tells you more about the types and length of the properties involved. Some of the supported types are shown in Table 1.
Null |
Absence of a value |
Edm.Binary
|
Fixed/variable length binary data
|
Edm.Boolean
|
Boolean (i.e., True/False)
|
Edm.Byte
|
Unsigned 8-bit integer
|
Edm.DateTime
|
Date and time
|
Edm.Decimal
|
Numeric value having fixed precision and scale
|
Edm.Int16
|
Signed 16-bit integer
|
Edm.Int32
|
32-bit integer
|
Edm.Time |
Time |
Edm.String
|
String fixed- or variable-length characters
|
Table 1
Basic data types available in OData
Note
While specifying collection or property names, you must provide the
correct case. For example Categories must not be written as
“categories,” and so on.
Figure 3
http:/services.odata.org/V2/Northwind/Northwind.svc/Categories
|----------------------Service Root URI-------------|--Resource Path-----|
Figure 3
URI for retrieving categories
If you like to view all categories having the CategoryID equal to 1, the corresponding URI looks like the one shown in Figure 4.
http:/services.odata.org/V2/Northwind/Northwind.svc/Categories(1)
|----------------------Service Root URI------------|--Resource Path-----|
Figure 4
Category ID equals 1
Likewise, if you need to have all products pertaining to the Category 1, use the resource path shown in Figure 5.
http:/services.odata.org/V2/Northwind/Northwind.svc/Categories(1)/Products
|----------------------Service Root URI-----------|-----Resource Path-----|
Figure 5
Resource path for accessing Products of Category "1"
Figure 5yFigure 2
The service root URI and the resource path can be supplied with further query options. The query option allows you to control the amount (or order) of returned data or to get further information on the specified resource. Figure 6 is an example.
http:/services.odata.org/V2/Northwind/Northwind.svc/Categories(1)/Products?$inlinecount=allpages
|----------------------Service Root URI------------|-----Resource Path-----|--Query Option------|
Figure 6
Example of a query string
OData Operations
As mentioned, the OData supports CRUD-style operations. These operations are Read (Retrieve), Create (Insert), Delete, and Update. The OData allows access to resources in the form of services via HTTP requests. Each operation is mapped to a corresponding HTTP method as depicted in Table 2.
Operation |
HTTP method |
Read (Retrieve)
|
GET |
Create (Insert)
|
POST |
Delete |
DELETE |
Update |
PUT |
Table 2
OData operations and corresponding HTTP methods
It is up to the service provider to support all or some of the operations mentioned. For illustrating the use of operations, I selected a read-write service freely available at the odata.org web site:
https://services.odata.org/V2/(S(xuh52ptttgitgrkbtjzk1o31))/OData/OData.svc/.
This service supports all the above-mentioned operations. While developing mobile applications, the developer needs to write the appropriate coding for carrying out the operations provided by the OData service. However, I use the RESTClient Add-on of the Firefox browser to illustrate the execution of the operations.
Note
The output of the OData service operation can be returned in two
formats, namely XML and JSON. I’m using the XML format, which is the
default format. For JSON, use ?$format=json after the supplied URI.
Read Operation
Read operations allow you to read an entire entity set (ReadEntitySet ) or a specific entity within an entity set (ReadEntity), returning a collection of entities (in a feed) or a single entity (in an entry document), respectively. (The HTTP GET request is used for the read operations.)
The ReadEntitySet enables you to get the entities within a particular entity set. You can simply carry out the read operation using the HTTP GET method of the RESTClient Add-on within a browser. For retrieving an entire entity set, use the name of the entity set at the end of the specified URI. For example, for retrieving the entire entity set Categories, this is the URI: https://services.odata.org/V2/%28S%28xuh52ptttgitgrkbtjzk1o31%29%29/OData/OData.svc/Categories.
Figure 7

Figure 7
Response body GET method
In this case, as you can see, the entity set is returned in a feed document that consists of three entries. You can expand a given entry to see its properties.
The ReadEntity operation, on the other hand, lets you retrieve the details of a single entity within an entity set. For testing such an operation using the RESTClient, you use the same GET method and place the URI in the respective field as shown in Figure 8.

Figure 8
GET Request for the ReadEntity operation
Since you need the details of the Category with the ID equal to 1, you use the URI of the ReadEntitySet operation for products, followed by the relevant key (in this case ….Categories([ID=1]).
The response body, in this case, is the one shown in Figure 9.

Figure 9
Response of RetrieveEntity operation
This contains the details of a single entity (i.e., Category 1 [Beverages]). For both operations, after success, the Status Code is the one shown in Figure 10.

Figure 10
Status code 200 OK
For both the read operations, you may have a number of query options after the URI. (This is covered in the next section).
Create Operation
The create operation allows you to create a new entity of a given entity type. The HTTP POST method request is used for carrying out the create operation. The URI supplied must be the same as the one used for retrieving the entity set of the type in question. For example, if you are creating the new Category, use the following URI: ……/Categories.
As a test purpose, use the RESTClient Add-on for the browser that allows you to execute the POST HTTP request. The RESTClient appears as shown in Figure 11.

Figure 11
RESTClient POST method
Make sure that POST is specified in the Method field. Enter the URI in the relevant field. Enter the content of the entry to be created (inserted) in the Body field. Before executing the POST method, you need to specify the Content-Type as application/atom+xml in the Header. The content entered in the Body field is shown in Figure 12.
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<entry
xmlns:d="https://schemas.microsoft.com/ado/2007/08/dataservices"
xmlns:m="https://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
xmlns="https://www.w3.org/2005/Atom">
<content type="application/xml">
<m:properties>
<d:ID m:type="Edm.Int32">3</d:ID>
<d:Name>Books</d:Name>
</m:properties>
</content>
</entry>
Figure 12
Body content for creating a new category
Once the URL is correctly entered as well as the body, click the SEND button. If the entity is successfully created, a new Category named Books is created. The Response header shows the Status Code 201 Created and the location of the newly created Category is also shown (Figure 13).

Figure 13
Response header for successful insertion
UpdateEntity Operation
The UpdateEntity operation updates an entity (i.e., changes the existing properties of the entity). The PUT HTTP method is involved in this case. Suppose you have already created a new Category entity (with property CategoryID equal to 3) having the name Books using the Insert operation. You can later change the name of the entity from Books to Books and Ebooks using the update operation.
When using the RESTClient, you enter the following URL in the relevant field:
https://services.odata.org/V2/(S(xuh52ptttgitgrkbtjzk1o31))/OData/OData.svc/Categories(3)
The exact entity that has to be modified must be specified (in this case, Category with ID equal to 3). The content body must be as shown in Figure 14, representing the entity to be updated (partial view).
…..
<content type="application/xml">
<m:properties>
<d:ID m:type="Edm.Int32">3</d:ID>
<d:Name>Books and Ebooks</d:Name>
</m:properties>
</content>
</entry>
Figure 14
Content body
Delete Operation
For deleting a particular entity from an entity set, use the delete operation via the DELETE HTTP method. The specified URI must indicate the specific entry that is to be deleted. For the Categories example, suppose you want to delete the entity having the key property CategoryID 2 via the RESTClient add-on. Figure 15 shows the URI that has to be used. The Method DELETE must also be specified.

Figure 15
DELETE Method executed in RESTClient
OData System Query Options
Now you see the OData system query options in detail. Query options are query-string parameters that can be specified to limit the amount and vary the order of the data that an OData service returns. Within the URI, these query options are prefixed with the $ character. An OData service may or may not support the entire query options listed. The service provider decides which of the mentioned Query options are supported.
Note
For brevity’s sake, in the examples of this section, I only show the query option under consideration instead of the entire URI.
- $format. This query option lets you retrieve the result set in a specified format. For example, if you want the results in a JSON format, use the query option in Figure 16.
…../Categories(1)/Products?$inlinecount=allpages&$format=json
Figure 16
Specifying a format
In this case, the results are shown in JSON format (Figure 17).

Figure 17
Response body in JSON format
In this case, the XML format is to be specified, so the query option looks like the one in Figure 18.
…../Categories(1)/Products?$inlinecount=allpages&$format=xml
Figure 18
Query option for XML format
- $filter. The $filter query option allows you to filter the results according to certain sets of criteria. In other words, it identifies a subset of the entries in the collection to which it is applied. This may be seen as analogous to the WHERE clause within an open SQL SELECT statement. With this query option, you can use a number of logical and arithmetic operators. Following are a few examples of how you can use this filter query option.
Suppose you want to get the details of the product whose name is Côte de Blaye. Using the filter option, the corresponding query string end looks like Figure 19.
……/Products?$filter=ProductName eq 'Côte de Blaye'
Figure 19
Filter option based on ProductName
Figure 20

Figure 20
Details of product Cote de Blaye
In case you have a ProductName that has apostrophe in it, you can specify it in the query option by adding an adding an extra apostrophe (’) before the one contained in the name. For example, to read the details of the product where the product name is equal to Sir Rodney’s Marmalade, use the query option in Figure 21.
……..Products?$filter=ProductName eq 'Sir Rodney''s Marmalade'
Figure 21
Fetching a product name containing an apostrophe
Figure 22
…..Products?$filter=UnitPrice gt 50
Figure 22
Finding products with a unit price greater than 50
Figure 23
…..Products?$filter=UnitPrice ge 10 and UnitPrice le 65
Figure 23
Finding products within a price range
Figure 24
……..Products?$filter=startswith(ProductName, 'S')
Figure 24
Finding Products starting with the letter S
Figure 25
……..Products?$filter=UnitPrice gt 50 and Discontinued eq ‘false’
Figure 25
Multiple properties usage in query
The query in Figure 25 returns all products with a unit price greater than 50 that are not in a discontinued state.
- $orderby. This query option enables sorting of the retrieved entries with respect to a given property. For example, in the case of the products example, you can sort products according to the unit price or the product name. You have the option of sorting in both ascending or descending order. By default the sorting is ascending. See the example in Figure 26.
...../Products?$orderby=Price
Figure 26
Sort by unit price
The string in Figure 26 sorts the retrieved products according to the unit price. However, if you want to sort the products using the price but in descending order, add desc as shown in Figure 27.
...../Products?$orderby=Price desc
Figure 27
Sort in descending order
- $select. Using the $select query option, you can limit the properties contained in the response body. This is similar to the specification of a fields list with the SELECT statement used in Open SQL. If a single property (for example, ProductName) is desired, the query option looks like the one in Figure 28.
……/Products?$select=ProductName
Figure 28
Selecting the property ProductName
Figure 29
……/Products?$select=ProductName,Price
Figure 29
Selecting more than one property
Figure 30 shows another example of multiple properties along with the filter and order by option.
……$filter=Rating gt 4&$orderby=Price&$select=Rating,Price
Figure 30
All products with a rating greater than 4
In this case, all products that have a rating greater than 4 are returned. These entries are sorted in ascending order based on the price. In addition, only the rating and price properties are included, rather than all product properties.
- $top. The $top returns the first (or top) N number of entries from a specified collection. For example if you want only the top 10 products from the relevant entity set, the following is the query string (Figure 31).
Figure 31
Top 10 products
- $skip. As the name denotes, this query option skips a particular number of entities from a given collection. For example if you want to skip the first 10 entries, use the following string in Figure 32.
Figure 32
Skip 10 entries
Figure 33
...../Products?$top=10&$skip=20
Figure 33
Using $top and $skip
- $count. This query option allows you to retrieve the total number of entries identified by a resource path (and any other query string parameter used). In this case, only a single raw value pertaining to the number of the entries is shown (Figure 34).
Figure 34
Getting the value of entries in the resource path
Figure 34
Figure 35 shows another example.
Figure 35
Getting all products in Category 1
In Figure 36 the resource path and filter query option identifies all products that have products with names beginning with the letter B. The total number of these products is returned as a raw value.
…./Products/$count/?$filter=startswith(Name, 'B')
Figure 36
Total number of products starting with the letter B
- $inlinecount. In contrast to the $count query option, the $inlinecount option allows you to include the identified entries by the resource path and the query options in the response body along with total count of the entries (Figure 37).
Figure 37
Total count of entries within the response body
Figure 38

Figure 38
Response body with count value
Figure 39 shows another example.
Figure 39
Total product number printed with first six products
- $value. This query option is used for retrieving the raw value of a particular property of a given entity. Figure 40 shows another example.
…..Products(1)/Rating/$value
Figure 40
Products by rating
In this case, the rating of the Product having the ID 1 is returned. In case the $value is not used, the Rating of the Product 1 is displayed in XML format. The various query options used in the read operations URI can be seen as analogous to the different elements of a SELECT statement written in Open SQL. Figure 41 shows the similarities.
GET URI format used in OData Retrieve Operation:
Root URI~/EntitySet?$filter=...&$orderby=...&$top=...&$select
Similar to Open SQL Statement having the form:
SELECT ($select) FROM EntitySet
WHERE ($filter)
ORDER BY ($orderby)
UP TO ($top) ROWS
Figure 41
Similarities between GET URIs and Open SQL select statements
Rehan Zaidi
Rehan Zaidi is a consultant for several international SAP clients (both on-site and remotely) on a wide range of SAP technical and functional requirements, and also provides writing and documentation services for their SAP- and ABAP-related products. He started working with SAP in 1999 and writing about his experiences in 2001. Rehan has written several articles for both SAP Professional Journal and HR Expert, and also has a number of popular SAP- and ABAP-related books to his credit.
You may contact the author at erpdomain@gmail.com.
If you have comments about this article or publication, or would like to submit an article idea, please contact the editor.