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.
Showing results for 
Search instead for 
Did you mean: 

recently, around February 2019, I published a blog post about how to wrap any RESTful service into an OData service that can be used in an offline mobile use case. (Link to Part 1).

Now, after a couple of month, it's time for an update. We released a new version of our Mobile Back-end Tools which renders the explained approach obsolete. You can now achieve the same much easier.

The idea is that you can now map any RESTful services (it may also be another OData service) in a declarative way instead of a pure coding approach. In addition, the new approach is also offering a data-staging area.

This is how the solution architecture will look like:

In this picture the petstore API would be on the "REST" service on left-hand side. You see that also JCO/RFC connections can be called from your OData Service as well as JDBC to relational Databases. Some limitation apply when doing this through Cloud Connector, but if you deploy your OData service locally you can directly connect to a database.

To build such an architecture you need to define:

  • OData Service Model (via CSDL) using the Mobile Back-end tools

  • Provide a DB and define it's connection properties in the project

  • Define a destination (in this case the Swagger petstore API)

  • Annotate the Service Model with information about the petstore API - this is the "mapping")

Here's a complete example:
<?xml version="1.0" encoding="utf-8" ?>
<edmx:Edmx xmlns:edmx="" xmlns:edmx4="" xmlns:m="">
<edmx:Reference Uri="vocabularies/">
<edmx:Include Namespace="" Alias="SQL" />
<edmx:Reference Uri="vocabularies/">
<edmx:Include Namespace="" Alias="Cache" />
<edmx:Reference Uri="vocabularies/">
<edmx:Include Namespace="" Alias="HTTP" />
<edmx:DataServices m:DataServiceVersion="2.0">
<Schema Namespace="mbtdemo" xmlns="">
<EntityType Name="Pet">
<Annotation Term="Cache.RefreshBy" String="loadAll" />
<Annotation Term="HTTP.Destination" String="petstore" />
<Annotation Term="HTTP.Request" Qualifier="loadAll" String="GET /findByStatus?status=available">
<Annotation Term="HTTP.ResponseBody">
"id": "${entity.PetID}",
"name": "${entity.PetName}",
"status": "${entity.Status}"
<PropertyRef Name="PetID" />
<Property Name="PetName" Type="Edm.String" Nullable="true" MaxLength="200" />
<Property Name="PetID" Type="Edm.Int64" Nullable="false" />
<Property Name="Status" Type="Edm.String" Nullable="true" MaxLength="20" />
<Property Name="NewColumn" Type="Edm.Int32" Nullable="true" />
<EntityContainer Name="MbtdemoService" m:IsDefaultEntityContainer="true">
<Annotation Term="SQL.CacheDatabase" />
<Annotation Term="SQL.TrackChanges" />
<EntitySet Name="Pets" EntityType="mbtdemo.Pet" />


On the top you can see that I have added some vocabularies. This is to define the namespace of available annotations.

In the next step "Pet" entity was annotated with additional information:

  • Cache Refresh
    Here we define the how and when Pets should be loaded. "loadAll" says that this cache is updated for all entities of Pets. Other option would be "loadPartition" which enables to load the cache on a subset of Pets

  • Http.destination defines where the back-end is located. In our case it is

  • Http.Request is where it gets interested. Here we map the "loadAll" to a specific HTTP GET request GET /findByStatus?status=available

  • The http.ResponseBody is now mapping the API response to the Pet OData entity

Later in the service definition I also annotated the EntityContainer with:

  • SQL.CacheDatabase which enables the whole architecture

  • SQL.TrackChanges which enables OData Delta tracking

Prerequisite is for this to work is that you use a real database and do not use the InMemory DB of Mobile Back-end Tools.


Once you deploy this model into action you will be able to access the petstore through your own, cached back-end with the complete OData feature set like:

  • /Pets?$filter=PetName eq 'Dog'

I think this is a significant improvement of what I have done in Part 1 of this blog.


Have fun,