I have an Angular 1.4 service that makes an $http.get() request to the MapQuest API. If I pass my API key as part of the url directly then it works however if I add it as part of the params field then it does not.
Working:
var url = 'http://open.mapquestapi.com/geocoding/v1/address?key=Gmjtd%7Cluub2d08nh%2C2s%3Do5-2u2gh4';
$http.get(url);
// Key actually sent
Gmjtd%7Cluub2d08nh%2C2s%3Do5-2u2gh4
Not working:
var url = 'http://open.mapquestapi.com/geocoding/v1/address';
$http.get(url, {
params: {
key: 'Gmjtd%7Cluub2d08nh%2C2s%3Do5-2u2gh4'
}
});
// Key actually sent
Gmjtd%257Cluub2d08nh%252C2s%253Do5-su2gh4
Not working either:
var url = 'http://open.mapquestapi.com/geocoding/v1/address';
$http.get(url, {
params: {
key: encodeURIComponent('Gmjtd%7Cluub2d08nh%2C2s%3Do5-2u2gh4');
}
});
// Key actually sent
Gmjtd%25257Cluub2d08nh%25252C2s%25253Do5-2u2gh4
It appears that passing the key in the params field causes it to undergo some kind of encoding process which renders it invalid.
How can I maintain the original key when using the params method?
Angular does indeed encode params. You should call decodeURIComponent since the key is already encoded.
$http.get(url, {
params: {
key: decodeURIComponent('Gmjtd%7Cluub2d08nh%2C2s%3Do5-2u2gh4');
}
});
Related
I am building a browser extension where I try to redirect a browser request to my page with a fair amount of data that will be contained in a JSON array returned from a service I call based on the requested URL. For example, if the user goes to example.com, I have a chrome.webRequest.onBeforeRequest.addListener that intercepts it based on the urls filter, invokes a AWS API Gateway endpoint that responds with a list of things in a JSON object. I need my local page to display that list of things in a local page.
I can show some small things by invoking the local page with URL parameters (and then treat it like a GET request), but this won't work for the amount of data i want to pass. How do I create a POST request for the redirect URL?
OR, is there some other pattern I should be using to do this?
listener code:
chrome.webRequest.onBeforeRequest.addListener(
function(details) {
if(swenToggle) {
return { redirectUrl: chrome.extension.getURL("markup/simple.html?r=n&url=" + details.url) }; // This is fine for simple data
} else {
//get the base URL
var baseUrl = new URL(details.url).hostname.split(".").slice(-2).join(".")
var apiUrl = // Call AWS API here
fetch(apiUrl).then(r => r.json()).then(result => {
console.log('RESULT : ' + result.body); // I need to pass this body to the redirectUrl below...
})
return { redirectUrl: chrome.extension.getURL("markup/complex.html?sourceUrl=" + baseUrl) };
}
},
{ urls: "example.com"},
["blocking"]
);
Solved it with a slightly different approach. Instead of calling the AWS API from background.js, I pass the parameters needed for the API call to complex.html as URL params, and then invoke the AWS API in complex.html.
Short:
I am unable to find any setting in documentation one drive api to get a file url that could not be accessed without access token
Details:
I tried different things with queryParameters: "select=id,name,size,file" but could not change the result
Using javascript API, when files chosen from one it gives an array named values in which each object contains properties like (some fake but sample values)
#microsoft.graph.downloadUrl: "https://public.sn.files.1drv.com/m7ZHglUdfkMkwg-qqnNj8"
#odata.context: "https://graph.microsoft.com/v1.0/$metadata#drives('D2CFA54CB9FFC341')/items/$entity"
id: "FA4454CB9FFC341!172"
name: "sada.pdf"
size: 4344
My code to get above results is
var odOptions = {
clientId: "df45ae45-68bd-4568-a473-4159a1b16fc1",
action: "download",
multiSelect: true,
// openInNewWindow: true,
// advanced: {
// queryParameters: "/drive/root/children?select=id,name,size,file",
// },
success: function (response) {
console.log(555, response);
},
cancel: function (response) { console.log(response); },
error: function (e) { console.log(e); }
};
OneDrive.open(odOptions);
the problen is https://public.sn.files.. public url (any one can access file without login using this url) unlike google drive which gives a secure url
The downloadUrl is a short lived URL that is preauthenticated so that authorization is not required. Access control checks are instead performed on the request that returns the URL. A flow that's closer to what Google Drive utilizes would be to hit the /content endpoint for a specific file - this request requires an OAuth token to be provided and will return the binary content.
I am trying to send 3 parameters in url for get method.
getUser: function(auser) {
var config = {
params: {
UserName: 'User89#domain170.com',
CorrelationId: '01233',
OrganizationId: '428'
}
}
//API Call
var promise = $http.get(API_URL, config, REQUEST_HEADER).then(
function(aGetUserResponse) { // return}
But I am getting 404 because my parameters are not sending in correct order. Why my order is changing? Any solution for this?
http://127.0.0.0:8000/client_01/users?CorrelationId=01233&OrganizationId=428&UserName=User89#domain170.com
Failed to load resource: the server responded with a status of 404 (Not Found)
The fact of the matter is, your server side code should be setup in a way that query parameter order in the query string does not matter. Here is a good explanation on the matter.
If you have access to the server side code that parses the parameters, the changes should really be made there. We can help with that if you share that code with us. It's really not a a problem with your angular code. If you don't have access to the code, I would suggest manually formatting the query string instead of letting Angulars $http service do it for you. Such as:
getUser:
function(auser) {
var config = {
params: {
}
}
}
function queryUrl(username, corrId, orgId){
return API_URL + "?UserName=" + username
+ "&CorrelationId=" + corrId
+ "&OrganizationId=" + orgId;
}
//API Call
var promise = $http.get(queryUrl(), config, REQUEST_HEADER).then(
function(aGetUserResponse) { // return}
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;
I'm working on a sort of file-manager application that connects to a RESTFUL file api.
On the angular app, each file and directory is an instance of angular $resource using the file-object property relativePathName as resource id .
js
var File = $resource(url + '/:type/:id', {id: '#relativePathName', type: '#type'}, {…});
The problem is, when updating a file resource, the relativePathName parameter gets url encoded, e.g. / becomes %2F which causes the server to intercept the request before it hits the actual API (I assume the server treats this as a physical address and of returns a 404 response). The API is capable of treating whole url segments as a single param, so basically it'd treat path/to/file as a uri parameter of http://myapp.com/api/files/create/path/to/file and not as a different uri.
My question is, is there a way to modify the request url after it's being generated by the private Router instance inside of the resource constructor? If so, how (found nothing on this in the docs)?. What would be a possible solution? passing relativePathName as a parameter instead of declaring it as the resource id (which would require modifying the API)?
Thanks in advance.
Thomas
Using $resource is not the one stop shop for RESTful service calls, it is merely a convenience service for api's that are structured in a certain way. If $resource cannot do what you need, just create your own service using a mix of $resource and $http that that fits the api you are trying to call.
In our app we wanted a different URL for getByName requests, so we override the resource address with the URL parameter of the action getByName like so:
myapp.factory('ListGroup', ['$resource',
function($resource) {
return $resource(
'/API/List/:Id',
{
Id:'#Id',
Name:'#Name'
},
{
getByName: {method: 'GET', url: '/API/List/Group/:Name', isArray: true}
}
);
}
]);
My question is, is there a way to modify the request url after it's being generated by the private Router instance inside of the resource constructor?
I'm not sure about inside of the resource constructor but you can use interceptors to programatically alter route urls after they have been generated by $resource.
structure
hooks.config.js
hooks.factory.js
hooks.module.js
hooks.module.js
module.exports = angular
.module("app.hooks", [])
.factory("hooks", require("./hooks.factory.js"))
.config(require("./hooks.config.js"));
hooks.config.js
module.exports = ["$httpProvider", function($httpProvider) {
$httpProvider.interceptors.push("hooks");
}];
hooks.factory.js
module.exports = ["$q", "$location", function($q, $location) {
var basePrefix = "/api/v1";
return {
//invoked on every http request
request: function(request) {
request.url = interpret(request.url);
return $q.when(request);
}
};
function interpret(str) {
//if requesting an html template, don't do anything
if (str.indexOf(".html") > -1)
return str;
//if you're accessing the api, append the base prefix globally here
else
return basePrefix + str;
}
}];