Axios is an easy and widely used when we talk about fetching data. But have you ever had problems with multi query params?
Let's check how to do it properly then! :)
QueryStrings
Working with QueryStrings, in general, can be an easy task, but sometimes we can face more specific situations that make the game a little bit more tricky.
Okay, but what the heck is a QueryString??
You may have seen some URLs that have the following format:
https://www.yourdomain.com/user?id=3
QueryStrings are part of the URL that contain an information that helps the backend to choose what it will be searching for in the database.
The example above shows a GET method searching for user with id equals to 3.
More than one param
Now let's think about lists!
Lists are great, right?! so we gonna imagine a scenario where we need to access a list of users that live in a given city and has a given age.
We can pass more than one param to the URL separating them with an "&" sign like this:
https://www.yourdomain.com/users?city=chicago&age=22
easy, right?!
The problem
What if we need to tell the backend to send users from two different cities and different ages?
Well, when working with checkbox type filters we have a problem.
So let's check this case out:
We have these filters in a Vue.js with Vuex application and everytime we click in an option an action is dispatched sending these params in an Object structure to a "filters" array in our state:
filters: [
{"key" = "city", "value"="chicago"},
{"key" = "city", "value"="ohio"},
]
Now that we have the needed information in the state, we can make our request with Axios after setting up the base url:
// Action
async GET_USERS() {
// Since we have mixed filters as objects in an array
// we must map them creating a new array with their values
const cityParams = state.filters.map((filter) =>
filter.key === 'city' ? filter.value : undefined
)
const ageParams = state.filters.map((filter) =>
filter.key === 'age' ? filter.value : undefined
)
const data = await this.$axios.get('/users', {
params: {
city: cityParams,
age: ageParams
},
})
}
It looks simple, but we still have a problem. If we click in a "22 age" checkbox, we will get the following url:
https://yourdomain.com/users?city[]=&age[]=22
If we click again in another age, for exemple 18:
https://yourdomain.com/users?city[]=&city[]=&age[]=22&age[]=18
Maybe the first one will work, if the backend is correctly identifying the keys ending with []. However the second one will break your request returning a 400 status code (bad request).
Solving it
This can be solved by using QS package.
Basically it will allow us to stringify the array of params (cityParams and ageParams).
After download the package using npm or yarn and import it, we can pass it as a third argument in the axios request as it follows:
import qs from 'qs';
// Action
async GET_USERS() {
// Since we have mixed filters as objects in an array
// we must map them creating a new array with their values
const cityParams = state.filters.map((filter) =>
filter.key === 'city' ? filter.value : undefined
)
const ageParams = state.filters.map((filter) =>
filter.key === 'age' ? filter.value : undefined
)
const data = await this.$axios.get('/users', {
params: {
city: cityParams,
age: ageParams
},
paramsSerializer: (params) => {
return qs.stringify(params, { arrayFormat: 'repeat' })
},
})
}
Note that when we map the params, we must return undefined if there is no value.
The values null and '' (empty string) return the key with empty value by default. Otherwise, undefined omit the whole param.
the following argument will repeat key=value for every value we have in the array.
{ arrayFormat: 'repeat' }
As result, we have a clean and readable URL (again clicking twice in checkboxes from age filter):
https://yourdomain.com/users?age=22&age=18
That was a little bit tricky but incredibly useful, right?!
Hope it helps! :)
Top comments (2)
Companheiro, preciso de ajuda
Quero limitar as linhas, hoje uso
const config = {
params: {
_limit: 5
no axios...
porém essa forma não funciona para a nova api que preciso usar
com angular dessa forma consigo dessa forma limitar
this.headers = new HttpHeaders().set('Authorization', 'Bearer ' + this.auth.getToken());
this.headers.append('Range', (this.offset - 1) + '-' + (this.limit - 1))
aqui ele diz que quer apenas um Range de 1
Thank you, just what I needed