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 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 composed 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.)
Via an OData service, you can expose data from one or more collections, each of which can be composed of zero or more entries. An example is a service having a collection named Categories that has three entries, each of which pertains to a given category. OData allows access to resources via operations. The service clients use HTTP requests (such as POST, GET, and so on) to carry out operations on the exposed resources.
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).
(In this article, the terms URI and URL are used interchangeably.)
Each service has a service root URI. For example, say you have a Northwind OData service at the URI
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.)
In Figure 1, the Northwind service has a number of collections such as Categories, Customers, and Employees. In the service document, there is no detailed information about the properties of the entity types.
Service document of a sample Northwind service
Each OData service has a metadata document corresponding to the underlying EDM in XML format. This is also known as a service metadata (EDMX) document. To view this document, use /$metadata at the end of the service root URI. For example, for the Northwind service, the metadata URI is http://services.odata.org/V2/Northwind/Northwind.svc/$metadata. The returned EDMX document looks like the one shown in Figure 2 (partial view).
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.
Absence of a Value
Fixed/Variable length binary data
Boolean i.e True/False
Unsigned 8-bit Integer
Date and Time
Numeric Value having fixed precision and scale
Signed 16 bit Integer
32 bit Integer
String fixed- or variable-length characters
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.)
Once you have seen the two documents, you can further drill down to retrieve other information provided by the service. You do this by creating a URI having the root URI followed by the resource that is to be acted upon. For example, Figure 3 shows the URI for retrieving the various categories.
|--------------------------Service Root URI------------------|--Resource Path-----|
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.
|--------------------------Service Root URI------------------|--Resource Path-----|
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.
|--------------------------Service Root URI------------------|-----Resource Path-----|
Resource path for accessing Products of Category “1”
The resource path shown in Figure 5 is possible since there is a Navigation Property Products that exists on the Category entity Type (as seen in Figure 2) referring to the relevant products of a Category.
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.
|-------------------------Service Root URI-------------------|-----Resource Path-----|----Query Option------|
Example of a query string
In this case, the total number (count) of products in Category 1 is also included in the returned set. (Query Options are discussed in detail in the “OData Query Options” section.)
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.
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:
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 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: http://services.odata.org/V2/%28S%28xuh52ptttgitgrkbtjzk1o31%29%29/OData/OData.svc/Categories.
The response in this case (in condensed form) is shown in 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.
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.
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.
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).
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.
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"?>
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).
Response header for successful insertion
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:
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).
<d:Name>Books and Ebooks</d:Name>
Upon successful update, the response body is empty. A success code 204 is displayed. However, it also says No Content.
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.
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.)
Here are the query options:
- $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.
Specifying a format
In this case, the results are shown in JSON format (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.
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'
Filter option based on ProductName
In this case, you get the details of the product Côte de Blaye as shown in 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'
Fetching a product name containing an apostrophe
If you want all products that have a unit price greater than 50, add the query option in Figure 22 after the base URI and resource path.
…..Products?$filter=UnitPrice gt 50
Finding products with a unit price greater than 50
To retrieve all products having unit prices between 10 and 65 (i.e., a range), use the string shown in Figure 23.
…..Products?$filter=UnitPrice ge 10 and UnitPrice le 65
Finding products within a price range
In addition, you can also use the $filter to display all the products that have names beginning with a particular letter. For example, fetch all products that have names starting from S. Figure 24 shows the corresponding query string.
Finding Products starting with the letter S
You can also use the filter option to specify selection criteria based on multiple properties. An example of this is shown in Figure 25.
……..Products?$filter=UnitPrice gt 50 and Discontinued eq ‘false’
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.
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.
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.
Selecting the property ProductName
If more than one property is required, the desired properties that are to be included in the response body are specified using commas. Figure 29 is an example.
Selecting more than one property
In this case, you have the properties ProductName and the Price in the result set.
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
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).
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.
Skip 10 entries
This query option may be used in conjunction with the $top option. For example, the following allows you to get the next 10 after skipping the first 20 entries (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).
Getting Value of entries in resource path
The string in Figure 34 returns the total number of product entries.
Figure 35 shows another example.
Getting all Products in Category 1
In this case, the total number of products that pertain to Category 1 is printed.
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.
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).
Total count of entries within the response body
This response body shows all the products as well as the total count of the products in the feed, as shown in Figure 38.
Response body with count value
Figure 39 shows another example.
Total product number printed with first six products
In this case, the system returns the first six products in the result set. However, along with it, the total number of products is also printed. If any filter option is included in the URI, the filter is first applied and then the total entries are computed and printed.
- $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 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:
Similar to Open SQL Statement having the form:
SELECT ($select) FROM EntitySet
ORDER BY ($orderby)
UP TO ($top) ROWS
Similarities between GET URIs and Open SQL select statements