How can I change the base URL of an AngularJS HTTP call? - angularjs

My application calls $HTTP many times like this:
this.$http({
method: this.method,
url: this.url
})
The this.url is always set to something like /app/getdata
Now I have moved the back-end of my application to another server and I will need to get data like this:
https://newserver.com/app/getdata
Is there a way that I can supply a base URL that will be used for all the $http calls?

I found a alternative solution instead of <base> tag:
written in coffeescript
$httpProvider.interceptors.push ($q)->
'request': (config)->
if config.url.indexOf('/api') is 0
config.url = BASE_URL+config.url
config

I usually keep settings in angular constants and inject them to services.

I tend to keep my urls close to where they are needed. So if I have a service, then I'd keep the base url there; like this: this.rootUrl = '/api/v1/';
This allows me to have additional contextual methods that 'extend' the url.
For example:
this.getBaseUrl = function(client_id, project_id) {
return this.rootUrl + 'clients/' + client_id + '/projects/' + project_id + '/';
};
Which I can then use like this:
this.createActivity = function(client_id, project_id, activity_name, callback) {
$http.post(this.getBaseUrl(client_id, project_id) + 'activities', {activity: {name: activity_name}})
.success(callback)
.error(this.handlerError);
};
or like this (within the same service):
this.closeActivity = function(activity_id, callback){
$http.get(this.rootUrl + 'close_activity/' + activity_id)
.success(callback)
.error(this.handlerError);
};

set baseUrl in $rootScope:
app.run(function($rootScope) {
$rootScope.baseUrl = "https://newserver.com";
});
add $rootScope into your app's controllers:
app.controller('Controller', ['$rootScope', function($rootScope){
...
this.$http({
method: this.method,
url: $rootScope.baseUrl + this.url
})

Related

Updating all api requests using ui-router stateParams and an interceptor

I have a an Angular application that reuses the same templates for several locations. The urls look something like:
/locations/location1/
/locations/location2/
/locations/location1/about
/locations/location2/about
And I have a state setup that sets up a location param which my other routes set as their parent:
$stateProvider
.state('root', {
url: '/locations/{location:[^/]*}',
abstract: true,
template: '<ui-view/>'
});
Within these page templates I have several components that make API requests. What I'd like to do is intercept all http requests to the api and prepend the location id based on the location property in $stateParams:
function apiInterceptor ($stateParams) {
return {
request: (config) => {
config.url = $stateParams.location + '/' + config.url;
return config;
}
};
}
module
.factory('apiInterceptor', apiInterceptor)
.config(function($httpProvider {
$httpProvider.interceptors.push('apiInterceptor');
}
Unfortunately this gives me a circular dependency:
ng1UIRouter <- $stateParams <- apiInterceptor <- $http <- ng1UIRouter
I believe I could get around the circular dependency using the $injector directly, but I've read that running into this problem means you probably have some sort of architecture problem. Is there a better way to get the location id without duplicating code all over for individual api requests?
For circular dependencies you can manually inject a service using $injector
try
function apiInterceptor ($injector) {
var $stateParams = $injector.get('$stateParams');
return {
request: (config) => {
config.url = $stateParams.location + '/' + config.url;
return config;
}
};
}

Store domain in one place in angular js service

I have the following example method in angular service:
function send(data) {
return $http({
method: 'POST',
url: 'https://test.domain/test/send',
data: $httpParamSerializerJQLike(data)
});
}
The domain that is https://test.domain/test is the same for all the services in my app. I do not want to write it every time in every services. I can abstract it in a constant and inject it in every service but I wonder if there is more clever solution. Is it possible to store the domain part in an interceptor or any other suggestions are welcome. Please provide code examples as I am quite new to angular. Thanks
I'd say rather than abstracting the values out into a constant, you should abstract the $http call into a service. Then you can just inject that service into all of your other services in place of $http. For example:
angular.module('myApp').factory("myHttp", ["$http", function ($http) {
return function (config) {
config.url = "https://test.domain/test" + config.url;
return $http(config);
};
}]);
So effectively what this service is doing is proxying calls to $http, but prepending your common URL to the beginning - this would allow you to change your example code to:
function send(data) {
return myHttp({
method: 'POST',
url: '/send',
data: $httpParamSerializerJQLike(data)
});
}
Of course, this is just one example of how you could do an abstraction like this - the myHttp service could take any form you like, depending on what would be most convenient for you. I think this is a better solution than using an interceptor in this case, as it allows you to pick and choose when you use it, rather than it being applied to every single HTTP request.
create an interceptor and on requests change the url.
angular.module('app').factory('domainInterceptorService', [
function () {
var request = function (config) {
config.url = 'https://test.domain/' + config.url;
}
return config;
}
return {request: request};
});

ASP MVC Angular JS $http not found

I have a problem with calling http get to WebApi controller from my angular code. I am using ASP MVC just to provide start page and the start page url looks like: http://localhost:23845/StudentsEditor/StudentsView and now from angular I am callinh http request:
angular.element(document).ready(function () {
$http({
method: "GET",
url: "api/Groups/GetGroups",
dataType: "json",
}).then(function successCallback(response) {
$scope.groups = response.data;
}, function errorCallback(response) {
alert("trouble...");
});
and I am getting 404 because the URL is incorrect. It concats the path and it loks like:
GET http://localhost:23845/StudentsEditor/api/Groups/GetGroups
instead of http://localhost:23845/api/Groups/GetGroups
plese give me some advice hoe to resolve it. Of course I have defined RouteConfig:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "StudentsEditor", action = "StudentsView", id = UrlParameter.Optional }
);
and the webApi config:
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "{url}/api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);
You should not hard code url's like that. You may use the Url.Content or Url.RouteUrl helper methods in your razor view to generate the relative url to the app base/root. It will take care of correctly building the url regardless of your current page/path. Once you get this value, You can use angular's value provider to pass this data from your razor view to your angular controller/ angular data services.
So in your razor view (Specific page/ Layout file), You may add this.
<script>
var myApp = myApp || {};
myApp.Urls = myApp.Urls || {};
myApp.Urls.baseUrl = '#Url.Content("~")';
</script>
<script src="~/Scripts/AngularControllerForPage.js"></script>
<script>
var a = angular.module("app").value("appSettings", myApp);
</script>
and in your angular controller, the appSettings will be injected and you can use that and build the correct url to your other web api end points.
var app = angular.module("app", []);
var ctrl = function (appSettings,$http) {
var vm = this;
vm.baseUrl = appSettings.Urls.baseUrl;
//build other urls using the base url now
var getUGroupsUrl = vm.baseUrl + "api/Groups/GetGroups";
// you can use getUGroupsUrl now for your http calls.
console.log(getUGroupsUrl);
$http.get(getUGroupsUrl).then(function(response) {
console.log(response.data);
}
};
ctrl.inject=['$http'];
app.controller("ctrl", ctrl)
You may also consider moving your web api calls from your angular controller to a data service to keep things clean & keep concern separated.
I found easy way to accomplish what I was looking for:
angular.element(document).ready(function () {
$http({
method: "GET",
url: window.location.origin + '/api/Groups/GetGroups',
dataType: "json",
}).then(function successCallback(response) {
$scope.groups = response.data;
}, function errorCallback(response) {
alert("trouble..");
});
});
and the key is window.location.origin which returns protocol + host + port

Configuring external http service in angularjs

I have a single page angular app which calls a RESTish service. How can I configure the base URL for my REST server so that in my services I can use relative URLs? Also, as I was playing around with the following interceptor I got an error where angular-ui router seemed to be using http to get views so this was affected by the middleware. Basically I guess I want a second http service to inject into my services that has this middleware, how can I do this?
app.config(["$httpProvider", function($httpProvider) {
$httpProvider.interceptors.push('middleware');
}]);
app.factory('middleware', function() {
return {
request: function(config) {
// need more controlling when there is more than 1 domain involved
config.url = "http://localhost:8080" + config.url;
return config;
}
};
});
The $http services is very important (and widely used) inside Angular.
You shouldn't alter it like this.
For handling requests to an API, it is best to create a dedicated service (even if it's a wrapper around $http).
E.g.:
.service('API', function ($http) {
var baseUrl = 'http://localhost:8080/';
this.get = function (path, config) {
return $http.get(baseUrl + path, config);
}
...
});
Then you can use your service for all API calls:
.controller('someCtrl', function (API) {
API.get('items').success(function (data) {
$scope.items = data;
});
});

AngularJS ngResource not sending custom header

I'm attempting to use ngResource to query a REST API. I need to specify my API key in a custom header. I've tried it like so:
angular.module('ApiService', ['ngResource'])
.factory('Api', ['$resource', function($resource) {
this.apiEndpoint = '';
this.apiKey = '';
return {
init: function(apiEndpoint, apiKey) {
this.apiEndpoint = apiEndpoint;
this.apiKey = apiKey;
},
get: function(collection) {
return $resource(this.apiEndpoint + 'api/1/' + collection, {},
{
get: {
method: 'JSONP',
headers: {'api_key': this.apiKey},
params: {callback: 'JSON_CALLBACK'}
}
}
).get();
}
};
}]);
which I then use in my controller like:
app.controller('MyCtrl', function ($scope, Api, ENV) {
Api.init(ENV.apiEndpoint, ENV.apiKey);
var widgets = Api.get('widgets');
});
My custom header isn't set when I inspect the XHR. Also, why will the XHR not run until I call an empty .get() after the initial $resource:get() method?
I've also tried to set the headers in $httpResource directly:
.config(function($httpProvider) {
$httpProvider.defaults.headers.get = {'api_key': 'abc123'};
})
but this still doesn't set the custom header when I inspect the network request. What am I missing?
This issue is, of course, that I was using JSONP in this request, which doesn't include the ability to craft headers when making a request. See how to change the headers for angularjs $http.jsonp.
Specifically, JSONP simply includes a <script> tag at the bottom of the DOM to load cross-domain javascript, so it's up to your browser to send the default headers.

Resources