I'm toying around with IBM worklight, and am trying to create an adapter to feed some data in from the Google places API.
I want to call this URL :
https://maps.googleapis.com/maps/api/place/search/json?key=AIzaSyCTlPms1pvhzeoRrBao5qW-DJMI_CWcbAM&location=52.0700,1.1400&radius=10000&sensor=false&name=coffee
Executing this URL works fine in a browser, and displays some nice JSON that I'm trying to obtain via Worklight.
The Worklight adapters are created in Javascript, this is what I have so far :
function getCoffeeHouses() {
var input = {
method : 'get',
returnedContentType : 'json',
path : 'maps/api/place/search/json',
parameters : {
'key' : 'AIzaSyCTlPms1pvhzeoRrBao5qW-DJMI_CWcbAM',
'location' : '52.0700,1.1400',
'radius' : '10000',
'sensor' : 'false',
'name' : 'coffee'
}
};
var response = WL.Server.invokeHttp(input);
// Extract latitude and longitude from the response.
var type = typeof response;
if ("object" == type) {
if (true == response["isSuccessful"]) {
// Return JSON object with lat and lng.
return response["results"];
}
else {
// Returning null. Web request was not successful.
return null;
}
}
else {
// Returning null. Response is not an object.
return null;
}
}
And this is the result that I get in the console, when I test the above:
Failed to parse JSON string
<!DOCTYPE html>
<html lang=en>
<meta charset=utf-8>
<meta name=viewport content="initial-scale=1, minimum-scale=1, width=device-width">
<title>Error 404 (Not Found)!!1</title>
<style>
*{margin:0;padding:0}html,code{font:15px/22px arial,sans-serif}html{background:#fff;color:#222;padding:15px}body{margin:7% auto 0;max-width:390px;min-height:180px;padding:30px 0 15px}* > body{background:url(//www.google.com/images/errors/robot.png) 100% 5px no-repeat;padding-right:205px}p{margin:11px 0 22px;overflow:hidden}ins{color:#777;text-decoration:none}a img{border:0}#media screen and (max-width:772px){body{background:none;margin-top:0;max-width:none;padding-right:0}}
</style>
<a href=//www.google.com/><img src=//www.google.com/images/errors/logo_sm.gif alt=Google></a>
<p><b>404.</b> <ins>That’s an error.</ins>
<p>The requested URL <code>/maps/api/place/search/json?key=AIzaSyCTlPms1pvhzeoRrBao5qW-DJMI_CWcbAM&location=52.0700%2C1.1400&radius=10000&sensor=false&name=coffee</code> was not found on this server. <ins>That’s all we know.</ins>
Caused by: java.io.IOException: Unexpected character '<' on line 1, column 1
[2012-07-23 11:08:57] An error occurred while invoking procedure CoffeeFinder/getCoffeeHouses parameters: {
"arr": [
]
}
null
Caused by: null
I think, that this is probably caused because the adapter is requesting as HTTP, whereas it should be using HTTPS.
If I alter the request to use HTTP in a browser, it displays similar results.
Question : Can I make an HTTPS request by altering the above Javascript, or am I misunderstanding worklight adapters?
Looks like googleapis will not work if you don't specify Host header inside of your request.
After adding it everything works as it should:
This is adapters's XML section
<connectivity>
<connectionPolicy xsi:type="http:HTTPConnectionPolicyType">
<protocol>https</protocol>
<domain>maps.googleapis.com</domain>
<port>443</port>
</connectionPolicy>
<loadConstraints maxConcurrentConnectionsPerNode="2" />
</connectivity>
This is adapter's JS:
function doGet() {
var input = {
method : 'get',
returnedContentType : 'json',
path : 'maps/api/place/search/json',
headers: {
Host: 'maps.googleapis.com'
},
parameters : {
'key' : 'AIzaSyCTlPms1pvhzeoRrBao5qW-DJMI_CWcbAM',
'location' : '52.0700,1.1400',
'radius' : '10000',
'sensor' : 'false',
'name' : 'coffee'
}
};
var response = WL.Server.invokeHttp(input);
return response;
}
in your adapter there is also an {ADAPTER NAME}.xml
In it, under connectivity under connectionPolicy, there is the protocol.
did you change it to https and deploy?
Related
I'm using the binance API to get the prices of usdt. The API works on postman but it doesn't work on google script.
function fetchCryptoPricesFromApi() {
const data = {
"page": 1,
"rows": 10,
"payTypes": [],
"asset": "USDT",
"tradeType": "SELL",
"fiat": "LKR",
"publisherType": null,
"transAmount": "2600"
}
const payload = JSON.stringify(data)
const options = {
"method" : "POST",
"contentType" : "application/json",
"payload" : payload
}
let response;
try {
response = UrlFetchApp.fetch('https://p2p.binance.com/bapi/c2c/v2/friendly/c2c/adv/search', options);
} catch (error) {
console.log('Oops Error, ', error);
return
}
const prices = JSON.parse(response)['data'];
console.log(prices)
}
I get the following error when executing this,
Oops Error, { [Exception: Request failed for https://p2p.binance.com returned code 403. Truncated server response: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML><HEAD><META HTTP-EQUIV="Content-Type" ... (use muteHttpExceptions option to examine full response)] name: 'Exception' }
I tried waiting some time as well.
From your showing error message, I confirmed the status code 403. Ref In this case, it is considered that the site cannot be directly accessed from the Google side. I think that the reason for your issue is due to this.
In this case, as a workaround, I would like to propose access to the URL without directly running the script with the script editor. When I tested this workaround, I confirmed that the value could be returned.
In this workaround, the following flow is used.
Put the custom function of =fetchCryptoPricesFromApi() to a cell.
Retrieve the values from the API.
Retrieve the values from the cell.
Parse the value as JSON data.
The sample script of this workaround is as follows.
Sample script:
In this workaround, I use Google Spreadsheet. So please create a new Google Spreadsheet and open the script editor of Google Spreadsheet. And, copy and paste the following script. And, run main() function with the script editor.
function fetchCryptoPricesFromApi() {
const data = {
"page": 1,
"rows": 10,
"payTypes": [],
"asset": "USDT",
"tradeType": "SELL",
"fiat": "LKR",
"publisherType": null,
"transAmount": "2600"
}
const payload = JSON.stringify(data)
const options = {
"method": "POST",
"contentType": "application/json",
"payload": payload
}
const response = UrlFetchApp.fetch('https://p2p.binance.com/bapi/c2c/v2/friendly/c2c/adv/search', options);
return response.getContentText();
}
// Please run this function.
function main() {
const sheet = SpreadsheetApp.getActiveSheet();
const range = sheet.getRange("A1");
range.setFormula("=fetchCryptoPricesFromApi()");
SpreadsheetApp.flush();
const value = range.getValue();
range.clearContent();
const prices = JSON.parse(value)['data'];
console.log(prices)
}
A web page (front) is calling a service which send a PDF stream as a response :
Here is the front code :
'click .btn': function (event) {
/.../
event.preventDefault();
Http.call(params, (err, res) => { // callback
if (err) console.log(err); // nothing
console.log({ res }); // print below result
const blob = new Blob(
[res.content],
{ type: `${res.headers['content-type']};base64` }
);
saveAs(blob, res.headers['content-disposition'].slice(21));
});
}
Here is the response from the server ( console.log(res) ) : { res : Object } printed in the console.
content: "%PDF-1.4↵1 0 obj↵<<↵/Title (��)↵/Creator (��)↵/Prod ..... lot of characters....%"
data: null,
statusCode: 200,
headers: {
connection: "close",
content-disposition: "attachment; filename=myDoc.pdf"
content-type: "application/pdf",
date: "date",
transfer-encoding: "chunked",
x-powered-by: "Express"
}
However, the PDF is downloaded with no content, it's full blank like corrupted ( But I can see the content in the string ). It works well with the CSV routes ( I send a csv as a stream and download it with the same method and I got the data).
I think there is something with the format %PDF ...% but I didn't manage to find something.
Note : With postman, it works, my PDF is saved, the page is not blank, I got the data. So there is something in the front I am not doing right.
I also tried with :
const fileURL = URL.createObjectURL(blob);
window.open(fileURL); // instead of saveAs
but the result is the same ( but in another tab instead of saved PDF ) blank page.
Any ideas ?
You probably forgot to specify the response type in your inital backend call - from the example you posted "arraybuffer" would be the correct one here, you can check all types here.
I have used filefield xtype to upload a file and calling a web service.
For my application, to handle success and failure block, i am using a variable 'success' such that if the value is true, it goes to success block and if the value is false, it goes to failure block.
If i set the value success=false, it comes to failure block but, when i decode the response it gives me "permission denied" error only in IE. In Chrome, we get the expected output even if it enters the failure block.
Since i am getting this error, i am handling this failure case in success block itself.
Below is the code snippet:
form.submit({
headers : {
"Accept" : "application/json; charset=utf-8"
},
url : 'calling a web service',
waitMsg : 'Loading... Please Wait...',
success : function (response, args) {
var jsonResp = Ext.decode(args.response.responseText);
if (jsonResp.exception) {
Ext.create('widget.uxNotification', {
title : 'Failed',
height : 150,
width : 350,
html : '<span style="text-align:center; display:block;color:red">' + jsonResp.R.MSG + '</span>'
}).show();
} else {
//actual code if success=true goes here
}
},
failure : function (response, args) {
var jsonResp = Ext.decode(args.response.responseText); //if i decode the response, i get permission denied
var msg = jsonResp.R.MSG || jsonResp.R.Message;
//R.MSG is undefined even if it is present in response and R.Message gives permission denied
Ext.Msg.alert(msg);
}
});
json Response for success case:
{
"success":true,
"R":{
"MSG":"Success"
}
}
json Response for failure case:
{
"success":true,
"exception":true,
"R":{
"MSG":"Failure"
}
}
I am sending another parameter 'exception' in the response to handle this. So if exception is true then it's actually a failure case.
Is it a bug in ExtJS library? Since i have seen the comments written in library file, stating that there is a problem with iframe.
Can anyone help me on how to solve this IE issue?
I am trying to set up a basic example that sends a custom keen.io event via js. At the moment I do not need any presentation, visualisation, etc.
Here is the example that I created from another one I found online. I attempted several variations, and all of them work in Google Chrome, but none of them works in Firefox (38.0 for Ubuntu canonical - 1.0).
if I add to the head the inline script (!function(a,b){a("Keen"...) as it is proposed in the manual, I do not get any errors in FF, but it seems that addEvent never gets called and it produces no response, "err" nor "res".
if I include the library from the CDN (d26b395fwzu5fz.cloudfront.net/3.2.4/keen.min.js), I get an error when the page is loaded:
ReferenceError: Keen is not defined
var keenClient = new Keen({
If I download the js file and serve it locally, after the button is clicked, I get the following error response:
Error: Request failed
err = new Error(is_err ? res.body.message : 'Unknown error occurred');
All of these attempts work from Chrome, but I need this to work from other browsers too.
I received a response from keen.io team. It turned out that Adblock Plus is interfering with the script. After I disabled it everything works in FF as in Chrome.
After some investigation in turned out that request to http://api.keen.io was blocked by "EasyPrivacy" filter of ABP with these filter rules: keen.io^$third-party,domain=~keen.github.io|~keen.io
So, sending a request to an "in-between" server (a proxy) seems to be the only solution that I can see.
We have a bit specific use case - a need to track a static site and also an available access to a rails api server, but the solution we ended up using may come useful to someone.
error.html
<html>
<head>
<title>Error</title>
<script src="/js/vendor/jquery-1.11.2.min.js"></script>
<script src="/js/notification.js"></script>
<script type="text/javascript">
$(document).on('ready', function () {
try {
$.get(document.URL).complete(function (xhr, textStatus) {
var code = xhr.status;
if (code == 200) {
var codeFromPath = window.location.pathname.split('/').reverse()[0].split('.')[0];
if (['400', '403', '404', '405', '414', '416', '500', '501', '502', '503', '504'].indexOf(codeFromPath) > -1) {
code = codeFromPath;
}
}
Notification.send(code);
});
}
catch (error) {
Notification.send('error.html', error);
}
});
</script>
</head>
<body>
There was an error. Site Administrators were notified.
</body>
</html>
notification.js
var Notification = (function () {
var endpoint = 'http://my-rails-server-com/notice';
function send(type, jsData) {
try {
if (jsData == undefined) {
jsData = {};
}
$.post(endpoint, clientData(type, jsData));
}
catch (error) {
}
}
// private
function clientData(type, jsData) {
return {
data: {
type: type,
jsErrorData: jsData,
innerHeight: window.innerHeight,
innerWidth: window.innerWidth,
pageXOffset: window.pageXOffset,
pageYOffset: window.pageYOffset,
status: status,
navigator: {
appCodeName: navigator.appCodeName,
appName: navigator.appName,
appVersion: navigator.appVersion,
cookieEnabled: navigator.cookieEnabled,
language: navigator.language,
onLine: navigator.onLine,
platform: navigator.platform,
product: navigator.product,
userAgent: navigator.userAgent
},
history: {
length: history.length
},
document: {
documentMode: document.documentMode,
documentURI: document.documentURI,
domain: document.domain,
referrer: document.referrer,
title: document.title,
URL: document.URL
},
screen: {
width: screen.width,
height: screen.height,
availWidth: screen.availWidth,
availHeight: screen.availHeight,
colorDepth: screen.colorDepth,
pixelDepth: screen.pixelDepth
},
location: {
hash: window.location.hash,
host: window.location.host,
hostname: window.location.hostname,
href: window.location.href,
origin: window.location.origin,
pathname: window.location.pathname,
port: window.location.port,
protocol: window.location.protocol,
search: window.location.search
}
}
}
}
return {
send: send
}
}());
example of sending notification manually from js code:
try {
// some code that may produce an error
}
catch (error) {
Notification.send('name of keen collection', error);
}
rails
# gemfile
gem 'keen'
#routes
resource :notice, only: :create
#controller
class NoticesController < ApplicationController
def create
# response to Keen.publish does not include an ID of the newly added notification, so we add an identifier
# that we can use later to easily track down the exact notification on keen
data = params['data'].merge('id' => Time.now.to_i)
Keen.publish(data['type'], data) unless dev?(data)
# we send part of the payload to a company chat, channel depends on wheter the origin of exception is in dev or production
ChatNotifier.notify(data, dev?(data)) unless data['type'] == '404'
render json: nil, status: :ok
end
private
def dev?(data)
%w(site local).include?(data['location']['origin'].split('.').last)
end
end
I'm working on cloud code that pings eBay, returns JSON, parses it, and stores the top two categories into an array. The parameters sent to eBay are based on what a user types into itemSearch bar the iOS app. When I attempt to send a query like "iPhone", it gives this error:
TypeError: Cannot read property 'findItemsByKeywordsResponse' of undefined
at Object.Parse.Cloud.httpRequest.success (main.js:37:15)
at Object.<anonymous> (<anonymous>:565:19) (Code: 141, Version: 1.2.18)
Here is my objective-c code:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if (sender != self.nextButton) return;
if (self.itemSearch.text.length > 0) {
[PFCloud callFunctionInBackground:#"eBayCategorySearch"
withParameters:#{#"item": self.itemSearch.text}
block:^(NSString *result, NSError *error) {
if (!error) {
NSLog(#"Successfully pinged eBay!");
}
}];
}
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
The cloud code (main.js) running on Parse:
Parse.Cloud.define("eBayCategorySearch", function(request, response) {
url = 'http://svcs.ebay.com/services/search/FindingService/v1';
Parse.Cloud.httpRequest({
url: url,
params: {
'OPERATION-NAME' : 'findItemsByKeywords',
'SERVICE-VERSION' : '1.12.0',
'SECURITY-APPNAME' : '*APP ID GOES HERE*',
'GLOBAL-ID' : 'EBAY-US',
'RESPONSE-DATA-FORMAT' : 'JSON',
'itemFilter(0).name=ListingType' : 'itemFilter(0).value=FixedPrice',
'keywords' : request.params.item,
// your other params
},
success: function (httpResponse) {
var response = JSON.parse(httpResponse.text)
// count number of times each unique primaryCategory shows up (based on categoryId), return top two (done with a for loop?)
var userCategories = {};
var data = httpResponse.data
data.findItemsByKeywordsResponse.searchResult[0].item.forEach(function(item)
{
var id = item.primaryCategory[0].categoryId;
if (userCategories[id]) userCategories[id]++;
else userCategories[id] = 1;
});
var top2 = Object.keys(userCategories).sort(function(a, b)
{return userCategories[b]-userCategories[a]; }).slice(0, 2);
console.log('Top two categories: ' + top2.join(', '));
response.success(httpResponse.data)
// if user has criteria info for one of the categories already, default to that, send to matchcenter
// if user has criteria for both categories, ask which one, default to selected categories criteria, send to matchcenter
// if user has no criteria for either category, redirect to criteriaViewController, save the criteria user inputs, send to matchcenter
// deal with success and respond to query
},
error: function (httpResponse) {
console.log('error!!!');
console.error('Request failed with response code ' + httpResponse.status);
}
});
});
The JSON usually looks like this when returned:
{
"findItemsByKeywordsResponse":[
{
"ack":[
"Success"
],
"version":[
"1.12.0"
],
"timestamp":[
"2014-03-26T18:29:40.583Z"
],
"searchResult":[
{
"#count":"100",
"item":[
{
"itemId":[
"151258132867"
],
"title":[
"Apple iPhone 4 - clean esn - Black (Verizon) Smartphone"
],
"globalId":[
"EBAY-US"
],
"primaryCategory":[
{
"categoryId":[
"9355"
],
"categoryName":[
"Cell Phones & Smartphones"
I don't think it's being returned properly, hence its inability to find "findItemsByKeywordsResponse". Is there a way I can print out the JSON being returned, to see whether I'm parsing the wrong thing?
You are parsing your response:
var response = JSON.parse(httpResponse.text)
But after that you don't use it. You work instead with httpResponse.data.
So try using your response object:
response.findItemsByKeywordsResponse.searchResult[0]......