Setting headers and http params for a single request in restangular - angularjs

I am trying to use restangular for file upload post request , I want to achieve the same functionality as below in restangular.
However, I was unsure how to set content type and transformRequest for just this particular request. If I understand correctly, setDefaultHeader sets it for all subsequent requests. Is there some other way?
myApp.service('$fileUpload', ['$http', function ($http) {
this.uploadFileToUrl = function(file, uploadUrl){
var filedata = new FormData();
filedata.append('file', file);
$http.post(uploadUrl, filedata, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
})
.success(function(){
})
.error(function(){
});
}
}]);

You have 2 situations here, the POST for create a new item or the PUT to edit an item:
// Save new Item
$scope.saveNew = function (item) {
var data = new FormData();
angular.forEach(item, function (fieldData, field) {
data.append(field, fieldData);
});
Restangular
.all('items')
.withHttpConfig({transformRequest: angular.identity})
.post(data, {}, {'Content-Type': undefined})
.then(function () {
// do on success
}, function () {
// do on failure
});
};
// Edit existing Item
$scope.save = function (item) {
var data = new FormData();
angular.forEach(item.plain(), function (fieldData, field) {
data.append(field, fieldData);
});
Restangular
.one('items', item._id)
.withHttpConfig({transformRequest: angular.identity})
.customPUT(data, undefined, {}, {'Content-Type': undefined})
.then(function () {
$location.path('sites');
});

To set the headers for a single request all you'll need to do is add an object containing the name and value of the headers as an argument to .post(), .get() or whatever method you need.
https://github.com/mgonto/restangular#element-methods
Restangular.all('some-endpoint').post(postContent, {}, {'Content-Type': undefined}).then(function (response) {
console.log('Weeeeee!!!');
});
As for the transformRequest I am unsure of, I haven't had to deal with anything like that before, this is the only thing I could find on it in the documentation:
https://github.com/mgonto/restangular#setdefaulthttpfields
But that seems to set it for all the request which isn't what you want, but it's something at least.
Anyway, hopefully this will help you get what you want.
Edit:
Since most of the request types in restangular have a query param and then the headers you need to pass in a blank query param object and then the headers, example has been updated to show this.

Since this is the first hit on Google for this issue, see Issue 420 in the Restangular issue tracker.
Basically the newest Restangular has a withHttpConfig function to set $http options right before a request is dispatched.
If you have a route at a URL something like example.com/api/users/:id/picture that accepts a multipart upload with an image for a specific user you could do something like:
Users.one(2)
.withHttpConfig({transformRequest: angular.identity})
.customPOST(filedata, 'picture', undefined, {'Content-Type': undefined})
.then(function(resp) {
// File data post is complete here
});
By default Angular will transform any data sent with $http to JSON. The transformRequest configuration simply replaces that default transformation with a NOP.

Related

Angular js how to pass data to delete service?

I am working in angular js on delete service api when passing data in service it is showing 400 bad request error.This is my js to call the service.
$scope.deleteUser = function(id){
var data = 'Id='+id;
DataService.deleteUser(data).then(function successCallback(response) {
console.log('deleted');
}, function errorCallback(response) {
console.log(response);
});
}
This is service js to delete users.
service.deleteUser = function(data){
var config = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'X-Auth-Token': 'mytoken'
}
};
return $http.delete(mainURL + '/users', data, config);
};
This is curl api request where i need to pass data:
curl -v -H "X-Auth-Token: mytoken" -X DELETE -F Id=665799088 http://<ipaddress>/users
The 2nd parameter to $http.delete is the config, so you need to pass the config object as the 2nd parameter and not data.
DELETE method type doesn't accept a Request body so you should not be passing the ID as data. Instead try this http://main_url/users?Id=id
So in your service use this
return $http.delete(mainURL + '/users?Id='+data, config);
Also check how you are passing the ID to your API. If you are passing ID as a query parameter then the above will work, but if you are passing it as a route parameter then the above URL won't work, but from your CURL expression I believe you are passing Id in the Query string and not as a route parameter.
According to documentation on $http service, delete method only accepts 2 parameters, url and config, meaning that your data is currently treated like config. You are most likely looking to pass some params options to your config object.
DataService.deleteUser(id).then(function successCallback(response) {
console.log('deleted');
}, function errorCallback(response) {
console.log(response);
});
And your service declaration should be more like.
service.deleteUser = function(id){
var config = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'X-Auth-Token': 'mytoken'
},
params : {
id : id
}
};
return $http.delete(mainURL + '/users', config);
};
Also keep in mind that a path looking like /users/id is more correct, if you are in charge of the API.

How to unit-test the responseType in AngularJS

I have a method that dynamically sets responseType attribute of the $http request based on the asset type that's being requested. I'd like to unit-test that the correct response type is being set using Jasmine.
From what I found, you can expect a request with certain headers, but responseType is not a header, it's a part of the request config. Here are the samples of my code (in TypeScript).
let config = {
headers: {
'Content-Type': contentType
}
}
if (contentType.startsWith('image')) {
config.responseType = 'arraybuffer';
}
$http.get(url, config);
Ok, this is a bit late, and I've spent quite a while on this, but I've finally gotten this to work.
Assuming you're reconstructing the $httpBackend in a beforeEach hook (mine's assigning it to a variable called 'backend'... in the App config (or perhaps a more global beforeEach hook, haven't tried it that way), you'll need to add a decorator function to the $httpBackend service:
app.decorator('$httpBackend', ['$delegate', function ($delegate) {
$delegate.interceptedCalls = [];
var $httpBackend = function (method, url, data, callback, headers, timeout, withCredentials, responseType,
eventHandlers, uploadEventHandlers) {
$delegate.interceptedCalls.push({
method: method,
url: url,
timestamp: new Date(),
type : responseType
});
return $delegate.apply(null, arguments);
};
angular.extend($httpBackend, $delegate);
return $httpBackend;
}]);
All that does is add an interceptedCalls property to your backend object which will contain a list of all the requests that go through it.
Then, in your test file, you can do something like this:
it("forwards the data correctly",function(){
var headers = {
'Content-Type' : 'application/json',
'Accept': 'application/json, text/plain, */*'
};
backend.expectPOST('/someRoute/',{"A" : "B"},headers)
.respond(200,"dsfkjlasdfasdfklsdfd");
service.functionThatCallsSomeRoute({"A" : "B"});
backend.flush();
expect(backend.interceptedCalls[0]['type']).to.equal('arraybuffer');
});
May not be the best way to do it, but since I'm essentially refreshing the whole thing (backend and service being tested) before every test, it will have all the calls in order on the object.

Does angular js have support for the HTML5 formdata object

I have been searching and I can't seem to find any articles on how to post formdata with angular. I don't want to upload a file I want to post text data as objects and then. does the $http module support posting using formdata instead of application/x-www-form-urlencoded?
You can use formdata normally as any other data in your post request.
see the below example
var formData = new FormData();
formData.append('key1', 'hello');
formData.append('key2', 'hi');
$http.post('https://some.com/post-here',formdata, {
headers: { 'Content-Type': false },
transformRequest: function(data) {
return data;
}
}).then(function() {
alert('success');
}, function() {
alert('error');
})

change Content-type to "application/json" POST method, RESTful API

I am new at AngularJS and I needed your help.
All I need just need is to POST my json to the API and recieve the proper response.
Here's my JSON where i don't know where to code this.
JSON
{
"userId" :"testAgent2",
"token" :"testAgent2",
"terminalInfo":"test2",
"forceLogin" :"false"
}
NOT SURE IF I'm doing this right.
CONTROLLER.JS
function UserLoginCtrl($scope, UserLoginResource) {
//Save a new userLogin
$scope.loginUser = function() {
var loggedin = false;
var uUsername = $scope.userUsername;
var uPassword = $scope.userPassword;
var uforcelogin = 'true';
UserLoginResource.save();
}
}
SERVICES.JS
angular.module('UserLoginModule', ['ngResource'])
.factory('UserLoginResource', function($resource, $http) {
$http.defaults.useXDomain = true;
delete $http.defaults.headers.common['X-Requested-With'];
$http.defaults.headers.post["Content-Type"] = "application/json"; //NOT WORKING
return $resource('http://123.123.123.123\\:1234/SOME/LOCATION/THERE', {}, {
save: {
method:'POST',
headers: [{'Content-Type': 'application/json'}]
} //NOT WORKING EITHER
});
});
INDEX.HTML
<html ng-app>
<head>
<script src="js/lib/angular/angular.js"></script>
<script src="js/lib/angular/angular-resource.js"></script>
</head>
<body ng-controller="UserLoginCtrl">
<form class="form-horizontal" name="form-horizontal" ng-submit="loginUser();">
<div class="button-login">
<!-- start: button-login -->
<button class="btn btn-primary" type="submit">Login</button>
</div>
</form>
</body>
</html>
I kept on getting a response like Unsupported Media Type. I don't know, what else to do.
Assuming you are able to use one of the more recent "unstable" releases, the correct syntax to change the header is.
app.factory('BarService', function ($resource) {
var BarService = $resource('/foo/api/bars/:id', {}, {
'delete': {
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
}
}
});
return BarService;
});
I find the $resource service is a tremendously powerful tool for building applications and has matured to a point that you do not need to fall back to $http as much. Plus its active record like patterns are damn convenient.
Posting a JSON object is quite easy in Angular. All you need to do is the following:
Create a Javascript Object
I'll use your exact properties from your code.
var postObject = new Object();
postObject.userId = "testAgent2";
postObject.token = "testAgent2";
postObject.terminalInfo = "test2";
postObject.forceLogin = "false";
Post the object to the API
To post an object to an API you merely need a simple $http.post function. See below:
$http.post("/path/to/api/", postObject).success(function(data){
//Callback function here.
//"data" is the response from the server.
});
Since JSON is the default method of posting to an API, there's no need to reset that. See this link on $http shortcuts for more information.
With regards to your code specifically, try changing your save method to include this simple post method.
The right way to set 'Content-Type': 'application/json' is setting a transformRequest function for the save action.
angular.module('NoteWrangler')
.factory('NoteNgResource', function NoteNgResourceFactory($resource) {
// https://docs.angularjs.org/api/ngResource/service/$resource
return $resource("./php/notes/:id", {}, {
save : { // redefine save action defaults
method : 'POST',
url : "./php/notes", // I dont want the id in the url
transformRequest: function(data, headers){
console.log(headers);
headers = angular.extend({}, headers, {'Content-Type': 'application/json'});
console.log(headers);
console.log(data);
console.log(angular.toJson(data));
return angular.toJson(data); // this will go in the body request
}
}
});
});
It seems there isn't a method to clear query parameters, the request will have both...

Angular.js delete resource with parameter

My rest api accpets DELETE requests to the following url
/api/users/{slug}
So by sending delete to a specified user (slug) the user would be deleted. here is the service code:
angular.module('UserService',['ngResource']).factory('User', function($resource){
var User = $resource('/api/users/:id1/:action/:id2', //add param to the url
{},
{
delete_user: {
method: 'DELETE',
params: {
id1:"#id"
}
},
update: {
method: 'PUT',
params: {
id1:"#id"
}
}
});
return User;
});
I call the delete function via
user.$delete_user({id:user.id}, function(){}, function(response){});
However the request seems to be send to the wrong url.
/api/users?id=4
So the parameter is actually missing, as a result I get a 405 Method not allowed. Is there any chance to send the delete request in the style of my api?
params is an object of default request parameteres in your actions. If you want url parameters you have to specify them in the second parameter like this:
angular.module('UserService',['ngResource']).factory('User', function($resource){
var User = $resource('/api/users/:id1/:action/:id2', //add param to the url
{id1:'#id'},
{
delete_user: {
method: 'DELETE'
}
});
return User;
});
this works with either:
// user has id
user.$delete_user(function(){
//success
},function(){
// error
});
or
var data = {id:'id_from_data'};
User.delete_user({},data);
or
var params = {id1:'id1_from_params'};
User.delete_user(params);
I've made a plnkr-example - you have to open your console to verify that the DELETE requests are correct.
See parameterDefaults in the Angular resource documentation.
I had this problem for a while I was using a service to add / delete / update categories. While passing in params for get it worked fine but then when deleting it was giving me a ?id=1234 instead of api/resource/1234
I got around this by making the default param a string.
///Controller
Service.delete({categoryId:id}, function(resp){
console.log(resp)//whatever logic you want in here
});
//SERVICES
$resource('api/resource/:categoryId', {"categoryId":"#categoryId"}, {
query:{method:"GET"},
delete:{method:"DELETE"},
});
Should work and the resulting url will be, originally I had categoryId in the default params as a variable name.
api/resource/1234 etc
Just omit the '#' in the parameter
.factory('reportFactory', ['$resource', 'baseUrl', function ($resource, baseUrl) {
return $resource(baseUrl + '/keys/:id', {}, {
delete: { method: 'DELETE',
headers: {
'Content-Type': 'application/json'
},
params: {id: 'id'} }
})
}]);
this will give you:
http://localhost:8080/reports/api/keys/b8a8a8e39a8f55da94fdbe6c
without the question mark
If you want to delete a model, there's no need to add params (params does not work for DELETE anyway):
$resource('/users/:id').delete({id: user.id}, function(res) {
...
})
or
$resource('/users/:role/:id').delete({role: 'visitor', id: user.id});
I'm not sure if it's a bug of ngResource.

Resources