Recently, I wanted to create a plunk (Plunker) where I needed to simulate an OData scenario that includes data update in an SAPUI5 app. This normally needs a backend server which would receive the OData request and send back a response.

Now, this is a bit tricky. Finding such a backend system open to public is not possible as far as I can see and setting up one for the sake of a temporary requirement is not a trivial task.

Here, a very useful component in the SAPUI5/OpenUI5 library comes to the help: sap.ui.core.util.MockServer. Well, as the component name suggests, this is a mock server that simulates server capabilities around HTTP requests.

So, here are the elements I will prepare for my plunk:

  1. A simple OpenUI5 app: A view, its controller, Component.js and index.html
  2. A simple EDMX (metadata) file to define the data model
  3. A JSON file for mock data
  4. A JavaScript file to implement a module based on the SAPUI5 MockServer component

Implementing the above also provides a simple SAPUI5 app template which you can use to demonstrate app behaviour in an isolated context and share your code.

Data Model

Let’s start with the data model. To keep it simple, I include only one basic entity in my metadata.xml file, i.e. Order.


Listing 1     Content of the metadata.xml file

Now, let’s create the JSON file that contains the mock data. Again, simply a couple of objects would be sufficient for the purpose:

 [ {   "OrderId": "ORDER01",   "OrderDate": "/Date(1245318362000)/",   "Status": "P",   "CustomerName": "Joe Blogs",   "CustomerAddressStreet": "1 Green Street",   "CustomerAddressPostcode": "SW1 1AA",   "CustomerAddressCountry": "United Kingdom",   "__metadata": {       "uri": "Orders('ORDER01')",       "type": "odataupdinbatch_srv.Order"    } }, {   "OrderId": "ORDER02",   "OrderDate": "/Date(1265318382000)/",   "Status": "C",   "CustomerName": "Jane Blogs",   "CustomerAddressStreet": "1 Blue Street",   "CustomerAddressPostcode": "KT2 2BB",   "CustomerAddressCountry": "United Kingdom",   "__metadata": {       "uri": "Orders('ORDER02')",       "type": "odataupdinbatch_srv.Order"    } } ] 

Listing 2     Content of the Orders.json file

Application View & Controller

As we now know what data our app will be handling, let’s create the only view of our app:


Listing 3     Content of the App.view.xml file

And we need a controller for the view:

 sap.ui.define([   "sap/ui/core/mvc/Controller",   "sap/ui/model/json/JSONModel" ], function(Controller, JSONModel) {   "use strict";   return Controller.extend("ss.ui5.problem.odataupdinbatch.App", {     onInit: function() {       this._oODataModel = this.getOwnerComponent().getModel();       this._oResourceBundle = this.getOwnerComponent().getModel("i18n").getResourceBundle();       var oViewModel = new JSONModel({         busy: false,         delay: 0       });       this.getView().setModel(oViewModel, "appView");       this._oViewModel = this.getView().getModel("appView");       this.getOwnerComponent().oWhenMetadataIsLoaded.then(this._doBinding.bind(this));     },     _doBinding: function() {       var sPath = "/" + this._oODataModel.createKey("Orders", {         OrderId: "ORDER01"       });       this.getView().bindElement(sPath);     },     onSave: function() {       this._oODataModel.attachEventOnce("batchRequestCompleted", this.onBatchRequestCompleted);       this._oODataModel.attachEventOnce("batchRequestFailed", this.onBatchRequestFailed);       this._oODataModel.submitChanges();     },     onBatchRequestCompleted: function(oData) {       debugger;     },     onBatchRequestFailed: function(oData) {       debugger;     }   }); }); 

Listing 4     Content of the App.controller.js file


Because I implement my apps as components, I need a Component.js file. As I work with an older SAPUI5 version, I include the app config/metadata in this file rather than the new way of doing it, i.e. via a descriptor file (manifest.json).

 sap.ui.define([   "sap/ui/core/UIComponent",   "sap/ui/model/odata/v2/ODataModel",   "sap/ui/model/resource/ResourceModel" ], function(UIComponent, ODataModel, ResourceModel) {   "use strict";   return UIComponent.extend("ss.ui5.problem.odataupdinbatch.Component", {     metadata: {       "version": "1.0.0",       "includes": [],       "rootView": {         "viewName": "ss.ui5.problem.odataupdinbatch.App",         "type": "XML",         "id": "app"       },       "dependencies": {         "libs": ["sap.ui.core", "sap.m", "sap.ui.layout"]       },       "config": {         "i18nBundle": "ss.ui5.problem.odataupdinbatch",         "serviceUrl": "/here/goes/your/serviceurl/",         "icon": "",         "favIcon": "",         "phone": "",         "phone@2": "",         "tablet": "",         "tablet@2": ""       }     },     init: function() {       var oCore = sap.ui.getCore();       var mConfig = this.getMetadata().getConfig();       var oConfig = {         disableHeadRequestForToken: true,         useBatch: true,         defaultOperationMode: "Client"       };       var oModel = new ODataModel(mConfig.serviceUrl, oConfig);       if (oModel.isBindingModeSupported(sap.ui.model.BindingMode.TwoWay)) { // true         oModel.setDefaultBindingMode(sap.ui.model.BindingMode.TwoWay);       }       this.setModel(oModel);       this._createMetadataPromise(oModel);       // set the i18n model       var oResourceModel = new ResourceModel({         "bundleName": mConfig.i18nBundle       });       this.setModel(oResourceModel, "i18n");       // call the base component's init function       UIComponent.prototype.init.apply(this, arguments);       // create the views based on the url/hash       //this.getRouter().initialize();     },     destroy: function() {       this.getModel().destroy();       this.getModel("i18n").destroy();       // call the base component's destroy function       UIComponent.prototype.destroy.apply(this, arguments);     },     _createMetadataPromise: function(oModel) {       this.oWhenMetadataIsLoaded = new Promise(function(fnResolve, fnReject) {          oModel.attachEventOnce("metadataLoaded", fnResolve);         oModel.attachEventOnce("metadataFailed", fnReject);       });     }   }); }); 

Listing 5     Content of the Component.js file

In this Component.js file, I define an OData model for my application using the SAPUI5/OpenUI5 component sap.ui.model.odata.v2.ODataModel. Here, I configure the model to use:

  • Two-Way Binding
  • $batch requests
  • GET request for fetching the the service document (and thus CSRF-token)
  • Client side mechanisms for operations like sorting and filtering

Mockserver Implementation

Now, comes the star of the show: mockserver.js. This module will utilise the MockServer component to implement server-like capabilities like responding an HTTP request. The code below is adapted from the template which SAP Web IDE provides when you create an SAPUI5 app from a template.

First, let me provide the code:

 sap.ui.define([   "sap/ui/core/util/MockServer" ], function(MockServer) {   "use strict";   var oMockServer,   _sAppModulePath = "ss/ui5/problem/odataupdinbatch/",   _sJsonFilesModulePath = _sAppModulePath ,   _sMetadataUrl = _sAppModulePath + "metadata",   _sMainDataSourceUrl = "/here/goes/your/serviceurl/";   return {   /**   * Initializes the mock server.   * You can configure the delay with the URL parameter "serverDelay".   * The local mock data in this folder is returned instead of the real data for testing.   * @public   */        init: function() {             var oUriParameters =,             sJsonFilesUrl =,             sEntity = "Orders",             sErrorParam = oUriParameters.get("errorType"),             iErrorCode = sErrorParam === "badRequest" ? 400 : 500,             sMetadataUrl =, ".xml");        oMockServer = new MockServer({             rootUri: _sMainDataSourceUrl        });        // configure mock server with a delay of 1s        MockServer.config({             autoRespond: true,             autoRespondAfter: (oUriParameters.get("serverDelay") || 1000)        });        oMockServer.simulate(sMetadataUrl, {             sMockdataBaseUrl: sJsonFilesUrl,             bGenerateMissingMockData: true        });        var aRequests = oMockServer.getRequests();        aRequests.push({             method: "MERGE",             path: new RegExp("(.*)Order(.*)"),             response: function(oXhr, sUrlParams) {             debugger;   "Mock Server: Incoming request for order");             var oResponse = {                  data: {},                  headers: {                       "Content-Type": "application/json;charset=utf-8",                       "DataServiceVersion": "1.0"                  },                  status: "204",                  statusText: "No Content"             };             oXhr.respond(oResponse.status, oResponse.headers, JSON.stringify({ d: }));             }        });        oMockServer.setRequests(aRequests);        var fnResponse = function(iErrCode, sMessage, aRequest) {             aRequest.response = function(oXhr) {                  oXhr.respond(iErrCode, {                       "Content-Type": "text/plain;charset=utf-8"                  }, sMessage);             };        };        // handling the metadata error test        if (oUriParameters.get("metadataError")) {             aRequests.forEach(function(aEntry) {                  if (aEntry.path.toString().indexOf("$metadata") > -1) {                       fnResponse(500, "metadata Error", aEntry);                  }             });        }        // Handling request errors        if (sErrorParam) {             aRequests.forEach(function(aEntry) {                  if (aEntry.path.toString().indexOf(sEntity) > -1) {                       fnResponse(iErrorCode, sErrorParam, aEntry);                  }             });        }        oMockServer.start();"Running the app with mock data");        },   /**   * @public returns the mockserver of the app, should be used in integration tests   * @returns {sap.ui.core.util.MockServer} the mockserver instance   */        getMockServer: function() {             return oMockServer;        }   }; }); 

Listing 6     Content of the mockserver.js file

Here, the adaptation of the module for my requirements happens in lines between 46 and 63. I add a definition for how the mock server should respond to a MERGE request (by default, SAPUI5 sends a MERGE request for an entity update) when an entity is specified with the path that conforms the given regular expression. This may need to be refined further in case the mock server is meant to handle more request types, e.g. the path given here would be problematic if there were another entity type such as OrderShipment.

As I would like to simulate an SAP Gateway server response, I set the response to have the HTTP status 204, the status text “No content” and return no data in the payload. This is how SAP Gateway responds to this kind of a request.


Now, the last piece of our coding elements: index.html:

               Order Management               

Listing 7     Content of the index.html file

Here, in index.html:

  • I refer to a specific OpenUI5 version, i.e. 1.38.7, in the bootstrap
  • When initialising the component, the MockServer component is called to be loaded and initialised so that it can receive the OData requests.
  • I have been preparing these files for Plunker, the file structure is flat and all the files are in the same folder. This is reflected in the module paths and the root path.


So, what does the app do:

  • It renders a view which displays a number of fields for the order that will be picked up from the mock data file Orders.json and with the ID ORDER01.
  • When a field content is changed, the ODataModel includes an update request to the to-be-sent $batch request. The ODataModel also includes other requests as required into the same $batch request.
  • When the Save button is clicked, the app calls the submitChanges() method to send the OData $batch request.
  • The response from the server is handled by the attached event handles for the events batchRequestCompleted and batchRequestFailed

Here is my Plunker template including all the files above:

For more information on the MockServer component, you can check the section in OpenUI5 Developer Guide: OpenUI5 SDK – Demo Kit

New NetWeaver Information at

Very Helpfull

User Rating: Be the first one !