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

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.

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.

fyi, in SAP Gateway you can easily specify JSON or XML rendering via ...?$format=json or ...?$format=xml.
Default is xml.
So for metadata it would look like this:
...IWBEP/GWDEMO/ProductCollection/?$metadata&$format=json or ...IWBEP/GWDEMO/ProductCollectio/?$metadata&$format=xml

Related

What is the main reason to use headers for authentication tokens?

Just getting up to speed with authentication in angular . What I read a lot is the usage of headers to pass in a token like here: $http Auth Headers in AngularJS
My question is with passing in the token for every request to the backend what are the main reasons to use headers? Is this just for a cleaner solution or is it for performance?
Using headers for this isn't an Angular thing, many APIs use these so that for example a server can determine if the client should be allowed access quickly by examining only the headers and not the request body. This allows better separation of concerns between authentication and authorization functions, and payload processing on the server.
Upstream servers (of which there may be many layers) can add and remove headers and generally route and authorize your request more efficiently than if this data were to be in the request body.
Headers also keep authentication data out of URL request parameters which looks cleaner but also stops authentication data appearing in browser history etc.
One downside could be that if you are making requests through a network proxy there's a chance that the proxy may strip some headers especially if they're non-standard names.
If your connection to server is HTTPS then HTTP HEADERS are also encrypted. Where as query params are not.

Angularjs proceed with server call even if CORS does not allow a header value

I have an AngularJS application that talks to various java services. In the application I have a global http header setting in an http interceptor. That means all the service requests from my application will get the header values.
Now the trouble is that all the services CORS settings won't allow this header value. Couple of services does, while others does not. The service calls to the servers that do not support the header fails, since the http interceptor always puts the header values.
Is there a better way to design, in the above said case, so as to avoid the issue stated?
Appreciate any help...
How about adding a response interceptor, looking for a 401 status? If you get a 401, attempt to do the same request again without the headers this time. If this succeeds, 'whitelist' this domain to make all following requests without the headers that you don't want.
Otherwise, if you have a limited number of services that you are making calls to, maybe whitelist them inside of your request interceptor? This would probably be easier, but it's not very elegant.

Explain and example about 'get', 'delete', 'post', 'put', 'options', 'patch', 'head' method?

I'm writing a webservice. Could any one explain these above methods and give me some example about them? Thank for your help.
GET should be used to retrieve data with no other effect however you can use query params in url to post data using get but it is not a safe method.
The POST method is used to request that the origin server accept the entity enclosed in the request as a new subordinate of the resource identified by the Request-URI in the Request-Line.Generally used to create new entity.
The PUT method requests that the enclosed entity be stored under the supplied Request-URI. Generally used to update existing entity.
The PATCH method applies partial modifications to a resource
The DELETE method requests that the origin server delete the resource identified by the Request-URI.
The TRACE method echoes the received request so that a client can see what (if any) changes or additions have been made by intermediate servers.
The HTTP CONNECT method method starts two-way communications with the requested resource. It can be used to open a tunnel usually to facilitate SSL-encrypted communication (HTTPS) through an unencrypted HTTP proxy.
The OPTIONS method allows the client to determine the options and/or requirements associated with a resource, or the capabilities of a server, without implying a resource action or initiating a resource retrieval.
HEAD Retrieve all resources in a collection (header only) i.e. The HEAD method asks for a response identical to that of a GET request, but without the response body. This is useful for retrieving meta-information written in response headers, without having to transport the entire content.
From this_link you can get a detail about these methods.I have used these resources to write these methods in short.
You can also get simplified details on this wikipidea page.
This stackoverflow link is also very descriptive for http methods.
And for the implementation part this open source Django_rest_code at github can be a very good example to look at how to implement these Http methods in Django(Python).
They are actions from the perspective of the client:
GET refers to the client requesting information in the form of a URL request to the server ie loading a web page full of data.
POST is the client sending information back to the server ie clicking submit on a text field.
PUT is very similar to POST except that the information sent back to the server must be identified under the supplied Request-URI
DELETE requests that the server delete the entity that the client has designated ie removing a blog post from your blog tells the server to forget that information.
Those are the 4 main methods through which clients and servers communicate, thus how information on the server is displayed to and controlled by the client.

working with $http.post function

I want to save data using AngularJS and RestApi. I am sending an object in data parameter.
I tried both $http.post() direct method and $http() method , but non of these are working.
Always the error coming is "Method not allowed-405"
I am running on local machine.
Edit:
Eventually by doing some modifications like I specified "localhost:xxx" before the 'api/abc', now I am getting the error as "The requested resource does not support the http method 'POST'".
The reason is that the API you're using does not support POST requests to the URL you're trying to POST to
More info from http://www.checkupdown.com/status/E405.html below
All Web servers can be configured to allow or disallow any method. For example if a Web server is 'read-only' (no client can modify URL resources on the Web server), then it could be set up to disallow the PUT and DELETE methods. Similarly if there is no user input (all the Web pages are static), then the POST method could be disallowed. So 405 errors can arise because the Web server is not configured to take data from the client at all.

I want my AngularJS response interceptor to have access to the un-transformed response

I have an $http response interceptor, and I want to have access in the interceptor function to the raw response object--not the return value of transformResponse. Is this possible?
A little background: every response gets wrapped in a JSON object containing various metadata such as API version, detailed status information, etc. My transformResponse method strips out this wrapper and returns only the actual response payload, because I don't want the various controllers and services to be using this metadata.
However, I would like to have interceptors that do things like complain if the API version is incorrect, or handle various abnormal status conditions, so they need access to that metadata.

Resources