I am confused why this is happening. I am fairly new with AngularJS/JS so bear with me. I want to create a simple side project that will assist me in learning how to cook, so I am using a recipe database API caled Yummly that will GET recipes with ingredients and other information.
Here's the documentation: https://developer.yummly.com/documentation.
I tried putting api key and ID in the URL as the API said I can. I also tried putting it in the HTTP headers as the API also said I could. I tried both in postman and both worked, but neither work in my code. I get the error:Cannot GET /[object%20Object]. So I am lost. Perhaps this description from the "How to use GET method" from the documentation is the reason?:
Don’t forget to URL-encode parameter names and values (i.e., [ and ] become %5B and %5D). I don't understand this preceding sentence so...
Here's my code. Thanks so much. Much appreciated!
angular.module("app", [])
.controller('AppController', ['$scope', '$http', function ($scope, $http) {
$scope.greeting = 'Hola!';
$scope.getRecipe = function(){
$http.get({
url: 'http://api.yummly.com/v1/api/recipes?q=onion+soup',
method: 'GET',
headers: {
'X-Yummly-App-ID':'myID (secret)',
'X-Yummly-App-Key':'myKey (secret)'
}
}).success(function(response) {
console.log("I got the response.");
}).error(function(error) {
console.log("failed", error);
})
}
}]);
If $http.get is preferred, the code would be:
$http.get('http://api.yummly.com/v1/api/recipes', {
params: {
q: 'onion+soup'
}
headers: {
'X-Yummly-App-ID':'myID (secret)',
'X-Yummly-App-Key':'myKey (secret)'
}
}).success(function(response) {
console.log("I got the response.");
}).error(function(error) {
console.log("failed", error);
})
According to the official document, the syntax of $http.get is:
get(url, [config]);
Shortcut method to perform GET request.
The first parameter of $http.get is a URL string. If an object is passed (as in the question), it would be converted to string, that's why you get the request sent to /[object%20Object] -- [object%20Object] is the toString() result of the config object.
Don’t forget to URL-encode parameter names and values (i.e., [ and ] become %5B and %5D). I don't understand this preceding sentence so...
Don't worry. This will be handled automatically. If the value of q above is 'onion+soup[xxx]', it would be URL-encoded as 'onion%2Bsoup%5Bxxx%5D'.
Related
My API implemented with expressJS returns json as normal response, but when an error occurred, returns error code with a plain text, by simply calling res.sendStatus(401).
This causes a problem on my frontend, I use angular ngResoruce, and the resource code is like this:
svc.authenticateApi = function() {
return $resource(apiEndpoint + 'authenticate', null, {
'save': {
method: 'POST',
transformResponse: function (data, header) {
console.log("transformResponse, header:", header());
console.log("transformResponse, data:", data);
return { data: angular.fromJson(data) };
},
},
});
};
This works fine when normal JSON data is returned, however, when error status is returned, the data parameter is not a serialised JSON string, it's plain text, and I get errors like this:
Apparently transformResponse tries to parse text Unauthorised as JSON and failed. I can work around this by sending every error response as JSON on the server end by calling something like `res.status(401).send({error: "Unauthorised"}, but that feels like a hack, and I don't want to manually repeat error text for each status code.
Is there a better way to handle this? I don't want it sounds like a rant, but ngResource document is really poor and I start to think using $http is a much better solution.
I've moved away from $resource and am using $http everywhere. I just find everything about $resource to be a bit wonky. I do think returning JSON from the server in all scenarios sounds like the best approach though. You could implement a custom handler to test your incoming responses to work around this, but that doesn't really feel right to me.
I'd guess that the error is occurring on the return { data: angular.fromJson(data) }; line though. You could wrap this in a try/catch as well.
I did find success following the suggestion by Mike Feltman to wrap the fromJson call in a try / catch. The idea is if there is an error, there's no need to bother transforming the response.
function transformIgnoringErrors(original) {
var data;
try {
data = angular.fromJson(original);
/* code to perform transformation */
} catch (err) {
/* return what came in because no need to transform */
data = original;
}
return data;
}
I am absolutly new in AngularJS and I am studying a tutorial that show how to access to this external weather forecast API: http://openweathermap.org/forecast to retrieve and use weather information.
So, into my application, I have a controller like this:
weatherApp.controller('forecastController', ['$scope', '$resource', '$routeParams', 'cityService', function($scope, $resource, $routeParams, cityService) {
// It contain the city selected in the view:
$scope.city = cityService.city;
$scope.days = $routeParams.days || 2;
$scope.weatherAPI = $resource("http://api.openweathermap.org/data/2.5/forecast/daily",
{ APPID: 'MY_PERSONAL_KEY',
callback: "JSON_CALLBACK",
cnt: 5
},
{ get: { method: "JSONP" }});
$scope.weatherResult = $scope.weatherAPI.get({ q: $scope.city, cnt: $scope.days });
$scope.convertToFahrenheit = function(degK) {
return Math.round((1.8 * (degK - 273)) + 32);
}
$scope.convertToDate = function(dt) {
return new Date(dt * 1000);
};
}]);
And I am finding some difficulties tho understand how exactly the service is called and the informations are required.
So from what I have understand (but I am absolutly not sure about it so correct me if I do wrong assertion) I have the following situation:
1) Into the controller I inject the $resource service provided by Angular that from what I have understand is an object that I can use for a user friendly RESTful web service interaction.
So by this line:
$scope.city = cityService.city;
I put a city (inserted by the user in the view) into the city property of the $scope of this controller and it will be user as one of the parameter used for the webservice query.
Then I create the weatherAPI property on the $scope object that I think should represent the way to access to this resource
$scope.weatherAPI = $resource("http://api.openweathermap.org/data/2.5/forecast/daily",
{ APPID: 'MY_PERSONAL_KEY',
callback: "JSON_CALLBACK"
},
{ get: { method: "JSONP" }});
So I think that weatherAPI is a resource object creted by the $resource service (or am I missing something?).
On this I set the web service URL (http://api.openweathermap.org/data/2.5/forecast/daily) and a couple of JSON objects, these:
{
APPID: 'MY_PERSONAL_KEY',
callback: "JSON_CALLBACK"
},
in which I declare the APPID field that is my personal key to use the key and the callback: "JSON_CALLBACK" field. What exactly represent this callback field?
And this second object:
{ get: { method: "JSONP" }}
Ok, the roole of these 2 objects for me are pretty obscure.
What exactly define? It seems to me that are something related to the security of my application but I am absolutly not sure about it
Finnally it retrieve data from the web service by:
$scope.weatherResult = $scope.weatherAPI.get({ q: $scope.city, cnt: $scope.days });
where I thonk that I am simply passing the 2 parameter (that are something like ?q=value&?cnt=value of a classic HTTPrequest)
So I think that weatherAPI is a resource object creted by the $resource service (or am I missing something?).
No, you're not missing anything. weatherAPI is exactly what you're think it should be.
in which I declare the APPID field that is my personal key to use the key and the callback: "JSON_CALLBACK" field. What exactly represent this callback field?
callback field is just an default GET parameter passed to API on each request. It is set here, so you don't have to pass it each time requesting something from API.
What exactly define? It seems to me that are something related to the security of my application but I am absolutly not sure about it
Third parameter passed into $resource call is an definition of available methods on your API.
In outer object, key is name of method. It is just name on which that method will be available. value is an object of settings for that method, in that case it is only specifying type of your method, which is "JSONP".
JSONP is an special type of request, it can be only an "GET" request, browsers won't allow "POST" here. JSONP must return simple function call, passing one parameter into it, JSON with result data. This function will be called on your JavaScript.
JSONP is just an workaround for making cross site calls.
I am having a serious issue with Angularjs and jQuery with this particular REST API. I am not in the same domain as said API, and can get the data back, however I am getting a "SyntaxError: invalid label "name" :{" error.
If I were to do something like $http.get or $.get I get a timeout after 10 seconds. However, if I use jsonp with either library I will see in Firebug that the data is returned in the net tab, however I get the error above in the console tab. After doing some research, I have seen plenty of people having issue with the API (a Jive product) and this specific line of text that is returned along with the JSON. The response looks something like this:
throw 'allowIllegalResourceCall is false.';
{"name":{ "givenName": "xxx"}}
The big problem is the first "throw" line. I have tried a bunch of ways to remove that line but I haven't found the proper way to do it. I apologize for not being able to provide a code sample, but if there is any way to get this work in Angularjs or jQuery, I will take it. I don't know if the answer lies in Angularjs interceptors, or transformResponse.
Any help that can be provided will be appreciated.
Thank you
AngularJs allows you do define the methods for transforming the http response data (so you can remove the first line of the response data). You can do this either for a single request or add a httpInterceptor.
Single request:
$http.get('...', {
transformResponse: $http.defaults.transformResponse.unshift(function(data) {
// Remove first line of response
data.split("\n").slice(1).join("\n")
}
});
HttpInterceptor
.config(['$httpProvider', function($httpProvider) {
$httpProvider.interceptors.push(function() {
return {
'request': function(config) {
config.transformResponse.unshift(function(data) {
return data.split("\n").slice(1).join("\n")
})
return config;
}
}
})
}])
Plunker: http://plnkr.co/edit/6WCxcpmRKxIivl4yK4Fc?p=preview
I've been hunting for a few hours now and can't seem to find any information specific to my setup so here goes.
I'm using the MEAN stack and wanting to use the Twitter API in my angular app. I have all the required keys and trigger a twitter api authentication on the server side using Node, then pass the token I get in response to my angular pages. I was hoping to be able to use this token to make requests to the api from an angular service. The request I'm trying to get working the moment is to fetch a given user's profile object. I've attached my service method below. The error I get when I run it is a 405 method no allowed, no access-control-allow-origin header is present.
angular.module('tms.system').factory('Twitter', ['$log', '$q', '$http', '$window', 'twitter', 'Global', function($log, $q, $http, $window, twitter, Global) {
return {
findProfile: function(handle) {
var deferred = $q.defer();
var config = {
timeout:3000,
headers: {
'Authorization': 'Bearer ' + Global.twitterToken,
'X-Testing' : 'testing'
}
};
$http.get('https://api.twitter.com/1.1/users/show.json?screen_name=' + handle, config).
success(function(data) {
$log.info(data);
deferred.resolve(data);
}).
error(function(status) {
$log.error(status);
});
return deferred.promise;
}
};
}]);
Just for future reference, as stated in the comments of maurycy's answer {and being myself trying to get tweets just from Angular without succes}, the best approach for this would be to get them from some backend.
I believe you should use $http.jsonp with a JSON_CALLBACK to get it to work, it's not going to happen with $http.get for sure
In my RESTful api one of the resources exposes a GET method that accept json as a parameter named 'query'. This parameter is passed directly to the MongoDB query allowing users to query the database directly using mongo syntax.
The problem I'm having is that the request always looks like this:
?&query=%7B%22source%22:%22incident%22%7D
Where it should look something like this:
?&query={'source': 'incident'}
This is how I am sending the GET request:
var query = {};
if ($scope.sourceFilter) { query.source = $scope.sourceFilter; }
var query = JSON.stringify(query);
$http.get('/api/feedbackEntries', {params: {limit: $scope.limit, query: query}}).success(function(data) { .......
I am doing the same thing on other get requests and I don't get this issue.
Am I doing something wrong here ? Is this to do with the way angular parses params ?
Thanks
Like the $http docs say
params – {Object.<string|Object>} – Map of strings or objects which will be turned to ?key1=value1&key2=value2 after the url. If the value is not a string, it will be JSONified.
Latter emphasis is added by me.
So the query property of the object you pass to the params configuration option is an Object. This means is will be JSONified, which means the same as
JSON.stringify(query);
So this
{'source': 'incident'}
Turns to this:
'{"source": "incident"}'
As RFC 1738 states:
... only alphanumerics, the special characters "$-_.+!*'(),", and
reserved characters used for their reserved purposes may be used
unencoded within a URL.
As it happens {, } and " are not on that list and have to be url encoded to be used in a url. In your case %7B corresponds to {, %7D corresponds to } and %22 corresponds to ".
So what is happening is normal and most server software automatically decodes the url query parameters for you, so they will be presented normally. Most likely you'll need to parse it back to JSON somehow!
Hope this helps!
When using RESTFul apis concider using ngResource, ngResource docs
Include it in your module:
yourApp = angular.module('yourApp', ['ngResource'])
Add your service:
yourApp.factory('YourService', ['$resource', function($resource){
return $resource('link/to/your/object', {});
}]);
Add your controller
yourApp.controller('YourController', [$scope,
'YourService', function($scope, YourService) {
$scope.yourData = YourService.get();
$scope.yourData = YourService.query(); //(When obtaining arrays from JSON.)
I've found this is the best way using a RESTFull api.
After some digging I figured this one out. Looking at the request I was making:
$http.get('/api/feedbackEntries',
I saw that the url does not end with a trailing slash. This was the only difference I could see compared with other requests that were working fine. So I added the trailing slash and magically it works. I can't explain why, whether it's something within angular or elsewhere .. but this is how I fixed the problem.
Hope this helps someone in the future.
Below is the code I used to get search result from my server, it works for me sending POST request with JSON params without .
var service = {
getResult: function ({"username": "roman", "gender": "male"}) {
var promise = $http({
url: ServerManager.getServerUrl(),
method: "POST",
data: params,
headers: {
'Content-Type': 'application/json'
}
})
.success(function (data, status, headers, config) {
console.log('getResult success.');
return data;
}).error(function (data, status) {
console.log('getResult error.');
});
return promise;
}
}
return service;