Sharepoint - Combine REST query "GetItems" action with OData $filter parameter

It does not seem possible to specify $filter query option for /_api/web/lists/getbytitle(listtitle)/getItems(query) endpoint.

But the specified REST query parameters could be defined using plain CAML query:

  • $top=5 -> <RowLimit>5</RowLimit>
  • $filter=substringof('Orders',Title) -> <Where><Contains><FieldRef Name='Title'/><Value Type='Text'>Orders</Value></Contains></Where>

There is another approach that allows to specify CAML query via payload of request body instead of query string as demonstrated below:

function postJson(endpointUrl,payload,success,failure)
{
    $.ajax({
      type: "POST", 
      headers: { 
            "accept": "application/json;odata=verbose",
            "content-type": "application/json;odata=verbose",
            "X-RequestDigest": $("#__REQUESTDIGEST").val()
      }, 
      data: JSON.stringify(payload),
      url: endpointUrl, 
      success: success,
      failure: failure 
   });
}

function getListItems(listTitle, queryViewXml,success,failure)
{
   var queryPayload = { 
       'query':{ 
           '__metadata': { 'type': 'SP.CamlQuery' },
           'ViewXml': queryViewXml
        } 
   }; 
   var endpointUrl = _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/getbytitle('" + listTitle + "')/getitems";
   postJson(endpointUrl,queryPayload,
     function(data){
        success(data.d.results);    
     },failure);
}

Usage

getListItems('Tasks',"<View><Query><Where><Contains><FieldRef Name='Title'/><Value Type='Text'>Orders</Value></Contains></Where></Query><ViewFields><FieldRef Name='Title'/></ViewFields><RowLimit>1</RowLimit></View>",
  function(items){
      //print info  
      for(var i = 0; i < items.length; i++) {
          console.log(items[i].Title);   
      }
  },
  function(error){
     console.log(JSON.stringify(error)); 
  });

I will accept the answer by @vadim-gremyachev based on the statement;

It does not seem possible ...

And the suggestion to use only CAML.

This is actually what I do today and so I decided to write an additional answer to my own question, with the approach I'm already using (just with the query-as-body fix), where I combine view query with my own custom one. Example below is from real world code where I use Angular, and jQuery is not included. I have removed some parts, but the approach is simple; given three variables listId, viewId and an additional CAML query additinalQuery the example code will return a promise with data filtered by both view query and a custom one.

var apiUrl = _spPageContextInfo.webAbsoluteUrl + "/_api/";
var listUrl = apiUrl + "Web/Lists('" + listId + "')";
var viewUrl = listUrl + "/Views('" + viewId + "')";
var digest = angular.element(document.getElementById("__REQUESTDIGEST")).val();

return $http.get(viewUrl, {
  params: { 
    $select: "ViewFields,ViewQuery",
    $expand: "ViewFields"
  }
}).then(function(res) {
  return {
    query: res.data.ViewQuery,
    fields: res.data.ViewFields.SchemaXml
  };
}).then(function(res) {
  var query = res.query.match(/<where>(.*)<\/where>/i);
  query = query ? ("<And>" + query[1] + additionalQuery + "</And>") : additionalQuery;
  return "<View><Query><Where>" + query + "</Where></Query><ViewFields>" + res.fields + "</ViewFields></View>";
}).then(function(viewXml) {
  return $http.post(listUrl + "/GetItems", {
    query: {
      ViewXml: viewXml
    }
  }, {
    headers: {
      "X-RequestDigest": digest
    }
  });
});

Not only is the "combining" of CAML queries (as seen above) crude and ugly, it is also much more cumbersome to build (think about query lookup with $filter vs CAML).


If u Do want to mix the OData with CAML then I would suggest that First Make the CAML query and later attach the $filter as the filter operates at last and needs a set of Results which are mentioned in your query from which the filtering process would be performed and not vise versa. Well Its simple logic and I don't think I need to provide further explanation to this matter still if all the querying and filtering process is done by OData method only then it doesn't matter whether you mention $filter first and condition later as it itself identifies which operation needs to be performed first irrespective to order in which you specify it but since you are using two different methods it is your responsibility to order your operations in a just manner.

var params = $.param({
     $top: 5
});
params = params + '&@q=' + JSON.stringify(query);
var params1 = $.param({
     params + '$filter': "substringof('sdf',Title)"
});

Or how ever u wish but make sure that $filter remains after the query.
Thanks