Skip to Content
Author's profile photo Wouter Lemaire

UI5 OData Requests with Promises


In complex UI5 projects you won’t be able to do everything by using bindings. You will probably need to do some OData requests manually in JavaScript. This can be due to several reasons, like in case you want to do a deep create (which is not supported with “createEntry”; ) or you want to manipulate data before showing. No matter what reason, you can’t avoid this ?

For these manual OData requests, we can use the default functions from the OData model in UI5 (nothing new here):

  • Read: for fetching data from the backend
  • Create: for sending new data to the backend
  • Update: for updating data on the backend
  • Remove: for deleting data on the backend

You can find all the details of these functions on the UI5 API Reference:

If you look at these functions, you’ll notice that they use a success and error callback functions to get a response from the backend. Nothing wrong with these functions, but I prefer working with promises… (read more about promises here: )

For that reason, I’ve created a wrapper that uses the OData model with Promises. I call it my “CoreService” object ?

OData with Promises

The “CoreService” object is based on the example from MDN web docs on using XMLHttpRequest:

( I don’t think that’s the original url, but I was not able to find it here:  )

It exists out of two parts:

  • One part for normal HTTP calls (that I copied from MDN)
  • Another part for OData calls

I’m going to focus on the “odata” function. The “odata” function in the “CoreService” returns a function for each CRUD operation which calls the internal “core.ajax” function. Each CRUD operation will call the “core.ajax” function but will use other parameters. What do the argument mean?

  • Type:
    • This defines the function that will be used in the UI5 ODataModel object (read,update,create or remove)
    • Will be different for each CRUD operation
  • url:
    • Url to the entity or entityset
  • Data:
    • JS object that needs to be send to the backend.
    • Will only be used for “post” and “put”
  • Parameters:

The “core.ajax” function will return a promise object that will be resolved in the success function and rejected in the error function.

The full function

odata: function (url) {
	var me = this;
	var core = {
		ajax: function (type, url, data, parameters) {
			var promise = new Promise(function (resolve, reject) {
				var args = [];
				var params = {};
				if (data) {
					params = parameters;
				params.success = function (result, response) {
						data: result,
						response: response
				params.error = function (error) {
				me.model[type].apply(me.model, args);
			return promise;

	return {
		'get': function (params) {
			return core.ajax('read', url, false, params);
		'post': function (data, params) {
			return core.ajax('create', url, data, params);
		'put': function (data, params) {
			return core.ajax('update', url, data, params);
		'delete': function (params) {
			return core.ajax('remove', url, false, params);

The full “CoreService” object:


How to use it

I would suggest to not use this “CoreService” object directly. What I mostly do is, I extend the “CoreService” object with a more precise object with a more meaningful name and only related functions in it. Let me explain this by applying on the Northwind Service as an example.

Create a second object that extends from “CoreService” (assuming CoreService” is added to the project) and give it the name “NorthwindService”. Now, we can use the “NorthwindService” to create more specific functions that apply on the Northwind service. For example, we can add a function “getSuppliers”. This function will call the get function of the “odata” function in the “CoreService” object for the entity “/Suppliers”, like this.

], function (CoreService,Sorter) {
	"use strict";

	var NorthwindService = CoreService.extend("be.wl.PromisesDemo.service.NorthwindService", {
		getSuppliers: function () {
			return this.odata("/Suppliers").get();
	return new NorthwindService();

We can also use predefined filters, like this:

Also look at the last line: “return new NorthwindService()” . This allows us to access one and the same instance of the “NorthwindService” from everywhere in the project.

getSuppliersWithFilter: function (aFilters) {
	var mParameters = {
	return this.odata("/Suppliers").get(mParameters);

Full code with more examples with filter, parameters and a create:
Later in this blog I have an example wilt a sorter and top.


One more thing before we can use the “NortwindService” in the project. We need to register the ODataModel to the “NortwindService”. This is something I do in the component:


Just call the “getSuppliers” function and fill the model with the response in the “then” function. You probably think why I don’t just use the OData model read function. It will show it’s benefit in a more complex example. Take for example that we want to do multiple requests in sequence like this:

Now, we’re ready to use the “NorthwindService” object in our project. I can for example use this in my Main controller like this:

  • Check if the supplier with ID 20 exists
    • This could fail but should not block the next request. For that reason, I’ve added a catch function after it.
  • Find out how many suppliers exists in the city “Redmond”
  • And finally get all the suppliers

After each request I show a message and update a progress bar to show the progress to the end-user:

It’s not the best example but it show how promises work. In this case you could also do this with Promise.All to run all request at the same time in a batch request, find more information about Promise.all here:

A more realistic example would be in case you create a new Supplier. Then we would need to know the next available ID. After creating the object, we should also update the list. This means we would have requests that need to wait for each other like this:

  • Get Max ID
  • Create new Supplier
  • Refresh supplier list

In code, it looks like this:

It could happen that the create fails, therefore I put a catch after the second then. In case the create fails, it will skip the second then and directly go to the catch. Everything after the first catch, will still be executed and update my list.

The function “getSupplierNextID” will get the Supplier with the highest ID by doing a $top = 1 and $orderby = ID in the OData request. In the result of the promise, it will add 1 to the highest found ID. We can assume that this ID will be unique. The function looks like this:


I have a full example of the code on GitHub:

You can import this in the SAP Web IDE and you’ll be able to try it out.

The result should look like this:

With the “add” button, you can generate a new Supplier.



I think this can help you managing your OData calls to the backend in complex and big projects.

It’s not that complex but very useful. I use it in many of my project and hope it can help others too.

Assigned Tags

      You must be Logged on to comment or reply to a post.
      Author's profile photo Nabheet Madan
      Nabheet Madan

      Very nice and useful!  CoreService is a cool name resonating with CDS:)

      For that reason, I’ve created a wrapper that uses the OData model with Promises. I call it my “CoreService” object ?

      Author's profile photo Pierre Dominique
      Pierre Dominique

      Hi Wouter,

      Interesting approach, I also use promises but I usually just encapsulate the code in a promise:

      return new Promise(function(resolve, reject) {, {
      		success: resolve,
      		error: function(oError) {



      Author's profile photo Naoto Amari
      Naoto Amari

      you do this to use the request as asynchronous but the function that call/return results as synchronous ???

      Author's profile photo Pierre Dominique
      Pierre Dominique

      The read method is asynchronous but I just prefer to use promises rather than callbacks.

      Author's profile photo Naoto Amari
      Naoto Amari

      and if you have to make some synchronous request how do you face that ?

      Author's profile photo Pierre Dominique
      Pierre Dominique

      Well you should probably not promisify a synchronous method but you could do it this way:

      function readFileSync(){
          return new Promise(resolve => {
      Author's profile photo Christoph John
      Christoph John


      would be great if you could also show on how such a core service can be implemented on top of the odata.v4 model.




      Author's profile photo Sakthi kumar
      Sakthi kumar

      Wouter LemaireVolker Buzek

      Mike Doyle

      Hi have two odata calls in two methods.

      function1(){ return new Promise(resolve,reject){{resolve(odataResponse)})}}

      function2(){ odata.Create(do something}


      from a different function, say function3, the call is like this:



      this.Promise =  this.function1();
      this.Promise.then( this.function2(),this );




      The problem is function1 is executed till odata read call. Then it jumps to function2, executes the create call and then executes the read call in function1.


      I want the read call to be executed first and then create call should happen. Can you please help??

      Author's profile photo Volker Buzek
      Volker Buzek

      cross-posting never really helps.

      but anyway, see my answer over at