Change query string parametesr of JavaScript requests - javascript

Is there a way to change the query string of JavaScript-induced requests? I want to add "&myParam=myValue" to any request sent by my HTML/JS application.

I don't think there's anything built in that lets you do that.
In my apps, I always have a central function XHR goes through so I have a single point to do things like this. If you don't have that or need to intercept calls from 3rd party libs:
You could wrap XMLHttpRequest.open to handle the XHR ones:
var originalOpen = XMLHttpRequest.open;
XMLHttpRequest.open = function() {
var args = Array.prototype.slice.call(arguments);
args[0] += (args[0].indexOf("?") == -1 ? "?" : "&") + "myParam=" + encodeURIComponent("myValue");
return originalOpen.apply(this, args);
};
...and then similar for fetch. But it seems brittle.
Alternately, you might look at using a cookie for the parameter, as the browser will add the cookie to the requests. (That assumes the requests are going to an origina you can add cookies for in your code.)

You could use partial application to lock in defaults when you declare your fetch function and essentially decorate the standard call that will merge your defaults and the passed params.
const fetchFactory = defaults => (url, data) => {
// make a copy of the defaults
const params = Object.assign({}, defaults)
// assign the passed in data with the defaults
params.body = JSON.stringify(Object.assign(params.body, data))
// call fetch with the params
return fetch(url, params)
}
// create a default for POST using the factory
const postFetch = fetchFactory({
method: 'post',
headers: {
'x-requested-with': 'fetch',
'Authorization': 'basic:' + btoa('a secret')
},
body: {
myParam: 'value'
}
})
// now you can call your function
postFetch('http://somewhere.com', {
one: 1,
two: 2
})
.then(respone => response.json())

It seems to me that you are asking how to set/edit URL parameters in http requests. Something quite similar has been asked here: here
If you are using XMLHttpRequest then the accepted answer in the link should work perfectly. The two key things the note are
the url parameters are simply a javascript object that you convert
into a JSON string. This happens through JSON.stringify({ myParam:
'hi'});
the question/answer linked are making post requests but you
may not want to make that request as well, I suggest doing some
research about which HTTP request method you want -
https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html

Related

JS - Getting either text or JSON with Fetch API

I am moving over from jQuery AJAX requests to the new Fetch API (nothing against jQuery, I still have it in my site, but Fetch looks - according to Jake Archibald and David Walsh and also IMHO - to be the new way of sending async requests).
As such, with jQuery, I had the following function (more or less):
function ajaxCall(type, url, data) {
return $.ajax({
type: type,
url: url,
data: data,
})
.fail(function(xhr, status, errorThrown) {
// Do fail stuff
})
.always(function(xhr, status) {
// Do always stuff
});
}
// Later...
var myAjax = ajaxCall(myType, myUrl, myData);
myAjax.done(function(xhr) {
// Do done stuff
});
This way, I could have one function be called to handle any and all ajax requests I could ever need (for the most part at least...). Note that I do not declare a dataType, as I use jQuery's intelligent guess. This way my server can send me whatever response and I could handle it (probably a smarter way to do this would be to pass another parameter with the data type - in the case the "intelligent guess" goes wrong, but this was the way I set it up).
I am now trying to recreate the above with the new Fetch API. What I have so far currently looks like this:
function fetchCall(url, method, body) {
// This if statement is supposed to handle
// query selectors (which in GET requests go in the url)
// on GET requests - as opposed to POST req's which go in the body
if (method === 'GET') {
var data = body;
url = new URL(url, location.protocol + '//' + location.host + '/');
Object.keys(data).forEach(key => url.searchParams.append(key, data[key]));
body = undefined;
}
return fetch(url, {
method: method,
body: body
}).then(function(res) {
if (res.ok) return res;
throw new Error('Server error. Status code: ', res.status);
}).catch(function(err) {
console.log(err);
});
}
// Later...
var myFetch = fetchCall(myUrl, myMethod, myBody);
myFetch.then(function(res) {
console.log(res);
});
The problem I am running into is that if res.ok return res; does not state what type of response it is (i.e. res.json(), res.blob(), res.text(), etc.).
Thus, I am wondering how to set up a dynamic way of setting the type of response body. Is this even possible at the Fetch API's current state of development? Is it just that there is something I am not duplicating in MDN?
After messing around with this, I also realized I could make it always set to return res.text(); and the if the call is supposed to be JSON, use JSON.parse(response);, but I do want it to be dynamic. What if I end up wanting to return a blob()?
So, as far as the conversation has reached, there is a way to understand what type of content has been received, with two remarks:
Typically you have to always know and expect exact content type, and a universal solution is rather odd in case of fetching from a certain remote endpoint, and
The Content-Type header is what will tell you the type of content received, but the server may send a wrong header, which is very unusual to happen and therefore is negligible.
The Response object has header property that is (kind of) a Map, so you can use its get method to get a value by key.
The easiest and cleanest way to check if the returned value is a certain MIME type you expect is by using a regular expression:
// replace url with the actual API endpoint URL
fetch(url).then(response => {
const contentType = response.headers.get('Content-Type'); // -> "text/html; charset=utf-8"
if (/text\/html/i.test(contentType)) {
// do something when the Content-Type is text/html
} else if (/application\/json/.test(contentType)) {
// do something when the Content-Type is application/json
}
// and so on, for every Content-Type you need.
}).catch(error => {
// do something when error happens
});

Why can I not use new XMLHttpRequest on my amazon server?

So bear with me because I feel that I've tried everything there is to try. I'm really new to JavaScript and I've primarily worked with C/C++ before and I am still a novice with respect to those languages as well. I tried to create a page on my aws services (ec2) server that when accessed with a get request of a URL it would use my server-side API key and return JSON data that it requested from the URL given. I was working with the League of Legends API and with NodeJs using forever start *.js, handlebars and express JavaScript as well.
I feel that it is important to mention that while this issue arose doing an assignment for a class I have since completed the assignment without including that functionality.
I tried to do this as both synchronous and asynchronous and it didn't work for me. I feel that it is because using var foo = new XMLHttpRequest is not the correct way to send a get request from a server to another server. When I tried to find a better way to do this using nodejs I could not find anything which made sense to me or that I could understand.
Please let me know why this is wrong/ why this breaks and how I can make it not break or do it properly. I couldn't find any similar stack overflow questions despite a few hours of struggling and searching.
app.get('/test',function(req,res){
//if(url == undefined){
var url = "https://na.api.pvp.net/api/lol/na/v1.4/summoner/by-name/RiotSchmick";
//}
var KEY= "REDACTED_FOR_POST";//note I have a functional api
//key that I can correctly use to view data through a browser get request.
var local = new XMLHttpRequest();//this line prevents this page from runnning
local.open("GET", "https://na.api.pvp.net/api/lol/na/v1.4/summoner/by-name/RiotSchmick?api_key=REDACTED_FOR_POST", false);
//RiotSchmick is used as an example "summoner" name in quick start
local.send(null);
var content = {};//holder for handlebars
content.text = local.responseText;//I expected this to have a string form JSON.
res.render('buffer.handlebars', content);
//buffer.handlebars is one line: {{text}} and properly prints data when
//content.text is assigned to a constant such as "hello"
})
Thanks for help and your time.
Unless you are using something like https://github.com/driverdan/node-XMLHttpRequest there's no XMLHttpRequest in node. XMLHttpRequest is an object that only exists in browsers.
You have to require http to make http requests in node.
var http = require('http');
Then you can do something like that (taken from the docs):
var postData = querystring.stringify({
'msg' : 'Hello World!'
});
var options = {
hostname: 'www.google.com',
port: 80,
path: '/upload',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': postData.length
}
};
var req = http.request(options, (res) => {
console.log(`STATUS: ${res.statusCode}`);
console.log(`HEADERS: ${JSON.stringify(res.headers)}`);
res.setEncoding('utf8');
res.on('data', (chunk) => {
console.log(`BODY: ${chunk}`);
});
res.on('end', () => {
console.log('No more data in response.')
})
});
req.on('error', (e) => {
console.log(`problem with request: ${e.message}`);
});
// write data to request body
req.write(postData);
req.end(
);

Angular2 easiest way to cache HTTP responses [duplicate]

This question already has answers here:
What is the correct way to share the result of an Angular Http network call in RxJs 5?
(22 answers)
Closed 6 years ago.
I have a page which makes http requests to the same location, just with different parameters depending on what the user wants. So my code looks something like this:
this.http.post( //I am open to POST methods or GET methods as I have security in the back to prevent malicious writes.
'http://192.168.1.45:3000/mylocation',
'p1=' + param1 + '&p2=' + param2,
{headers: headers}
)
In JQuery for example you have build into the framework a cache attribute which caches automatically and is very easy to implement:
$.ajax({
cache: true,
//other options...
});
Does Angular2 have something similar to this? I would like to cache these dynamic responses as long as the user is in the application. So if a user requests the same url with the same parameters then it would just grab it from the cache, and if the params were never yet used then it would make the network call.
I could not find anything in the Angular2 docs in the request options:
https://angular.io/docs/js/latest/api/http/RequestOptions-class.html
Cache the data, and if cached data is available return this, otherwise make the HTTP request. If you want to reuse for different requests (parameters) you can adjust to store the references in an array instead.
getData() {
if(this.data) {
// if `data` is available just return it as `Observable`
return Observable.of(this.data);
else if(this.observable) {
// if `this.observable` is set then the request is in progress
// return the `Observable` for the ongoing request
return this.observable;
} else {
// create the request, store the `Observable` for subsequent subscribers
this.observable = this.http.get('/someUrl')
.map(res => res.json())
.do(val => {
this.data = val;
// when the cached data is available we don't need the `Observable` reference anymore
this.observable = null;
})
// make it shared so more than one subscriber can get the result
.share();
return this.observable;
}
}

Generating a unique value for a header on each $http call

I have a fairly large AngularJS application and for logging purposes, I am being tasked with adding a custom header to all of our HTTP requests from the app that contain a unique ID for each request. This really is more valuable to our API calls, but as of now I'm just aiming for all requests (getting templates, styles, etc.)
I am currently using a provider decorator to patch each of the methods exposed by $HttpProvider (implementation based on this post), to attempt to call the ID method each time one of those $http methods runs, and add the appropriate header:
module.config([
'$provide',
function ($provide) {
$provide.decorator('$http', [
'$delegate',
function addUniqueIdHeader($http) {
var httpMethods = ['get', 'post', 'put', 'patch', 'delete'];
/**
* Patched HTTP factory function that adds a request ID each time it is called.
* #param {string} method - A valid HTTP method.
* #return {function} A function that sets various request properties.
*/
function httpWithHeader(method) {
return function(url, data, config) {
config = config || {};
config.headers = config.headers || {};
// the magic
config.headers['My-Custom-Header'] = aUniqueId();
data = data || {};
config.method = method.toUpperCase();
// return `$http` with a modified config, adding the URL and data passed in
// `_.extend()` is lodash, not underscore.
return $http(_.extend(config, {
url: url,
data: data
}));
}
};
// back up the orginal methods and patch
_.each(httpMethods, function (httpMethod) {
var backupMethod = '_' + httpMethod;
$http[backupMethod] = $http[httpMethod];
$http[httpMethod] = httpWithHeader(httpMethod);
});
return $http;
}
]);
}
]);
What I have so far works some of the time, but doesn't seem to work consistently (some API requests have it, some don't). I should note that we are using a quite old version of AngularJS (1.0.6) and no, I cannot upgrade (as much as I would love to) so the use of request interceptors is not possible. Additionally, we use Restangular for the majority of our API interactions.
My question is, is using a provider decorator the right way to go? If so, is there a cleaner way to add the header without having to override/patch each individual HTTP method that I'm overlooking?
Thanks in advance.
I ended up solving my issue by utilizing Restangular's request interceptors, since the version of Angular we use doesn't have them baked in.

Add access_token in backbone.js

In my REST server, it's requiring the access_token to be present in every request. i.e. in POSTing data, access_token needs to be submitted together with the attributes.
How do I configure backbone.js to add access_token to every GET, PUT, POST and DELETE request?
Thanks.
Okay, I think I found a way how to do it in jQuery.
$.ajaxSetup (
{
data: { access_token: 'my_access_token' }
}
);
Backbone uses jQuery/Zepto for AJAX requests, so you can use the functionality available in those libraries.
To add custom headers to all XHR calls made by jQuery, you can use the jQuery.ajaxSend event, which is triggered before every ajax request, and modify the jqXHR it receives as an argument.
Edit based on OP's comments:
Probably the simplest way to modify the sent data is to override the Backbone.sync function. You could wrap the native implementation, and add the required property there:
var nativeSync = Backbone.sync;
Backbone.sync = function (method, model, options) {
//for POST/PUT requests, add access token to the request
if(model && (method === 'create' || method === 'update')) {
var data = _.extend(model.toJSON(), {
access_token: 'token'
});
options.data = JSON.stringify(data);
}
//call the native Backbone.sync implementation
nativeSync(method, model, options);
};

Categories

Resources