How to correctly use axios params with arrays - javascript

How to add indexes to array in query string?
I tried send data like this:
axios.get('/myController/myAction', { params: { storeIds: [1,2,3] })
And I got this url:
http://localhost/api/myController/myAction?storeIds[]=1&storeIds[]=2&storeIds[]=3
So, I should to get this url:
http://localhost/api/myController/myAction?storeIds[0]=1&storeIds[1]=2&storeIds[2]=3
What I should add in my params options to get this url?

You can use paramsSerializer and serialize parameters with https://www.npmjs.com/package/qs
axios.get('/myController/myAction', {
params: {
storeIds: [1,2,3]
},
paramsSerializer: params => {
return qs.stringify(params)
}
})

Without having to add more libraries and using ES6 you could write:
axios.get(`/myController/myAction?${[1,2,3].map((n, index) => `storeIds[${index}]=${n}`).join('&')}`);

Thanks so much the answer from Nicu Criste, for my case, the API requires params like this:
params: {
f: {
key: 'abc',
categories: ['a','b','c']
},
per_page: 10
}
Method is GET and this API requires the format is: API?f[key]=abc&f[categories][]=a&f[categories][]=b...
So I assigned the paramsSerializer of axios like this:
config.paramsSerializer = p => {
return qs.stringify(p, {arrayFormat: 'brackets'})
}
Install qs please go to this link
Read more about paramsSerializer in axios document
Edit format of params: Read more at qs stringifying document

In my case, I use ES6 array function.
array element make querystring use reduce function.
Object array also works.
const storeIds = [1,2,3]
axios.get('some url', {
params: {
storeIds: storeIds.reduce((f, s) => `${f},${s}`)
}
})

In my case, I am using someting like this
const params = array.map((v)=>{
return `p=${v}&`
})
Only concat params.join('') to the URL where you get data:
`url_to_get?${params.join('')`
In my back-end in ASP.net I receive this
[FromUri] string [] p

This answer is inspired by #Nicu Criste's answer.
But might be not related to the posted question.
The following code was used to generate the query params with repetitive keys which had been supplied with an object array.
Note: If you are a developer with bundlephobia, use the following approach with care: as with UrlSearchParams support varies on different browsers and platforms.
const queryParams = [{key1: "value1"}, {key2: "value2"}]
axios.get('/myController/myAction', {
params: queryParams,
paramsSerializer: params => {
return params.map((keyValuePair) => new URLSearchParams(keyValuePair)).join("&")
}
})
// request -> /myController/myAction?key1=value1&key2=value2

I rewrote the existing paramSerializer shipped in axios. The following snippet does the same serialization while putting indices between square brackets. I tried qs but it is not compatible with my python connexion backend (for JSON string parameters).
const rcg = axios.create({
baseURL: `${url}/api`,
paramsSerializer: params => {
const parts = [];
const encode = val => {
return encodeURIComponent(val).replace(/%3A/gi, ':')
.replace(/%24/g, '$')
.replace(/%2C/gi, ',')
.replace(/%20/g, '+')
.replace(/%5B/gi, '[')
.replace(/%5D/gi, ']');
}
const convertPart = (key, val) => {
if (val instanceof Date)
val = val.toISOString()
else if (val instanceof Object)
val = JSON.stringify(val)
parts.push(encode(key) + '=' + encode(val));
}
Object.entries(params).forEach(([key, val]) => {
if (val === null || typeof val === 'undefined')
return
if (Array.isArray(val))
val.forEach((v, i) => convertPart(`${key}[${i}]`, v))
else
convertPart(key, val)
})
return parts.join('&')
}
});

I got using "paramSerializer" a bit confuse. Before looking for the "right way" to use axios with array querystring on Google, I did following and got working:
var options = {};
var params = {};
for(var x=0;x<Products.length;x++){
params[`VariableName[${x}]`] = Products[x].Id;
}
options.params = params;
axios.get(`https://someUrl/`, options)...
It is going to create querystring parameters like:
VariableName[0]=XPTO,VariableName[1]=XPTO2
which the most webservers expected as array format

I know that this approach is not very good and I don't know the downsides it may have, but i tried this and it worked:
before making the request, prepare the params:
let params = '?';
for (let i = 0; i < YOUR_ARRAY.length; i++) { // In this case YOUR_ARRAY == [1, 2, 3]
params += `storeIds=${YOUR_ARRAY[i]}`; // storeIds is your PARAM_NAME
if (i !== YOUR_ARRAY.length - 1) params += '&';
}
And then make the request like so:
axios.get('/myController/myAction' + params)

In React I needed to use axios with a params in array. This was query param:
"fields[0]=username&fields[1]=id&populate[photo][fields][0]=url&populate[job][fields][1]=Job"
to send with axios, for that I installed by CLI
npm install qs Read more about qs
and declared
const qs = require('qs');
after
const query = qs.stringify({
fields: ['username', 'id'],
populate: {
photo: {
fields: ['url']
},
job: {
fields: ['Job']
}
}
}, {
encodeValuesOnly: true
});
and finally I called the axios like this:
axios.create({
baseURL: "http://localhost:1337/api/",
}).get(`/users?${query}`) // this parameter show all data
.then((response) => console.log(response.data))
.catch((err) => {
setError(err);
});

Basically, reading from docs https://axios-http.com/docs/req_config
paramsSerializer is an optional function, which we should use if the default serialization of params done by axios is not as expected. We can use serialization libraries (which I feel is best approach) to serialize in the params in the paramsSerializer function as per our needs.
Let's see an example.Suppose params is like ...
{
params: {
delay: 1,
ar:[1,2,3]
}
}
then you will get queryString like this ?delay=1&ar[]=1&ar[]=2&ar[]=3 when you make the request, but you might want like this
?delay=1&ar[0]=1&ar[1]=2&ar[2]=3 so in order to get query string as per our format. we can use qs https://www.npmjs.com/search?q=qs library and serialize our params in the paramsSerializer function as below
{
method: "GET",
params: {
delay: 1,
ar:[1,2,3]
},
paramsSerializer: (params) => {
return qs.stringify(params,{
encodeValuesOnly: true
});
}
},

This work it for me:
axios.get("/financeiro/listar",{
params: {
periodo: this.filtro.periodo + "",
mostrarApagados: this.filtro.mostrarApagados,
mostrarPagos: this.filtro.mostrarPagos,
categoria: this.filtro.categoria,
conta: this.filtro.conta
}
})

This was better for me:
axios.get('/myController/myAction', {
params: { storeIds: [1,2,3] + ''}
})

In my case, there was already jQuery implemented into my codebase. So I just used the predefined method.
jQuery.param(Object)

Related

How do I filter through API information to find a perfect match of a specific search param in React?

I have an API call returning 1 movie name at random... The code has it set up so it returns 1 movie name only.
I then have a second API call that uses that movie name in a second axios request to find streaming services available for this specific movie title.
My issue is, the second API call returns an array of 20 or so choices. For example, if I searched for 'Jaws' it delivers results for Jaws, all the other Jaws movies and any other movie with Jaws in the name.
My question is, how do I filter through this return information, to find a perfect match with the right movie title and just show that info? I hope you can help and sure it is going to be some filtering logic. Thankyou! I am new to React so trying to learn.
const optionsParams = { method: 'GET', url: 'https://mdblist.p.rapidapi.com/', params: [], headers: { 'X-RapidAPI-Host': 'mdblist.p.rapidapi.com', 'X-RapidAPI-Key': '384177d302msh9d8e58dffccp1bfa57jsnf3cea9fef042', }, }; axios .request({ ...optionsParams, params: { s: ${movieData.title}} }) .then(function (response) { console.log(response.data); const traktid = response.data.search.traktid; const traktidOptions = { ...optionsParams, params: { t: ${traktid}` }
};
axios.request(traktidOptions).then(function (response) {
const streamingServices = response.data.streams;
setStreamingState(streamingServices);
//console.log(streamingState);
console.log(response.data.streams)
let temporaryArray = [];
for (let i = 0; i < response.data.streams.length; i++){
temporaryArray.push(response.data.streams[i].name)
console.log(temporaryArray);
}
setStreamingState(streamingState => [...streamingState, `${temporaryArray}`])
if (streamingState) {
console.log(streamingState)
} else return false;
})
})`
Array methods are the perfect tool for iterating and organising array data.
In this case the Array.prototype.find() will help you look through your array and return a single item based on your criteria.
For example:
const yourArray = ["jaws", "not this jaws", "definitely not jaws"];
const found = yourArray.find(arrayItem => arrayItem === "jaws");
This is a simple example without objects, so you would just need to set the criteria based on an object property.

Axios - How not to add [] to the multi parameters?

Axios adds square brackets to the param if there are multiple params with an equal name. The problem is that I need not to include those brackets since I use Django Rest Framework and Django Filters.
How can I do that if I use this notation?
axios.get(list_url, {params: {somelist:[1,2,3]}})
I don't want url/?somelist[]=1&somelist[]=2&somelist[]=3
Instead I want url/?somelist=1&somelist=2&somelist=3
Try to do it using paramsSerializer's indexes:null in axios config
axios.get(someurl, {
params: {
foo: [1, 2, 3]
},
paramsSerializer: {
indexes: null
}
});
I got this from here https://www.npmjs.com/package/axios#axios-api
screenshot with attributes of paramsSerializer
You can do like this with URLSearchParams (a native object that exists in browsers and in Node.js as well):
const axios = require('axios');
const { URLSearchParams } = require('url');
var params = new URLSearchParams();
params.append("q", 'test');
params.append("foo", 2);
params.append("foo", 11);
var request = {
params: params
};
axios.get('http://google.com/', request).then(x => x.request).then(console.log);

graphql passing dynamic data to mutation

haven't used graphql or mongodb previously. What is the proper way to pass objects for the update mutation?
Since the only other way i see to pass multiple dynamically appearing parameters is to use input type which is appears to be a bit ineffective to me (in terms of how it looks in the code, especially with bigger objects), i just pass the possible values themselves. however in this case i need to dynamically construct updateObject, which again, going to get messy for the bigger models.
for example now i did:
Mutation: {
updateHub: async (_, { id, url, ports, enabled }) => {
const query = {'_id': id};
const updateFields = {
...(url? {url: url} : null),
...(ports? {ports: ports} : null),
...(enabled? {enabled: enabled} : null)
};
const result = await HubStore.findByIdAndUpdate(query, updateFields);
return {
success: !result ? false : true,
message: 'updated',
hub: result
};
}
}
any advise on the better way to handle this?
thanks!
It appears your code could benefit from using ES6 spread syntax -- it would permit you to deal with an arbitrary number of properties from your args object without the need for serial tertiary statements.
Mutation: {
updateHub: async (_, { id, ...restArgs } ) => {
const query = {'_id': id};
const updateFields = { ...restArgs };
const result = await HubStore.findByIdAndUpdate(query, updateFields);
return {
success: !result ? false : true,
message: 'updated',
hub: result
};
}
}
If for some reason you need to explicitly set the undefined properties to null in your object, you could possibly use some a config obj and method like defaults from the lodash library as shown below:
import { defaults } from 'lodash';
const nullFill = { url: null, ports: null, enabled: null }; // include any other properties that may be needed
Mutation: {
updateHub: async (_, { id, ...restArgs } ) => {
const query = {'_id': id};
const updateFields = defaults(restArgs, nullFill);
const result = await HubStore.findByIdAndUpdate(query, updateFields);
return {
success: !result ? false : true,
message: 'updated',
hub: result
};
}
}
Also, FWIW, I would consider placing the dynamic arguments that could be potentially be updated on its own input type, such as HubInput in this case, as suggested in the graphql docs. Below I've shown how this might work with your mutation. Note that because nothing on HubInput is flagged as requird (!) you are able to pass a dynamic collection of properties to update. Also note that if you take this appraoch you will need to properly destructure your args object initially in your mutation, something like { id, input }.
input HubInput {
url: String
ports: // whatever this type is, like [String]
enabled: Boolean
// ...Anything else that might need updating
}
type UpdateHubPayload {
success: Boolean
message: String
hub: Hub // assumes you have defined a type Hub
}
updateHub(id: Int, input: HubInput!): UpdateHubPayload

Axios conditional parameters

axios.get(globalConfig.FAKE_API, {
params: {
phone: this.phone,
mail: this.mail
},
})
.then((resp) => {
this.req = resp.data
})
.catch((err) => {
console.log(err)
})
Is there any way I can make conditional parameters when doing GET / POST requests with Axios? For example, if my mail parameter is empty, i won't send an empty parameter, like: someurl.com?phone=12312&mail=
Either you can maintain a variable of params before making a request and only add key if it has data like:
const params = {}
if (this.mail) { params.mail = this.mail }
or you can do like below, we write normal js code between ...() the parenthesis. We are adding a ternary condition.
axios.get(globalConfig.FAKE_API, {
params: {
phone: this.phone,
...(this.mail ? { mail: this.mail } : {})
},
})
Reghav Garg's idea looks neat at first glance, but with more than one optional parameter, I'm afraid it will get messy.
You could simply use one of the common utility libraries like underscore or lodash and utilize their filter function:
const allParams = {
mail: this.mail,
phone: this.phone,
// ...
};
axios.get(globalConfig.FAKE_API, {
// 'Pick' takes only those elements from the object
// for which the callback function returns true
//
// Double negation will convert any value to its boolean value,
// so null becomes false etc.
params: _.pick(allParams, (value, key) => { return !!value; })
})

Use fetch to send get request with data object

I'm using Fetch (Fetch API) in a project and I would like to, for consistence purposes, create a function that receives all the parameters such as method, url and data and creates the correct request, depending if it's a GET or a POST request.
Is it possible, using Fetch, to send a data object that for the GET request, converts data into and string with the parameters and if it is a POST request, it just sends the data object in the body?
It would look like this:
fetch ('/test', {
method: 'GET',
data: {
test: 'test'
}
});
This doubt was inspired by this jQuery ajax behaviour:
$.ajax({
url: '/test',
method: 'GET',
data: {
test: 'test'
}
});
This would produce this request:
'/test/?test=test'
If I pass the data object as normal in the fetch constructor for a
GET request, would it send the request like the example I gave
'/test/?test=test'
If you want to add query string to a fetch request :
From the SPEC
var url = new URL("https://a.com/method"),
params = {a:1, b:2}
Object.keys(params).forEach(key => url.searchParams.append(key, params[key]))
fetch(url)
this will produce a request :
you could either use the Url class:
var url = new URL("/test/")
Object.keys({test: 'test', a: 1}).forEach(key => url.searchParams.append(key, params[key]))
fetch(url);
or parse the string yourself, if you want wider browser support:
var params = {test: 'test', a: 1},
qs = Object.keys(params).reduce(function(_qs, k, i){ return _qs + '&' + k + '=' + params[k]; }, '').substring(1);
console.log(qs)
I'll show you snippets for creating query with and without using URLSearchParams.
The code will be in typescript for the if you're using it. if not, just remove types, it will work in the same way.
Simple solution (URLSearchParams)
/**
* Creates query from given object
* - It doesn't work with deep nesting
* - It doesn't remove empty fields
* #returns `state1=6&state2=horse` without `?`
*/
function createQuery(queryObject?: Record<string | number, unknown> | null): string {
if (queryObject == null) return ""
// Typescript: The `as ...` expression here is ok because `URLSearchParams` will convert non-string by itself
const searchParams = new URLSearchParams(queryObject as Record<string, string>)
return searchParams.toString()
}
Solving problems solution (URLSearchParams)
/**
* Creates query from given object
* - It doesn't work with deep nesting
* - Removes empty fields
* #returns `state1=6&state2=horse` without `?`
*/
function createQuery(queryObject?: Record<string | number, unknown> | null): string {
if (queryObject == null || !Object.keys(queryObject).length) return ""
for (const key in queryObject) {
if (Object.prototype.hasOwnProperty.call(queryObject, key)) {
const value = queryObject[key]
// Use `!value` expression if you want to delete values as `0` (zero) and `""` (empty string) too.
if (value == null) delete queryObject[key]
}
}
const searchParams = new URLSearchParams(queryObject as Record<string, string>)
return searchParams.toString()
}
No URLSearchParams solution
/**
* Creates query from given object
* - Supports prefixes
* - Supports deep nesting
* - Removes empty fields
* #returns `state1=6&state2=horse` without `?`
*/
function createQuery(queryObject?: Record<string | number, unknown> | null, keyPrefix?: string): string {
if (queryObject == null || !Object.keys(queryObject).length) return ""
keyPrefix = keyPrefix ? (keyPrefix + "_") : ""
const queryKeys = Object.keys(queryObject)
const queryArray = queryKeys.map(key => {
const value = queryObject[key]
if (value) {
if (isDictionary(value)) {
return createQuery(value, keyPrefix + key + "_")
}
return keyPrefix + encodeURIComponent(key) + "=" + encodeURIComponent(String(value))
}
return ""
})
return queryArray.filter(Boolean).join("&")
}
isDictionary Helper
I used isDictionary helper here too, you can find it here
Usage
You need to put ? in the beginning of your endpoint plus createQuery
fetch("/test?" + createQuery({ foo: 12, bar: "#user->here", object: { test: "test", bird: { super: { ultra: { mega: { deep: "human" }, shop: 7 } }, multiple: [1, 2, 3] } } }))
Result
foo=12&bar=%40user-%3Ehere&object_test=test&object_bird_super_ultra_mega_deep=human&object_bird_super_ultra_shop=7&object_bird_multiple=1%2C2%2C3
or
foo: 12
bar: #user->here
object_test: test
object_bird_super_ultra_mega_deep: human
object_bird_super_ultra_shop: 7
object_bird_multiple: 1,2,3
Conclusion
We got different snippets you can choose from depending on your goals.

Categories

Resources