Patch request with angular.js is send to wrong url - angularjs

My REST API is configured to accept this kind of request
public function lockUserAction($slug)
{} // "lock_user" [PATCH] /users/{slug}/lock
So sending a patch request to
/api/users/2/lock
Will lock the user with id=2. This is my rest service inside angular.js
angular.module('UserService',['ngResource']).factory('User', function($resource){
var User = $resource('/api/users/:id',
{},
{
list: { method: 'GET' },
lock: { method: 'PATCH' }
}
);
return User;
});
List works just finde, but lock does not work. The console prints:
PATCH /api/users 405 (Method Not Allowed)
I invoke it like this
$scope.lock = function(user){
user.$lock();
}
In the error message I see the url /api/users instead of /api/users/2/lock. Is this normal behaviour? Of course list excepts only GET requests and PATCH requests are not allowed on /api/users only on /api/users/{slug}/lock.
Any ideas why /api/users is called and not /api/users/{slug}/lock. Any ideas how to fix this?

When you call $lock angular has no idea that you intend to call the same url as before, with some extra path element. Also there is no way for angular to know what is a value of :id param.
Than let angular know about locking:
var User = $resource('/api/users/:id/:action', //add param to the url
{},
{
list: { method: 'GET' },
lock: { method: 'PATCH',params:{action:"lock",id:"#id"}} //set param value, so angular knows where to send request, #id refers to user id in json representation of user
}
);

Related

How to send multiple parameters in AngularJS $http.post to Web API controller action method

How to send multiple parameters in an angularjs $http.post to web api controller action method.
Below is my code.
AngularJS code
var complexObj = { prop1: "value", prop2: "value" };
var id = 100;
var data = { id: id, complexObj: complexObj };
$http({
method: 'POST',
url: 'http://localhost/api/WebApiController/MethodName',
data: data
}).success(function (data, status) {
//do something...
});
$http.post('http://localhost/api/WebApiController/MethodName', data)
.success(function (data, status) {
//do something...
});
Web API controller
[RoutePrefix("api/WebApiController")]
public class WebApiController: ApiController
{
[Route("MethodName")]
public ReturnValue WebApiAction(string id,ComplexObj complexObj)
{
// process request and return data...
}
}
I am getting below response message in fiddler.
{ "message": "No HTTP resource was found that matches the request
URI 'http://localhost/api/WebApiController/MethodName'.",
"messageDetail": "No action was found on the controller
'WebApiController' that matches the request." }
When I send the complexObj alone, its hitting the web api,but all properties are null or set to default values.
What am I doing wrong? How can I send two or more parameters(both complex objects and string/int) in $http.post? Any help is much appreciated.
Web API doesn't support multiple post parameters in this way.
Your best bet is to roll up Id into ComplexObj and post it as a single parameter.
complexObj.id = id;
var data = complexObj;
Update your signature to take just a single object.
[Route("MethodName")]
public ReturnValue WebApiAction(ComplexObj complexObj)
{
// process request and return data...
}
If you absolutely want to be able to post data like this, consider Rick Strahl's post on creating a custom parameter binder.

AngularJS $resource GET params appear in URL

My REST backend [ based on NodeJS/express/mongojs] is complaining 404 (not found) when Params are attached as part of URL. Backend rest interface is coded as below;
var express = require('express');
var router = express.Router();
router.get('/login', auth.signin); //auth.signin is code to verify user
Above REST service is consumed by AngularJS based frontend through $resource as below;
Definition:
angular.module('myapp').factory('signinmgr', function($resource) {
return $resource("http://localhost:3000/login", {}, {
'get': {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
}});
Usage:
signinmgr.get({'username':'myname', 'password':'mypass'}, function(data){
//success
}, function(x){
//failed
});
Problem:
Frontend code above produces a URL to consume REST service where parameters are part of URL i.e. http://localhost:port/login?username=myname&password=mypass [if I use GET method, POST is OK]. I wanted my front end to keep URL as http://localhost:port/login and post any parameters through body as backend is using req.body.paramName to read those. [Actual Solution]
If (1) cannot be done, and my frontend is sending params as part of URL, I needed help as to know how to equip my backend to allow this URL with parameters so that backend doesnt return 404 as the base URL http://localhost:port/login is already there.
PS: for (1), I tried this thread with data:{username:'',password:''} but of no use. Please help if I am missing something very obvious or some concept.
Try the $http service instead:
angular.module('myapp').factor('signinmgr', function($http) {
return {
login: function (username, password) {
$http.post("http://localhost:3000/login", {
username: username,
password: password
}
}
};
});
signinmgr.login('myname', 'mypass').then(function(data){
//success
}, function(x){
//failed
});
Each request that my nodejs/expressjs backend receives has three places for passed attributes;
params{}
query{}
body{}
My problem (1) cannot be fixed in case I want to use GET method since with GET request parameters are visible as part of URL i.e. http://localhost:port/login?username=myname&password=mypass. To send my username/password I had to use POST that sends parameters as part of body{}.
My problem (2) was that I was using GET and mistakenly looking for parameters in body{} of request. Instead, parameters passed as part of URL in GET request are added to query{} of the request.

API-key header is not sent (or recognized). Angularjs

I'm trying to access an API with AngularJS but I get the following error:
XMLHttpRequest cannot load http://www.football-data.org/alpha/soccerseasons/398/leagueTable?callback=JSON_CALLBACK. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://purepremier.com' is therefore not allowed access.
This is my code for the service:
angular.module('PremierLeagueApp.services', []).
factory('footballdataAPIservice', function($http) {
var footballdataAPI = {};
footballdataAPI.getTeams = function() {
$http.defaults.headers.common['Auth-Token'] = 'token';
return $http.get('http://www.football-data.org/alpha/soccerseasons/398/leagueTable?callback=JSON_CALLBACK');
};
return footballdataAPI;
});
I use an authentication token (api key) to access the api, but according the API owner this API key header is not sent or recognized. Do you have any idea how I can adapt the code to make this work? thanks!
You should hide that API key before posting on a public site such as this. I would advise you regenerate your key (if possible) just in case - better safe than sorry.
Assuming your site url is 'http://purepremier.com' from the error message, the API should add a 'Access-Control-Allow-Origin' header with your site URL to allow you access. Have a look here for more information.
This is not directly related to your problem, but I notice you are setting $http defaults every time getTeams() is called. You should either set this outside of the actual function call (preferably in a run block), or just send the GET request with that header specifically applied. As the API key is specific (I assume) to that call, you may not want to be sending it to anyone and everyone, every time you make a HTTP request.
Change your factory code like this:
factory('footballdataAPIservice', function($http) {
return {
getTeams: function(){
return $http({
url:'http://www.football-data.org/alpha/soccerseasons/398/leagueTable',
headers: { 'X-Auth-Token': 'your_token' },
method: 'GET'
}).success(function(data){
return data;
});
}
}
});
Inject factory in your controller and retreive the data:
.controller('someController',function(footballdataAPIservice,$scope){
footballdataAPIservice.getTeams().then(function(data){
$scope.teams=data;
console.log($scope.teams)
});
});
Here is the working plunker
You change the Auth-Token To Authorization
$http.defaults.headers.common['Authorization'] = 'token';
Because token is send via headers using Authorization
try jsonp
angular.module('PremierLeagueApp.services', []).
factory('footballdataAPIservice', function($http) {
var footballdataAPI = {};
footballdataAPI.getTeams = function() {
$http.defaults.headers.common['Auth-Token'] = 'token';
return $http.jsonp('http://www.football-data.org/alpha/soccerseasons/398/leagueTable?callback=JSON_CALLBACK');
};
return footballdataAPI;
});

Getting 401 error when call $http POST and passing data

I am calling a Web API 2 backend from an angularjs client. The backend is using windows authentication and I have set up the $httpProvider to use credentials with all calls and it works fine for all GETS.
Like this:
$httpProvider.defaults.withCredentials = true
But, when using the POST verb method AND passing a data js object I get a 401 error. If I remove the data object from the $http.post call it reaches the endpoint but I would like to pass up the data I need to save.
Here's an example of the client-side call:
var saveIndicator = function (indicator) {
var req = {
method: 'POST',
url: baseUrl + "/api/indicators",
data: indicator
};
return $http(req).then(function (response) {
return response.data;
});
};

$resource invalidation in angularjs

I have this use case where I pass authToken to every request and this token changes everytime the person logins.
app.factory('Comment', function ($resource, localStorageService, $cacheFactory) {
return $resource('http://localhost:port/comments/:id', {"id":"#id", port:':9000'}, {
query: { method:'GET', isArray: true , headers: {'X-AUTH-TOKEN':'authToken='+localStorageService.get("authToken")}},
save: { method:'POST',headers: {'X-AUTH-TOKEN':'authToken='+localStorageService.get("authToken")}},
update: {method:'PUT' ,headers: {'X-AUTH-TOKEN':'authToken='+localStorageService.get("authToken")}},
delete : {method: 'DELETE',headers: {'X-AUTH-TOKEN':'authToken='+localStorageService.get("authToken")}},
get : { method: 'GET', headers: {'X-AUTH-TOKEN':'authToken='+localStorageService.get("authToken")}}
});
The behaviour I am seeing is that if the authToken changes for some reason the $resource keeps adding the previous authToken while sending the request. I am using the $http directly for login and for any commenting related stuff I am using $resource. Am I missing something?
After login I make sure that my localStorage has the newly created token but the request are using the previous authToken till I refresh the page after which it adds the correct header I know that the $resource uses some kind of caching and tried to remove the $http cache like this after loggin in.
$cacheFactory.get('$http').removeAll();
but didnt't help
It's because token is assigned once when factory code executes. Try this instead:
get : { method: 'GET', headers: {
'X-AUTH-TOKEN': function(){
return 'authToken=' + localStorageService.get("authToken");
}
}}

Resources