Search code examples
angularjsodatabreezesap-gateway

Metadata queries to SAP Gateway from Breeze always return 406 Not Acceptable


I'm using BreezeJS 1.5.1 in an Angular 1.3 project to try to query a SAP Gateway server, which I'm assured implements OData. As the title says, every request to the $metadata service returns a 406 Not Acceptable response from the server.

<error xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
  <code>005056A509B11ED19BEB6513AA349DA5</code>
  <message xml:lang="en">
    The resource identified by the request is only capable of generating response entities which have content characteristics not acceptable according to the accept headers sent in the request
  </message>
</error>

I've tried initializing Breeze with several different adapter configurations ('OData', 'odata', 'WebApiOData'); this ensures that Breeze calls /$metadata on startup and not /Metadata, but does not fix the problem.

// breeze.config.initializeAdapterInstances({ dataService: 'OData' });
// breeze.config.initializeAdapterInstance('dataService', 'odata', true);
breeze.config.initializeAdapterInstances({ dataService: 'webapiodata' });

The Gateway server must always return XML for its metadata call (JSON metadata isn't available on SAP), and is having trouble with the Accept header of the request (Accept:application/json;odata.metadata=full). I can't find the right combination of headers that it will accept in Postman, other than those from calling the metadata service directly from Chrome (Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8) which works.

I've pointed the app at different services and even different Gateway instances, all with the same result. Have I missed a fundamental piece of config?

Edit 31/10/14

Per Ward's answer below, I intercepted the dataJS request (as suggested in the OData Ajax section at http://www.getbreezenow.com/documentation/controlling-ajax) and replaced the Accept headers for the $metadata call.

var oldClient = $window.OData.defaultHttpClient;
var myClient = {
  request: function (request, success, error) {
    $log.log('Intercepting OData request', request.requestUri);
    if (endsWith(request.requestUri, '$metadata')) {
      request.headers.Accept = 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8';
    }
    return oldClient.request(request, success, error);
  }
};
$window.OData.defaultHttpClient = myClient;

Of course there's a different problem now but this one is solved at least.


Solution

  • No, you haven't missed anything fundamental. However, SAP may have.

    As I recall, the result of an OData $metadata request is always XML, never JSON, and I believe that Breeze would have been happy to receive it as XML.

    Yes, the accept header does specify JSON even though the response won't be JSON. That's kind of sloppy on the part of Breeze (or the Data.js library Breeze delegates to ... not sure yet).

    But SAP should NOT have freaked out. The request's accept header is supposed to be advisory and the server should do the best it can to satisfy the request media-type format. It doesn't have to honor the requested format. In can return in a different format if need be.

    In this case, SAP should have just sent the metadata in XML. Apparently SAP is being persnickety.

    I'll look into this soon. Meanwhile, you can use a $http interceptor to patch the accept header yourself for this particular request.

    Back with more later.