Hi I am developing web application in angularjs. I am making lot of http calls to interact with web api. As a result i have to send lot of data in headers too. I have created factory for get data as below. These data should should be passed in headers. Below is my factory.
var myapp = angular.module('RoslpApp');
myapp.factory("ScrollFunction", ['$location', '$anchorScroll', '$cookieStore', function ($location, $anchorScroll, $cookieStore) {
return {
getheaders: function () {
var cookiePreferredLanguage = $cookieStore.get('PreferredLanguage');
var headers={
Logintoken: $cookieStore.get('LoginToken'),
LoginId: $cookieStore.get('LoginID'),
RequestedPlatform: "Web",
RequestedLanguage: cookiePreferredLanguage
};
return headers;
}
}
}
]);
Below is my sample http call.
function getpermissiondetails() {
var headersdata = ScrollFunction.getheaders();
$scope.Create = "Create";
var getsavedvechilceUrl = baseurl + "api/RolesPermission/getgroups";
var request = {
url: getsavedvechilceUrl,
method: 'GET',
headers: {
RequestedPlatform: headersdata.RequestedPlatform,
RequestedLanguage: headersdata.RequestedLanguage,
Logintoken: headersdata.LoginToken,
LoginId: headersdata.LoginID
}
};
$http(request).then(function (response) {
$scope.groups = response.data.data;
}, function (error) {
})
}
What i want in header is i already have data in var headersdata = ScrollFunction.getheaders(); Is it possible to pass something like headers: { headersdata } because i can make add headers in factory. No need to expand it in each http call. I tried headers: { headersdata } but this is not sending any data to api. May i know is there any better solution? Any help would be appreciated. Thank you.
I guess this is a code refractoring question.
Q: Can I avoid doing the messy property assignment by doing something shortcut like headers={ factory data }?
A: Ok. I probably did a bad job paraphrasing your question. I'm just trying to make it more understandable.
Short answer: Yes. You can further shorten your code by doing this.
var request = {
url: getsavedvechilceUrl,
method: 'GET',
headers: ScrollFunction.getheaders()
};
Why?
Your function getheaders() is already returning a javascript object which is exactly what request.headers is looking. An object {}.
Since getHeaders() is already returning an object you can just plug it straight into request.headers. That is, you no need to re-create an object and reassign the property back in one by one.
Hope this helps.
Related
I have this $http request interceptor
app.config(function($httpProvider) {
$httpProvider.interceptors.push(function() {
return {
request: function(req) {
// Set the `Authorization` header for every outgoing HTTP request
req.headers['cdt_app_header'] = 'tamales';
return req;
}
};
});
});
Is there any way we can add a header or cookie to every $http request, but keep the header value secure / not visible with JavaScript?
We can add an obfuscation layer with this header to prevent easy access to our API endpoints, but I am wondering about a more truly secure solution.
Cookies are used for secure sessions, and these are more secure because they cannot be accessed with JavaScript. Say we have a user who can do this request with front-end code:
GET /api/users
we don't really want them to be able to make a simple request with cURL or a browser without an extra piece of information. The cookie we give them will give them the ability to use the browser address bar to make a GET request to /api/users, but if we add the requirement to have another cookie or header in place, then we can prevent them from accessing endpoints that are authorized for, in a format that we don't really want them to use.
In other words, we want to do our best to give them access, but only in the context of a front-end Angular app.
I can't add a comment because of my rep but what are you doing on the back-end to authorize users? If the cookie is signed and contains user permissions it shouldn't matter that the header is visible in the client as it will also be verified on the back-end API call.
in this sample i used HttpRestService to get RESTful API, read this article
at first we create a service to get our configs in this sample is getConfigs
we use getConfigs in the app.run when application is started, after get the configs we set them all in the header as sample.
after that we can get userProfile with new header and also secure by call it from our controller as you see.
in this sample you need to define apiUrl, it's your api host url, remember after logout you can remove the header, also you can define your configs dynamically to make more secure for your application.
HttpRestService.js github link
app.js
var app = angular.module("app", ["HttpRestApp"]);
app.service
app.service("service", ["$http", "$q", "RestService", function (http, q, restService) {
this.getConfigs = function () {
var deferred = q.defer();
http({
method: "GET",
async: true,
headers: {
"Content-Type": "application/json"
},
url: "you url to get configs"
}).then(function (response) {
deferred.resolve(response.data);
}, function (error) {
deferred.resolve(error);
});
return deferred.promise;
}
var api = {
user: "User" //this mean UserController
}
//get user with new header
//this hint to your api with this model "public Get(int id){ return data; }"
//http://localhost:3000/api/users/123456
this.getUserProfile= function(params, then) {
restService.get(params, api.user, true).then(then);
}
}]);
app.run
app.run(["RestService", "service", function (restService, service) {
var header = {
"Content-Type": "application/json"
}
//get your configs and set all in the header
service.getConfigs().then(function (configs) {
header["systemId"] = configs.systemId;
});
var apiUrl = "http://localhost:3000/";
restService.setBaseUrl(apiUrl, header);
}]);
app.controller
app.controller("ctrl", ["$scope", "service", function ($scope, service) {
$scope.getUserProfile = function () {
//this is just sample
service.getUserProfile({ id: 123456 }, function (data) {
$scope.user = data;
});
}
$scope.getUserProfile();
}]);
I have a basic angular APP that makes a GET request call to a API URL. The data returned is in JSON format. The API documentation states the following:
You must provide your App ID and key with every request that you make to the API. To do this, set an HTTP Authorization header on your requests that consists of your ID, followed by a colon, followed by your key, eg abc123:xyz789.
How do I incorporate this to my basic HTTP request.my code is below.
angular.module('myApp', [])
.controller('MyControler', function($scope, $http) {
$scope.$watch('search', function() {
fetch();
});
$scope.search = "My Search Query";
function fetch() {
$http.get("https://APIURlGoesHere" + $scope.search )
.then(function(response) {
$scope.details = response.data;
});
$http.get("ttps://APIURlGoesHere" + $scope.search)
.then(function(response) {
$scope.related = response.data;
});
}
});
Best way I know so far to implement this is: Interceptors
You can find some useful info about it here and here
And on SO, here: AngularJS $http interceptors
In your case, basically, you need to create a file with the following implementation (or equivalent) and include it into your project:
function myInterceptor() {
function request(req) {
var token = "mytoken" ; //<<--here you need to set the custom header's info (eg: abc123:xyz789)
var myHeader = "myHeader"; //<<--here you need to set the custom header's name (eg: Authorization)
if (token) {
//put custom header for sending the token along with every request
req.headers[myHeader] = token;
}
return req;
}
return {
request: request
};
};
function conf($httpProvider) {
$httpProvider['interceptors'].push('myInterceptor');
};
angular
.module('your_module_name')
.factory('myInterceptor', myInterceptor)
.config(['$httpProvider', conf]);
This will intercept every request made from your frontend app and will include that header on it.
Citing this topic:
How to use Basic Auth with jQuery and AJAX?
So, in Angular, it would be:
$http({
method: "GET",
url: "https://APIURlGoesHere" + $scope.search,
headers: { 'Authorization' : 'Basic '+btoa(username + ":" + password)
})
.then(function(response) {
$scope.details = response.data;
});
I've been trying to make a request to a NodeJS API. For the client, I am using the Mithril framework. I used their first example to make the request and obtain data:
var Model = {
getAll: function() {
return m.request({method: "GET", url: "http://localhost:3000/store/all"});
}
};
var Component = {
controller: function() {
var stores = Model.getAll();
alert(stores); // The alert box shows exactly this: function (){return arguments.length&&(a=arguments[0]),a}
alert(stores()); // Alert box: undefined
},
view: function(controller) {
...
}
};
After running this I noticed through Chrome Developer Tools that the API is responding correctly with the following:
[{"name":"Mike"},{"name":"Zeza"}]
I can't find a way to obtain this data into the controller. They mentioned that using this method, the var may hold undefined until the request is completed, so I followed the next example by adding:
var stores = m.prop([]);
Before the model and changing the request to:
return m.request({method: "GET", url: "http://localhost:3000/store/all"}).then(stores);
I might be doing something wrong because I get the same result.
The objective is to get the data from the response and send it to the view to iterate.
Explanation:
m.request is a function, m.request.then() too, that is why "store" value is:
"function (){return arguments.length&&(a=arguments[0]),a}"
"stores()" is undefined, because you do an async ajax request, so you cannot get the result immediately, need to wait a bit. If you try to run "stores()" after some delay, your data will be there. That is why you basically need promises("then" feature). Function that is passed as a parameter of "then(param)" is executed when response is ready.
Working sample:
You can start playing with this sample, and implement what you need:
var Model = {
getAll: function() {
return m.request({method: "GET", url: "http://www.w3schools.com/angular/customers.php"});
}
};
var Component = {
controller: function() {
var records = Model.getAll();
return {
records: records
}
},
view: function(ctrl) {
return m("div", [
ctrl.records().records.map(function(record) {
return m("div", record.Name);
})
]);
}
};
m.mount(document.body, Component);
If you have more questions, feel free to ask here.
I'm setting up a project using django-tastypie REST API and AngularJS. I'm fine with reading things from the json file through angular, but I cannot find a decent tutorial that would show me how to make even a simple CRUD application that isn't saving all the information in an object or whatever, but is manipulating the database through the tastypie api. Can any of you show me a tutorial of such sort or maybe just show me some sample code for this?
Thank you.
Use $resource - A factory which creates a resource object that lets you interact with RESTful server-side data sources.
Let's say you have Django model Book, and tastypie resource named BookResource. It's URL is /api/v1/book/. As you know, this URL actually is a resource, that means you can manipulate data in your Book model with GET, POST, DELETE, etc. requests.
You can "map" the Angular $resource to this API resource in a way:
someModule.factory('bookResource', ['$resource', function($resource) {
var apiResourceUrl = "/api/v1/book/:bookId/";
// id - your model instance's id or pk, that is represented in API resource objects.
var resource = $resource(apiResourceUrl, {bookId: '#id'}, {
all: {
method: 'GET', params: {}, // GET params that will included in request.
isArray: true, // Returned object for this action is an array (miltiple instances).
},
get: {
method: 'GET',
},
// [Define custom save method to use PUT instead of POST.][2]
save: {
/* But, the PUT request requires the all fields in object.
Missing fields may cause errors, or be filled in by default values.
It's like a Django form save.
*/
method: 'PUT',
},
// [Tastypie use POST for create new instances][3]
create: {
method: 'POST',
},
delete: {
method: 'DELETE',
},
// Some custom increment action. (/api/v1/books/1/?updateViews)
updateViews: {
method: 'GET',
params: {"updateViews": true},
isArray: false,
},
});
}]);
someModule.controller('bookCtrl', ['$scope', '$routeParams', 'bookResource',
function ($scope, $routeParams, bookResource) {
if ("bookId" in $routeParams) {
// Here is single instance (API's detail request)
var currentBook = bookResource.get({bookId: $routeParams.bookId}, function () {
// When request finished and `currentBook` has data.
// Update scope ($apply is important)
$scope.$apply(function(){
$scope.currentBook = currentBook;
});
// And you can change it in REST way.
currentBook.title = "New title";
currentBook.$save(); // Send PUT request to API that updates the instance
currentBook.$updateViews();
});
}
// Show all books collection on page.
var allBooks = bookResource.all(function () {
$scope.$apply(function(){
$scope.allBooks = allBooks;
});
});
// Create new
var newBook = new bookResource({
title: "AngularJS-Learning",
price: 0,
});
newBook.$save();
}]);
Angular's docs provide more information how to make usage of resource really incredibly.
Here is the problem with urls. As I remember, Angular will send request to /api/v1/books/1 (without slash in the end) and you'll get 404 from tastypie. Let me check this.
[2] http://django-tastypie.readthedocs.org/en/latest/interacting.html#updating-an-existing-resource-put
[3] http://django-tastypie.readthedocs.org/en/latest/interacting.html#creating-a-new-resource-post
Maybe I'm going about this the wrong way, i'm not sure, but I have 2 services, one is a user service which gets a bunch of details about the user from the server, the other being one that relies on some user details from the user service and then makes some more calls to the server to get other information.
Anyway, because of the async stuff that goes on when the 2nd service makes the calls the information required from the user server has not yet been populated.
I know Angular services can depend on one another, but not in this context it would appear?
factory('User', ['$resource', function ($resource) {
return $resource(usersUrl, {}, {
//The data model is loaded via a GET request to the app
query: {method: 'GET', params: {}, isArray: false},
putupdate: {method: 'PUT', params:{}}
});
}])
.factory('UserData', function() {
var data = {}
data.userinfo = {};
if(data = {}){
}
return {
updateinfo: function(newdata) {
data.userinfo = newdata;
// alert(data.userinfo.user)
},
userinfo: data
}
})
.factory('PlansData', ['UserData', 'User', '$rootScope', function(userData, user, $rootScope) {
var data = {}
data.plansinfo = {};
//alert(userData.data.userinfo.user.email)
if(data = {}){
}
return {
updateinfo: function(newdata) {
alert(user.query())
data.plansinfo = newdata;
},
plansinfo: data
}
}])
So I have a user service and a caching userdata service, but if I ever try and call anything from UserData in the PlansData service I get undefined.
How do I get plansData to wait for UserData to have some data?
Thanks
Tom
I'm not sure what you're trying to accomplish, but this line of code:
if(data = {}){
}
In both your services is wiping out your data object. You're setting the whole data object to be {}