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

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);

Related

Why does the "append" method in javaScript does not return an array?

Here is an API call, which needs some values to return a specific set of products,
issue
"category_slug" has to be an array but for some reason, the API says it's not. what is the problem here?
const url = new URL(
"https://someApi/products"
);
let params = {
"limit": "10",
"page": "1",
"category_slug": ["shoes"]
};
// "limit" is "how many products in on one page".
// "page" is the fetched page with the specific "limited" products.
//issue
// "category_slug" is a specific products category, this has to be an array but for
// some reason, the API says it's not. what is the problem here?
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
//here I'm appending the specific value in {params} to the URL.
let headers = {
"Accept": "application/json",
"Content-Type": "application/json",
};
fetch(url, {
method: "GET",
headers: headers,
})
.then(response => response.json())
.then(json => console.log(json));
See, you expect too little and too much at the same time of such a beautiful thing as URLSearchParams.
Too little, because usually you can just pass the whole params object into its constructor without wasting time on keys, forEach, etc...
const url = new URL('https://example.com/');
const params = {
limit: 10,
page: 1
};
url.search = new URLSearchParams(params); // yes, that easy
console.log(url.toString());
// https://example.com/?limit=10&page=1
Too much, because URLSearchParams is not designed to work with arrays. When appended element is an array, it's just stringified:
const url = new URL('https://example.com/');
const params = {
slug: [1, 2, 3]
};
url.search = new URLSearchParams(params);
console.log(url); // https://example.com/?slug=1%2C2%2C3
In this case, slug param got 1,2,3 (result of [1, 2, 3].toString()) assigned to it (and all the commas were urlencoded - replaced by %2C sequence).
Your API might actually work with this, but there's a huge chance it expects array args to be passed in the following format:
https://example.com/?slug=1&slug=2&slug=3
... yet even this might not work, if API expects array args to be passed with [] appended to each key, like this:
https://example.com/?slug[]=1&slug[]=2&slug[]=3
So you'll have to check your API (it's hard to debug such things just by looking into crystal ball, you know...), take its flavor into account - and process your items separately. For example,
const url = new URL('https://example.com/');
const params = {
limit: 10,
page: 1
};
url.search = new URLSearchParams(params);
const slugs = [1, 2, 3];
url.search += ['', ...slugs.map(
slug => `category_slug[]=${encodeURIComponent(slug)}`)].join('&');
console.log(url.toString());

How to propertly pass query string parameters? Angular

I want to send an HTTP request with parameters via a query
Example:
URL: https://api/endpoint?d=1&value=2
To add params for your URL, you need to create the correct options, for example:
const options = { params: new HttpParams().set('value1', '1').set('value2', '2') };
return this.http.get(`${APP_BASE_URL}/endpoint`, options);
Before is an example, you can create a petition with params of many ways.
Check the documentation here
You can create an object and pass it as 2nd parameter in get method.
const url="example.com/data";
const parameters = {
'value1': 1,
'value2': 2
};
return this.httpClient.get(url, {
params: parameters
})
This will create your url like below:-
URL: https://api/endpoint?value1=1&value2=2

square brackets in query parameter keys

I need to GET data from an API that uses square brackets as part of the parameter name. I didn't write the API, so don't shoot the messenger!
Edit: I should have noted, this code will run on node (server-side), not in the browser.
I'm using Axios in Javascript, and this is my axios call:
axios.get(url, {params: {queryParams}})
.then(res => {
brands = res.data;
console.log(res.data);
})
.catch(error => {
console.log( '\n\n\n\n')
console.log(error);
});
The params are as follows. For brevity, I'm showing the three different formats I've tried (direct character, escaped and ASCII encoded), but in each attempt, I've passed the three parameters with the same format.
Set the query parameters
let queryParams = {
"tables": table,
"manifest": manifest,
"where[0][0]": field,
"where%5B0%5D%5B1%5D": "%3D",
"where\\[0\\]\\[2\\]": searchValue,
"ordery_by": "id%2C%20ASC",
"limit": "100",
"app": "json",
'client_key': authkey
}
In all cases, axios seems to transform the parameters into a javascript web token.
If, on the other hand, I concatenate the parameters to the URL as a string, the request works, and I get the data I expected.
let fullPath = url.concat(
"?tables=", table,
"&manifest=", manifest,
"&where%5B0%5D%5B0%5D=", field,
"&where%5B0%5D%5B1%5D=", "%3D",
"&where%5B0%5D%5B2%5D=", searchValue,
"&ordery_by=", "id%2C%20ASC",
"&limit=", "100",
"&app=", "json",
"&client_key=", authkey
)
While I have a workaround solution (as shown above), is there a way doing this with a proper parameters object?
If you are doing this in browser you could use the URLSearchParams() to iterate a human readable object and have it create the query string.
There is also a similar module available for Node
axios supports passing a URLSearchParams object as params argument also
let queryParams = {
"tables": 1,
"manifest": 2,
"where[0][0]": 3,
"where[0][1]": "=",
"where[0][2]": 4,
"ordery_by": "id,ASC",
"limit": "100",
"app": "json",
'client_key': 'abc'
}
const sParams = new URLSearchParams(Object.entries(queryParams));
console.log('query string')
console.log(sParams.toString())
console.log('sParam entries')
console.log(JSON.stringify([...sParams]))
.as-console-wrapper { max-height: 100%!important;top:0;}
Going a step further you can construct the full url with URL constructor
const url = new URL('https://myApi.com')
url.search = new URLSearchParams(Object.entries(queryParams));
console.log(url.href)

How to correctly use axios params with arrays

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)

How can I get HttpParams values as JSON object?

I'm using Angular 5 with HttpInterceptors.
I already know I can get each value I want from HttpParams via several methods.
Also - If I want to see all values , I can use the .toString() method
params = new HttpParams()
.set('page', '2')
.set('sort', 'name');
console.log(params.toString()); //Returns page=2&sort=name
But in my case I send json objects as parameters :
{
a:1 , b:[1,2,3] , c:[{...}]
}
I'm using interceptors to log the request parameters , but when I JSON.stringify(req.Params) , I get :
Params={
"updates": null,
"cloneFrom": null,
"encoder": {},
"map": {}
}
Which doesn't expose the values.
I don't want to see the parameters as a regular form post parameters -( it will be very unclear), but as an object as I've sent it.
Question:
How can I extract the parameters from the request object in the interceptor , but as json format :
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>
{
JSON.stringify( req.params) // <--- ?? doesn't yield the params.
}
If you don't like method toString() that returns an encoded string, where key-value pairs (separated by =) are separated by &s you can write your own method that will transform data stored in Map in some data you want to use.
For example:
const params = new HttpParams()
.set('page', '2')
.set('sort', 'name');
const paramsArray = params.keys().map(x => ({ [x]: params.get(x) }));
console.log(JSON.stringify(paramsArray));
It's similar to the approach that is used in toString method
https://github.com/angular/angular/blob/master/packages/common/http/src/params.ts#L177-L186
Ng-run Example
What you actually requested was a JSON Object. So this is how you get such an object:
const params = new HttpParams()
.set('page', '2')
.set('sort', 'name');
const paramsObject = params.keys().reduce((object, key) => {
object[key] = params.get(key)
return object
}, {})
console.log(paramsObject)
// And json if you really want
const json = JSON.stringify(paramsObject)

Categories

Resources