Agora Analytics (BETA) Rest API does not work for route /analytics/call/lists route - analytics

When making a GET request (through Postman) at "https://api.agora.io/beta/analytics/call/lists" with query parameters:
appid (following the official documentation, i base64 encoded {Customer ID}:{Customer Secret} string)
start_ts (timestamp format e.g. 1627990383)
end_ts (timestamp format e.g. 1628163183)
When I make the request, i get a response with status 200 OK, but the response body is the following :
{
"code": 500,
"message": "Unknown error"
}
I set the headers as mentioned in the official documentation :
Has anyone got a legit response from this request? And what was his request construction?

I have the same problem. I asked the support what to do, this is what they answered me:
The analytics restful API you are trying to use is part of the
Enterprise support package and requires that for you to be able to use
them. We do have something in the works for cheaper analytics later
down on the line so if you do want to purchase a package for restful
APIs for analytics, please let us know and we can put you in contact
with a CSM.
I think this functionality is supported only in the Enterprise version of the package.

Related

Google API Request stopped working

I have an API that I use to get the events from multiple accounts. Recently the API stopped working and I am not able to figure out why.
Here is an example of my request: https://www.googleapis.com/calendar/v3/calendars/pub500.mankato%40gmail.com/events?key=myKey
The call returns a Google_Service_Exception - (400) Bad Request
From you question, I take it that you are managing authentication for calling APIs. Based on the information provided by Michael, I think you will find this GCP documentation for using API keys helpful:
https://cloud.google.com/docs/authentication/api-keys#api_key_restrictions
The answer to this question (is|was) to validate the error response message from the API and read it carefully. I also recommend rechecking API settings(Console), the API call and to check every single step if its use in any kind of framework. (Test against the API)
Google_Service_Exception - (400) Bad Request
seems to be invalid API credentials (API key)
Update after creating new API key:
"(403) The request did not specify any referer.
Please ensure that the client is sending referer
or use the API Console to remove the referer restrictions."
That means you have to specify a referer in your API call or go to your API console (where you created the new KEY) and remove the "referer restriction"

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.
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

What is the OAuth scope for the Google Translation API?

Surely someone else is using the API, I've looked and searched, I cannot seem to find the correct value to place for the scope parameter when authenticating:
I've looked at all these scope lists, nothing, tried the OAuth 2.0 playground, translation is not there.
oauth playground v1
oauth playground v2
oath supported scopes
auth scopes
Any clues welcomed, thank you.
Error message:
Error: invalid_request
Missing required parameter: scope
Learn more
Request Details
Update
User Ezra explained that OAuth2 authentication is not needed for the Translation API.
I got down this road by this path:
I was trying to make the sample code here work:
translation api sample code
And didn't have the apiclient.discovery module
from apiclient.discovery import build
I went off looking for that which landed me here to this quick-start configurator
which gave me an autogenerated translation api project here:
This starter project which is supposed to be tailored for Translation API includes a whole bunch of OAuth configuration and so I wound up asking the question because of the error mentioned here
exception calling translation api: <HttpError 400 when requesting https://www.googleapis.com/language/translate/v2?q=zebra&source=en&alt=json&target=fr&key=MYSECRETKEYWENTHERE returned "Bad Request">
The code I'm using to make said call which errors out in this way is:
service = build('translate', 'v2',
developerKey='MYSECRETKEYWENTHERE')
result = service.translations().list(
source='en',
target=lang,
q='zebra'
).execute()
If I make the same call directly that the error complains about, it works ok
https://www.googleapis.com/language/translate/v2?key=MYSECRETKEYWENTHERE&q=zebra&target=fr&alt=json&source=en
Updated Again
Okay, I removed all the OAuth code from the sample project and then ran it again and then finally noticed that I had a typo in my secret key... donk
Thanks for the answers!
.
Thank you
I think you are misunderstanding what OAuth scopes are for. You didn't list any of your code, so I'm going to explain some concepts, and hope that you can apply them to your situation.
OAuth Scopes explained:
The purpose of OAuth scopes is accessing information about authenticated users. The scopes are different for each applications, and determine what information about a user that an application is granted access to.
Concretely, an OAuth request with the scope parameter as
https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile
Would show the user a prompt similar to the following when logging in:
+ View basic information about your account
* View your name, public profile URL, and photo
* View your gender and birthdate
* View your country, language, and timezone
+ View your email address
* View the email address associated with your account
While one with only https://www.googleapis.com/auth/userinfo.email would show something like:
+ View your email address
* View the email address associated with your account
Translate API explained:
To use the Translate API, you don't have to have users authenticated with OAuth. You simply get an API Key, and provide that key in your request to the service.
The use of the Translate API is completely orthogonal to the use of OAuth.
As documented on the Translate API site, to translate something you simply make a request to
https://www.googleapis.com/language/translate/v2?parameters
with the appropriate parameters.
The parameters needed are, as listed in the documentation, the
API key. Use the key query parameter to identify your application.
Target language. Use the target query parameter to specify the language you want to translate into.
Source text string. Use the q query parameter to identify the string to translate.
Concretely, a request to translate the text "hello world" into German would be:
https://www.googleapis.com/language/translate/v2?key=INSERT-YOUR-KEY&source=en&target=de&q=Hello%20world
Look at the parameters specification to get an idea of what you have to supply.
What to do:
Look at the source of the Python example using the Translate API or look up the API library for the language you want to use.
You'll see in the examples that there is no mention of OAuth scopes, because it's not needed to authenticate against the Translate API service. You only need to provide your API key, and the text to be translated in your request to the service.
There may be API calls that require scope, but Translate is not one of them.
If there is some piece of information about a user that you need, you will have to look up the API and Scope needed to access that piece of information. You will then supply this information to the Translate API as necessary.
In case of 400:
If you are getting an error response, that's good, because the call to the service is working, even if it's not doing what you want.
In the case of a 400, the Translate API's response will give you a clue about your error in its response.
{
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "keyInvalid",
"message": "Bad Request"
}
],
"code": 400,
"message": "Bad Request"
}
}
The response above indicates that the key is invalid. You can request a new one (or find out your old one) through the Google API Console.
Summary:
OAuth scopes are used for requesting information about a user. You will have to identify the scope when authenticating the user, and you will have access to all information provided by those scopes.
The Translate API doesn't need a scope. You provide an API Key (and some other information) in your request, and it gives back the translation as documented.
If there is information about a user that you wish to translate, it must be done in two steps. First, collect the information by authenticating the user in the appropriate scope, and second by providing that information to the Translate API.
If you're getting a 400, the response will include some information you can use to debug the problem.
According to Google's documentation, you have to look at the documentation for your specific API.
Update as per this Google Group question:
"The Translate API (both v1 and v2) is an unauthenticated API, so you don't need to use OAuth with it. Instead, for v2, you should use an API key, which you can get here: http://code.google.com/apis/console"
For error message
Error: invalid_request
Missing required parameter: scope
You need to add scopes in your form
<input type="hidden" name="scope" value="https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo#email https://www.googleapis.com/auth/plus.me https://www.googleapis.com/auth/tasks https://www-opensocial.googleusercontent.com/api/people https://www.googleapis.com/auth/plus.login" />
Please refer spring social login with linkedin,facebook,twitter and google providers.

Force.com callout: Is there a way to get the full response from the target server

When calling a web service from Force.com, I am getting:
System.CalloutException: Web service callout failed: Unexpected
element. Parser was expecting element
'http://schemas.xmlsoap.org/soap/envelope/:Envelope' but found ':HTML'
The network guys at the other end has asked to see the full response that Salesforce is getting from their server.
Is there a way to achieve that? I have tried running with debug level 'Finest' from execute anonymous, but that yields the same little message with no further detail.
The message you are getting is because an error is generated as Saleforce is trying to parse the response is and it isn't logged unfortunately.
The parsing error is happening because instead of a SOAP message response you are getting an HTML page. This usually happens when you are accessing a service that is protected behind a firewall. Which means you may be able to see the service when browsing on your computer but remember that Salesforce is outside of your firewall and thus any communication by Salesforce to your service will be blocked.
Couple of ways to address this but this wiki topic from Salesforce best covers the options:
http://www.salesforce.com/us/developer/docs/api/Content/sforce_api_om_outboundmessaging_security.htm
The above is specific to outbound messaging but essentially the technology issues are the same.
Don't forget that Apex includes an HttpRequest Class that works as a lower layer than the SOAP APIs. You should be able to write up a test method that sends a hard-coded XML request to the server and dumps the HttpResponse so you can see it.
Adding my own best answer, based on some internet research:
You can use an external tool like Runscope as a webservice proxy to automatically forward requests and pass through responses and view the XML SOAP messages. This is not a native solution on SFDC but it does do the job.
https://www.runscope.com/
The issue is that Force.com is trying to parse a SOAP response that's actually just HTML. This happens sometimes when an error occurred server-side and the response is meant for a browser to display, rather than sending back an exception report via a properly formatted SOAP response.
If they can't figure out why they are not sending back a consumable SOAP response, then you can try using other tools (outside of Force.com) to make the same webservice call from your browser and then see what the HTML actually says on return.

How to check for an HTTP status code of 401?

In one of the answers that I have received here, I encountered a problem of not knowing how to pass automatically through "Google App Engines" my ID and a password to a website, on which I am a registered user and have an account. A suggestion was given to me to "check for an HTTP status code of 401, "authorization required", and provide the kind of HTTP authorization (basic, digest, whatever) that the site is asking for". I don't know how to check for status code. Can anyone, please, tell me how to do it?
+++++++++++++++++++++++++++++++++
Additional Information:
If I use this way in Google App Engine (fetching the url of my eBay summary page):
from google.appengine.api import urlfetch
url = "http://my.ebay.com/ws/eBayISAPI.dll?MyEbay&gbh=1&CurrentPage=MyeBaySummary&ssPageName=STRK:ME:LNLK"
result = urlfetch.fetch(url)
if result.status_code == 200:
print "content-type: text/plain"
print
print result.status_code
I always get "200" instead of "401"
In ordinary Python code, I'd probably use the lower-level httplib, e.g.:
import httplib
domains = 'google.com gmail.com appspot.com'.split()
for domain in domains:
conn = httplib.HTTPConnection(domain)
conn.request('GET', '/')
resp = conn.getresponse()
print 'Code %r from %r' % (resp.status, domain)
this will show you such codes as 301 (moved permanently) and 302 (moved temporarily); higher level libraries such as urllib2 would handle such things "behind the scenes" for you, which is handy but makes it harder for you to take control with simplicity (you'd have to install your own "url opener" objects, etc).
In App Engine, you're probably better off using urlfetch, which returns a response object with a status_code attribute. If that attribute is 401, it means that you need to repeat the fetch with the appropriate kind of authorization information in the headers.
However, App Engine now also supports urllib2, so if you're comfortable with using this higher level of abstraction you could delegate the work to it. See here for a tutorial on how to delegate basic authentication to urllib2, and here for a more general tutorial on how basic authentication works (I believe that understanding what's going on at the lower layer of abstraction helps you even if you're using the higher layer!-).
Unless I don't understand fully your question, you can grab the return code from the Response Object using the status_code property.
First, you'll have to issue a fetch() to the URL you want to test.
Most user-oriented sites don't use HTTP authentication, preferring instead to use cookie-based authentication, with HTML forms for signin. If you want to duplicate this in your own code, you need to make an HTTP POST request to the login URL for the application in question, and capture the cookie that's sent back, including that in all your future requests to authenticate yourself. Without more details about the specific site you're trying to authenticate against, it's difficult to be more specific.
You are not getting 401 because that site is not returning 401 but 200 always. Usually type of coding we do for websites is return 200 with a page saying "Please login..blah blah", if site returned anything other then 200 browser will not display the funky error msg.
So in short as i mentioned in other question, you need to look into login page, see what params it uses e.g login=xxx, password=yyy, post it to that page and you will have to manage the cookies too, that is where library like twill etc come into picture.

Resources