GET with query string with Fetch in React Native - reactjs

I am making a request like this:
fetch("https://api.parse.com/1/users", {
method: "GET",
headers: headers,
body: body
})
How do I pass query string parameters? Do I simply add them to the URL? I couldn't find an example in the docs.

Your first thought was right: just add them to the URL.
Remember you can use template strings (backticks) to simplify putting variables into the query.
const data = {foo:1, bar:2};
fetch(`https://api.parse.com/1/users?foo=${encodeURIComponent(data.foo)}&bar=${encodeURIComponent(data.bar)}`, {
method: "GET",
headers: headers,
})

Short answer
Just substitute values into the URL like this:
const encodedValue = encodeURIComponent(someVariable);
fetch(`https://example.com/foo?bar=${encodedValue}`);
Longer answer
Yes, you just need to add the query string to the URL yourself. You should take care to escape your query string parameters, though - don't just construct a URL like
`https://example.com/foo?bar=${someVariable}`
unless you're confident that someVariable definitely doesn't contain any &, =, or other special characters.
If you were using fetch outside of React Native, you'd have the option of encoding query string parameters using URLSearchParams. However, React Native does not support URLSearchParams. Instead, use encodeURIComponent.
For example:
const encodedValue = encodeURIComponent(someVariable);
fetch(`https://example.com/foo?bar=${encodedValue}`);
If you want to serialise an object of keys and values into a query string, you could make a utility function to do that:
function objToQueryString(obj) {
const keyValuePairs = [];
for (const key in obj) {
keyValuePairs.push(encodeURIComponent(key) + '=' + encodeURIComponent(obj[key]));
}
return keyValuePairs.join('&');
}
... and use it like this:
const queryString = objToQueryString({
key1: 'somevalue',
key2: someVariable,
});
fetch(`https://example.com/foo?${queryString}`);

Here's an es6 approach
const getQueryString = (queries) => {
return Object.keys(queries).reduce((result, key) => {
return [...result, `${encodeURIComponent(key)}=${encodeURIComponent(queries[key])}`]
}, []).join('&');
};
Here we're taking in a queries object in the shape of key: param
We iterate and reduce through the keys of this object, building an array of encoded query strings.
Lastly we do a join and return this attachable query string.

I did a small riff on Mark Amery's answer that will pass Airbnb's eslint definitions since many teams seem to have that requirement these days.
function objToQueryString(obj) {
const keyValuePairs = [];
for (let i = 0; i < Object.keys(obj).length; i += 1) {
keyValuePairs.push(`${encodeURIComponent(Object.keys(obj)[i])}=${encodeURIComponent(Object.values(obj)[i])}`);
}
return keyValuePairs.join('&');
}

My simple function to handle this:
/**
* Get query string
*
* #param {*} query query object (any object that Object.entries() can handle)
* #returns {string} query string
*/
function querystring(query = {}) {
// get array of key value pairs ([[k1, v1], [k2, v2]])
const qs = Object.entries(query)
// filter pairs with undefined value
.filter(pair => pair[1] !== undefined)
// encode keys and values, remove the value if it is null, but leave the key
.map(pair => pair.filter(i => i !== null).map(encodeURIComponent).join('='))
.join('&');
return qs && '?' + qs;
}
querystring({one: '##$code', two: undefined, three: null, four: 100, 'fi###ve': 'text'});
// "?one=%23%40%24code&three&four=100&fi%23%23%40ve=text"
querystring({});
// ""
querystring('one')
// "?0=o&1=n&2=e"
querystring(['one', 2, null, undefined]);
// "?0=one&1=2&2" (edited)

Yes you should, there are a few classes in JS, that can help you a handy one is https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams
e.g. if you had the params in a javascript object say
let params = {one: 'one', two: 'two'}
you could say this function
let queryString = new URLSearchParams()
for(let key in params){
if(!params.hasOwnkey())continue
queryString.append(key, params[key])
}
then you can get your nicely formatted query string by saying
queryString.toString()

The accepted answer works, but if you have more params than one it doesn't generalize. I suggest the following approach, which also handles array parameters:
let route = 'http://test.url.com/offices/search';
if (method == 'GET' && params) {
const query = Object.keys(params)
.map((k) => {
if (Array.isArray(params[k])) {
return params[k]
.map((val) => `${encodeURIComponent(k)}[]=${encodeURIComponent(val)}`)
.join('&');
}
return `${encodeURIComponent(k)}=${encodeURIComponent(params[k])}`;
})
.join('&');
route += `?${query}`;
}

Related

query string params as array of objects - issues javascript

I've got a problem!
I need to get in query string params encode something like this:
filters[0].columnName: createdBy
filters[0].value: ew
filters[0].operation: contains
filters[1].columnName: title
filters[1].value: eweqw
filters[1].operation: endsWith
but I just get nothing but...
filters: [name,"contains", o'}]
my code is:
const getQueryStringFilters = (): string => {
let filter = filters
.reduce((acc, { columnName, value }) => {
acc.push(encodeURIComponent(`[${columnName},"contains", ${value}'}]`));
return acc;
}, [])
.join(',"and",');
if (filters.length > 1) {
filter = `[${filter}]`;
}
return filter;
};
and I am using devexpress react-grid :( cannot find solution... somebody could help me out?

Next.js router create query string and query string array

I use Next.js on my project and I need to make a dynamic query string. I use this code:
const createQuery = (filter) => {
let currentPath = router.pathname;
let filterSize = Object.keys(filter).length;
filterSize != 0 ? (currentPath += "?") : null;
Object.keys(filter).map(function (key, index) {
currentPath +=
key + "=" + filter[key] + (index === filterSize - 1 ? "" : "&");
});
router.push(currentPath);
};
It works but I don't send an array to query string. How can I do this? Also, ss there an easier way to create a query string in Next.js?
You can use URLSearchParams to simplify your code
const params = new URLSearchParams({
var1: "value",
var2: "value2",
arr: "foo",
});
console.log(params.toString());
//Prints "var1=value&var2=value2&arr=foo"
You can easily pass dynamic query strings using nextjs/router
Router.push accepts query as an object which will be converted to query parameters.
for example:
Router.push({
pathname: currentPath,
query: {
page: 1,
skip: 10
}
})
// results into currentPath?page=1&skip=10

AWS GraphQL JSON string formatting

I'm attempting to create an object value to pass into DynamoDB using AWS AppSync and GraphQL. I'm very close to what I need but I'm stumbling on nested JSON.
Let's say I have an array:
let officers = [{"id":"0","IgRole":"Role1","IgName":"testname1","IgEmail":"testemail1","IgPhone":"testphone1","IgStart":"teststart1","IgEnd":"testend1"},
{"id":"1","IgRole":"Role2","IgName":"testname2","IgEmail":"testemail2","IgPhone":"testphone2","IgStart":"teststart2","IgEnd":"testend2"}]
I now want to create an object with each of the array values as a child object so, I do this:
for (let i in officers) {
officersJson['"' + officers[i].IgRole + '"'] = '{"Name":"' + officers[i].IgName + '","Email":"' + officers[i].IgEmail + '","Phone":"' + officers[i].IgPhone + '","Date commenced":"' + officers[i].IgStart + '","Date to end":"' + officers[i].IgEnd + '"}';
}
Here are the results:
Object {
"Role1": "{'Name':'testname1','Email':'testemail1','Phone':'testphone1','Date commenced':'teststart1','Date to end':'testend1'}",
"Role2": "{'Name':'testname2','Email':'testemail2','Phone':'testphone2','Date commenced':'teststart2','Date to end':'testend2'}"
}
I think the problem is that the each entire key / value is not in string format. If you look at
"Role1": "{......
you can see that the string breaks.
and this is the response from AWS:
Variable 'Officers' has an invalid value. Unable to parse {\"Role1\"={\"Nam
See the = sign
How can I format the object into a complete JSON string? I was fairly pleased I managed to get anywhere near the format I needed but this last bit has me stumped.
Finally worked it out. I needed a slightly different approach. Posting it in case it helps anyone else:
Firstly I created an array of roles, as this will be the keys for the value objects:
for (let i in officers) {
roles.push(officers[i].IgRole);
}
I then created a new array.
let arrOfficers = [];
for (let i in officers) {
arrOfficers.push(officers[i]);
}
I then use a function to create objects from an array:
function groupBy(objectArray, property) {
return objectArray.reduce(function (acc, obj) {
let key = obj[property];
if (!acc[key]) {
acc[key] = [];
}
acc[key].push(obj);
return acc;
}, {});
}
let newresult = groupBy(arrOfficers, "IgRole");
Finally I create my object and then stringify it:
let officersJson = {};
for (let i in roles) {
officersJson[roles[i]] = newresult[roles[i]][0];
}
theObjectIwant = JSON.stringify(officersJson)

Firestore - Simple full text search solution

I know that firestore doesn't support full text search and it giving us solution to use third party services. However I found a simple solution to simple "full text search" and I think this might help others who doesn't want to use third party services as me for such a simple task.
I'm trying to search for company name which is saved in firestore collection under my companyName which can be in any format for example "My Awesome Company". When adding new company with companyName or updating a value in companyName I'm also saving searchName with it which is the same value as company name but in lower case without spaces
searchName: removeSpace(companyName).toLowerCase()
removeSpace is my simple custom function which remove all spaces from a text
export const removeSpace = (string) => {
return string.replace(/\s/g, '');
}
That turns our company name to myawesomecompany which is saved in searchName
Now I've got a firestore function to search for company which indexing through searchName and returning companyName. Minumum search value is a searched value without last character and maximum search value is a searched value with added "zzzzzzzzzzzzzzzzzzzzzzzz" transformed to lower case. That means if you search for My Aw then min value will be mya and max value will be myawzzzzzzzzzzzzzzzzzzzzzzz
exports.handler = ((data) => {
const searchValue = data.value.replace(/\s/g, '').toLowerCase()
const minName = searchValue.substr(0, searchName.length-1)
const maxName = searchValue + "zzzzzzzzzzzzzzzzzzzzzzzz"
let list = []
const newRef = db.collection("user").where("profile.searchName", ">=", minName).where("profile.searchName", "<=", maxName)
return newRef.get()
.then(querySnapshot => {
querySnapshot.forEach(doc => {
list.push({ name: doc.data().profile.companyName})
})
return list
})
})
I didn't have time to fully test it but so far it works without any problems. Please let me know if you spot anything wrong with it. Now the question is
Is "z" character the highest value character in firestore or is there any other more decent way to add into the search value maximum amount without adding "zzzzzzzzzzzzz"?
I like your decision to preprocess the text so that it can be queried, but you could provide for a more flexible search by storing lowercase keywords with the users and searching those. In other words, transform:
"My Awesome Company"
to...
{ my: true, awesome: true, company: true }
...and test against that.
When adding/updating the property:
// save keywords on the user
let keywords = {}
companyName.split(' ').forEach(word => keywords[word.toLowerCase()] = true)
When querying:
let searchKeywords = userInputString.split(' ').map(word => word.toLowerCase())
let collection = db.collection("user")
searchKeywords.forEach(keyword => {
collection = collection.where(`keywords.${keyword}` , '==' , true);
});
With a little modification of previous answer I have made another simple text search. I'm saving keyword to an array instead of saving it in object like this
nameIndex: textIndexToArray(companyName)
where textIndexToArray is my custom function
export const textIndexToArray = (str) => {
const string = str.trim().replace(/ +(?= )/g,'')
let arr = []
for (let i = 0; i < string.trim().length; i++) {
arr.push(string.substr(0,i+1).toLowerCase());
}
return arr
}
which transfer a text into array. For example
"My Company"
will return
[m, my, my , my c, my co, my com, my comp, my compa, my compan, my company]
with nameIndex saved in firestore we can simply query the data thorough nameIndex and return companyName
exports.handler = ((data) => {
const searchValue = data.value.toLowerCase()
let list = []
const newRef = db.collection("user").where("nameIndex", "array-contains", searchValue)
return newRef.get()
.then(querySnapshot => {
querySnapshot.forEach(doc => {
list.push({ name: doc.data().companyName, })
})
return list
})
})

FlowRouter is not recognized inside of an apollo (graphql) query

I’m having a problem when using react-apollo with FlowRouter (in a meteor project). This is my graphql query (it is supposed to update each 5 seconds):
#graphql(myQuery, {
options: {
pollInterval: 5000,
variables: {
userId: FlowRouter.getQueryParam('r'),
registerToken: FlowRouter.getQueryParam('registerToken')
}
},
})
export const default class MyComponent;
If I hard-coding the userId and registerToken arguments, the query works just fine.
So I guess the problem here is that these FlowRouter.getQueryParam() functions return undefined (even though I'm on client side). They work well if I call them inside of MyComponent or the browser console.
Is this code running on page load? I don't see why, but maybe getQueryParam is always undefined on page load? (Or you could parse location.href)
If so, it's reactive, so you could wait until it has a value, and then start the query:
Tracker.autorun(c =>
if (FlowRouter.getQueryParam('r')) {
// do query
c.stop()
}
)
Based on Loren's answer, I omitted the FlowRouter.getQueryParam() functions and used pure JavaScript instead (copied from this SO question):
function getParameterByName(name, url) {
if (!url) {
url = window.location.href;
}
name = name.replace(/[\[\]]/g, "\\$&");
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, " "));
}
Usage:
// query string: ?foo=lorem&bar=&baz
var foo = getParameterByName('foo'); // "lorem"
var bar = getParameterByName('bar'); // "" (present with empty value)
var baz = getParameterByName('baz'); // "" (present with no value)
var qux = getParameterByName('qux'); // null (absent)
Everything's working now !

Resources