I am trying to program the following Curl command using Angular JS. I'm very new to AngularJS, so I may be missing something fundamental.To be specific, this is a mobile app, that is using the ionic framework (which uses Angular JS)
The curl command is this:
curl -X POST -d "username=xxxx&password=xxxx&action=login&view=console" http://myserver.com/zm/index.php?skin=xml
This works perfectly from command line.
In AngularJS, I have the following code:
angular.module('starter.controllers').controller('MonitorCtrl', function($ionicPlatform, $scope,$http)
{
console.log("***MAKING REQUEST");
//$http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
$http({
url:'http://myserver.com:9898/zm/index.php?skin=xml',
method:'post',
headers: {'Content-Type': 'application/x-www-form-urlencoded',
'Accept': '*/*',
},
transformRequest: function(obj) {
var str = [];
for(var p in obj)
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
var foo= str.join("&");
console.log ("****RETURNING "+foo);
return foo;
},
data: {username:'admin',
password:'xxxx',
action:'login',
view:'console'}
})
.success (function()
{console.log("****YAY");
})
.error(function(data, status, headers, config)
{
console.log("***OOPS "+status + " H: "+data);
});
});
When I run this code, I see a POST request going to my server (I am sniffing using httpry) and a 200OK being returned from the server with the required payload, but my success handler is not being called. The error handler is called with a status of 0
data should be a json. It depends on your server.
The common way to do it is is using properties on an object:
data: {username: 'xxxx', password: 'xxxx', action: 'login', view:'console'}
but if your server receives a string as an input then:
data: {key: 'username=xxxx&password=xxxx&action=login&view=console'}
Okay, I finally figured it all out
a) Amir popovich is right in that if I am dealing with XML, I need to 'transmogrify' (transform in a magical manner, for non Calvin and Hobbes readers) JSON to XML. The updated code I posted in my question does exactly that and works. But even after doing all that, my URL post (or get) was failing.
b) The entire darn CORS error I was facing was because I was running this app in a desktop browser (Safari) and it was Safari that was kicking out the response unless it had Accept Origin
c) When I deployed and tested the app on my phone, it worked like a charm. Don't ask me why
Related
I have a Node console app. In my app, I am trying to send some data to a third-party web service. I can successfully add data via the third-party web service via POSTMAN. In my Postman, I have a request setup like this:
Headers
api-key
{my key}
Content-Type
application/json
Body
{
"value": [
{
"#operation": "send",
"id":"1",
"name":"Hello",
"position": { "type": "Point", "coordinates": [90.000000, 0.000000] },
"tags":["january", "friends"]
}
]
}
I am now trying to replicate sending this data via Node. In an attempt to do this, I've written the following:
var ops = {
host: 'example.com',
path: '/api/upload?version=2',
method: 'POST',
headers: {
'api-key':'[my key]',
'Content-Type': 'application/json'
}
};
var r = https.request(ops, (res) => {
res.on('data', (d) => {
console.log(res.statusCode);
console.log(res.statusMessage);
});
});
var data = {
"value": [
req.body.record // req is passed in via express
]
};
console.log(data);
r.write(JSON.stringify(data));
r.end();
When the line console.log(data); is executed, I see the following in the console window:
{ value:
[ { '#operation': 'send',
id: '1',
name: 'Hello',
position: [Object],
tags:[Object]
} ] }
I'm not sure if this is a printing problem or an actual problem. Either way, my real issue is that when I send my request, I see the following also printed in the console window:
400
Bad Request
That data looks correct. I don't understand why I'm getting a 400 when I try to send from Node. Yet, it works just fine from Postman. Does it have to do with the quotation marks? I thought JSON.stringify handled that.
What am I doing wrong?
Honestly, unless you have a really good reason not to, just use something like request. It's way easier/cleaner than trying to build it yourself.
I can't answer any more specifically without knowing what the API you're talking to is expecting.
Also, in your res.on('data'), just console.log(req); and see what else is hiding in there; it might help you solve this with your existing code.
I would try
console.log(JSON.stringify(data));
Instead of
console.log(data);
and then decide what is wrong. This will give me full data in way it is sent to server.
Update:
I have made quick experiment and received following output:
{"value":[{"#operation":"send","id":"1","name":"Hello","position":{"type":"Point","coordinates":[90,0]},"tags":["january","friends"]}]}
The difference with the original JSON is in way how the coordinates are sent to the web service (as integers), which can be your problem.
Thanks for your help in advance.
I am trying to solve a problem that has bugged me pretty much for a few weeks now on and off (tried to solve it myself) and i am pretty stuck.
Basically i have a scenario where i am sending a data call to a identity server (Oauth 2.0) to retrieve a token that is then used in a API call.
To do this, i have setup two calls to the request module in NodeJS. The first call queries the server whilst the second call needs to use the token retrieved in the first to access the API i am accessing.
I cannot figure out how to get the variable from the first call (the token) to be accessible to the second request. I keep getting that it is undefined from the console.
This is the code i have tried so far. Relevant variable. Trying to take variable token through to request 2 as i need that token for the api call. I am running these requests in a function called dostuff.
var request = require('request');
var http = require('http');
var fs = require('fs');
var options = {
url: 'https://identitywebsite.com/connect/token',
headers: {'authorization' : 'basic <<KEY>>', 'Content-Type' : 'application/x-www-form-urlencoded'},
port: '443',
path: '/users',
method: 'POST',
body: 'grant_type=password&username=<<USERNAME>>&password=<<PASSWORD>>&scope=read+write'
var dostuff = function() {
request(options, function(error, response, body){
console.log("success");
Data = JSON.parse(body);
//console.log(xx);
global.token = data.access_token;
})
};
var options2 = {
url: 'https://apiwebsite.com',
headers: {'authorization' : 'Bearer ' + token, 'Content-Type' : 'application/json'},
port: '443',
path: '/users',
method: 'GET'
}
console.log(options2);
request(options2, function(error, response, apiresponse){
console.log("triggered");
console.log(" data success2");
apidata = JSON.parse(apiresponse);
console.log(apidata);
});
Well a few things you should do. One is use some promises. Also do your best to not use global variables.
Also you are missing a closing bracket on your first options.
Promises are really neat though, as you can do things like this.
do_something(options)
.then(function(my_data){
var options2 = {
url: 'https://apiwebsite.com',
headers: {'authorization' : 'Bearer ' + my_data, 'Content-Type' : 'application/json'},
port: '443',
path: '/users',
method: 'GET'
}
do_something_else(options2)
.then(function(my_other_data){
//do stuff with my_other_data
}
}
Use this library! It makes doing promises with requests really easy!
https://github.com/request/request-promise, you could also do this in bluebird which is my favorite of all the promise libraries, but it is slightly more complex.
Edit:
Since someone posted that this is off topic, which it isn't. I will go farther in depth of why this is not working the way you think it should. One of the reasons this is not working quite right is Node.JS is asynchronous.
What this means is your code is not waiting for your first request to finish before running your second request so you are not actually getting the token before your next request needs this.
One of the ways around this is to use promises like I said originally. There are plenty of libraries out there that force synchronicity. There is this library for example:
https://github.com/yortus/asyncawait
and many many more.
You could abstract this farther and call your first request from your second request as well to grab the API key and store it.
I am trying to access an API using AngularJS. I have checked the API functionality with the following node code. This rules out that the fault lies with
var http = require("http");
url = 'http://www.asterank.com/api/kepler?query={"PER":{"$lt":1.02595675,"$gt":0.67125}}&limit=10';
var request = http.get(url, function (response) {
var buffer = ""
response.on("data", function (chunk) {
buffer += chunk;
});
response.on("end", function (err) {
console.log(buffer);
console.log("\n");
});
});
I run my angular app with node http-server, with the following arguments
"start": "http-server --cors -a localhost -p 8000 -c-1"
And my angular controller looks as follows
app.controller('Request', function($scope, $http){
// functional URL = http://www.w3schools.com/website/Customers_JSON.php
$scope.test = "functional";
$scope.get = function(){
$http.get('http://www.asterank.com/api/kepler?query={"PER":{"$lt":1.02595675,"$gt":0.67125}}&limit=10',{
params: {
headers: {
//'Access-Control-Allow-Origin': '*'
'Access-Control-Request-Headers' : 'access-control-allow-origin'
}
}
})
.success(function(result) {
console.log("Success", result);
$scope.result = result;
}).error(function() {
console.log("error");
});
// the above is sending a GET request rather than an OPTIONS request
};
});
The controller can parse the w3schools URL, but it consistently returns the CORS error when passed the asterank URL.
My app avails of other remedies suggested for CORS on this site (below).
Inspecting the GET requests through Firefox shows that the headers are not being added to the GET request. But beyond that I do not know how to remedy this. Help appreciated for someone learning their way through Angular.
I have tried using $http.jsonp(). The GET request executes successfully (over the network) but the angular method returns the .error() function.
var app = angular.module('sliderDemoApp', ['ngSlider', 'ngResource']);
.config(function($httpProvider) {
//Enable cross domain calls
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
});
You should understand one simple thing: even though those http modules look somewhat similar, they are totally different beasts in regards to CORS.
Actually, the node.js http.get() has nothing to do with CORS. It's your server that makes a request - in the same way as your browser does when you type this URL in its location bar and command to open it. The user agents are different, yes, but the process in general is the same: a client accesses a page lying on an external server.
Now note the difference with angular's $http.get(): a client opens a page that runs a script, and this script attempts to access a page lying on an external server. In other words, this request runs in the context of another page - lying within its own domain. And unless this domain is allowed by the external server to access it in the client code, it's just not possible - that's the point of CORS, after all.
There are different workarounds: JSONP - which basically means wrapping the response into a function call - is one possible way. But it has the same key point as, well, the other workarounds - it's the external server that should allow this form of communication. Otherwise your request for JSONP is just ignored: server sends back a regular JSON, which causes an error when trying to process it as a function call.
The bottom line: unless the external server's willing to cooperate on that matter, you won't be able to use its data in your client-side application - unless you pass this data via your server (which will act like a proxy).
Asterank now allows cross origin requests to their API. You don't need to worry about these workarounds posted above any more. A simple $http.get(http://www.asterank.com/api/kepler?query={"PER":{"$lt":1.02595675,"$gt":0.67125}}&limit=10')
will work now. No headers required.I emailed them about this issue last week and they responded and configured their server to allow all origin requests.
Exact email response from Asterank : "I just enabled CORS for Asterank (ie Access-Control-Allow-Origin *). Hope this helps!"
I was having a similar issue with CORS yesterday, I worked around it using a form, hopefully this helps.
.config(function($httpProvider){
delete $httpProvider.defaults.headers.common['X-Requested-With'];
$httpProvider.defaults.headers.common = {};
$httpProvider.defaults.headers.post = {};
$httpProvider.defaults.headers.put = {};
$httpProvider.defaults.headers.patch = {};
})
.controller('FormCtrl', function ($scope, $http) {
$scope.data = {
q: "test"//,
// z: "xxx"
};
$scope.submitForm = function () {
var filters = $scope.data;
var queryString ='';
for (i in filters){
queryString=queryString + i+"=" + filters[i] + "&";
}
$http.defaults.useXDomain = true;
var getData = {
method: 'GET',
url: 'https://YOUSEARCHDOMAIN/2013-01-01/search?' + queryString,
headers: {
'Content-Type': 'application/json; charset=utf-8'
}
};
console.log("posting data....");
$http(getData).success(function(data, status, headers, config) {
console.log(data);
}).error(function(data, status, headers, config) {
});
}
})
<div ng-controller="FormCtrl">
<form ng-submit="submitForm()">
First names: <input type="text" name="form.firstname">
Email Address: <input type="text" ng-model="form.emailaddress">
<button>bmyutton</button>
</form>
</div>
Seems to work with the url you posted above as well..
ObjectA: 0.017DEC: 50.2413KMAG: 10.961KOI: 72.01MSTAR: 1.03PER: 0.8374903RA: 19.04529ROW: 31RPLANET: 1.38RSTAR: 1T0: 64.57439TPLANET: 1903TSTAR: 5627UPER: 0.0000015UT0: 0.00026
I should also add that in chrome you need the CORS plugin. I didn't dig into the issue quite as indepth as I should for angular. I found a base html can get around these CORS restrictions, this is just a work around until I have more time to understand the issue.
After lots of looking around. The best local solution I found for this is the npm module CORS-anywhere. Used it to create AngularJS AWS Cloudsearch Demo.
My code is attempting to post data to a Coldfusion API from my local Node.js server. I have managed to communicate with the API and authenticate myself via the request headers. However I am having difficulty actually passing my JSON object through as I cannot get the structure right.
The API does not accept the JSON option of the request module, so that is my easiest option out of the window.
The API is expecting the following:
{
'source': {
'customer': {
'customerlogin': 'myusername',
'customerpassword': 'mypassword',
}
}
}
my code works if I hard code the following body parameter (from a sucessful post by somebody else) into my post.
var Jrequest = require('request');
var options = {
uri: 'http://myAPI/customerSSO.json',
headers: {'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': something', 'Timestamp': timestamp},
method: 'POST',
body: 'source=%7B%0D%0A++%22customer%22%3A+%7B%0D%0A++++%22customerlogin%22%3A+%22myusername%22%2C%0D%0A++++%22customerpassword%22%3A+%22mypassword%22%2C%0D%0A%09%22success%22%3A+%22%22%0D%0A++%7D%0D%0A%7D' // Working
};
Jrequest(options, function (error, response, body){
res.send(body);
});
If I send the JSON through in other ways, for example json.stringify(), it is rejected on the grounds that 'source is required but not defined'.
So I suppose my question is, in node.js how do I turn JSON into something that looks like this
'source=%7B%0D%0A++%22customer%22%3A+%7B%0D%0A++++%22customerlogin%22%3A+%22myusername%22%2C%0D%0A++++%22customerpassword%22%3A+%22mypassword%22%2C%0D%0A%09%22success%22%3A+%22%22%0D%0A++%7D%0D%0A%7D'
or have I overlooked another option?
Thanks for any help and apologies if I have used incorrect terminology.
I think this should work:
var querystring = require('querystring');
...
request({
...
headers : { 'Content-Type': 'application/x-www-form-urlencoded', ... },
body : 'source=' + querystring.escape(JSON.stringify({
'customer': {
'customerlogin': 'myusername',
'customerpassword': 'mypassword',
}
})),
...
}, ...)
Your example also contains newlines and carriage returns and such, but I'm assuming those are optional.
I need to do a POST method inside a firefox add-on to another server, I have been trying to use different ways, and after googling I found out that I should use the Request module from the SDK inside my main.js.
I am using firefox v 23
I tried using the chrome module
var xmlhttp = chrome.Cc["#mozilla.org/xmlextras/xmlhttprequest;1"]
.createInstance(chrome.Ci.nsIXMLHttpRequest);
but I got NS_ERROR_FAILURE. I even added the permissions in the package.json
"permissions": {
"cross-domain-content": ["https:[some url]"]
}
But it still gives the same error.
I then used the Request module but didn't work so far. I tried a GET method with the Request module and it works fine. But the POST method always returns a 0 status and an empty response.
I tried doing the same request via a browser http client and it worked fine!! But through the code inside the add-on it always returns a 0.
The request sets headers and of course has a payload.
var contentObject = {[Valid JSON Object]};
var myRequest = Request({
url: "https://[some url]",
headers: {
"pragma": "no-cache"
},
content: contentObject,
contentType: "application/json",
onComplete: function (response) {
console.log("Status: " + response.status);
console.log("Response json: " + JSON.stringify(response));
}
}).post();
Your support is highly appreciated. There are very few resources I found over the internet about this issue and non of them solved my problem.
I guess the server script expects a JSON string representation of the contentObject. But this is not how objects are treated by the request module, they are turned to key/value pairs.
So change
content: contentObject
to
content: JSON.stringify(contentObject)
the POST method always returns a 0 status and an empty response
This might not be direct answer, but I had the same problem last couple of days. A friend who was connected to network via different provider tried the same code and it worked fine. Also, if I remember correctly, I could connect to the port 80 but not to the port where I was sending POST request so that port might be blocked on the network you are connected.