Axios conditional parameters - javascript

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

Related

How do I increment automatically a variable when calling a Cypress method?

createUserPatch is an API custom command to create a new User.
You can see that I have created a variable "A" inside it.
The variable is used in the body emails part [a]+'freddie.doe#example.com','type': 'work','primary': true}]
I want to find a way to automatically increase the variable "A" whenever I call the command createUserPatch.
Cypress.Commands.add('createUserPatch', (user) => {
var A = 1;
cy.request({
method: 'POST',
url: '/scim/v2/users',
qs: {
key : Cypress.env('apiKey')
},
body :{
schemas: user.schemas,
userName: user.userName,
emails: [{ 'value': [A]+'freddie.doe#example.com','type': 'work','primary': true}],
name : 'Maurice'
}
}).then(res => {
return res.body;
});
});
I use this command in the test below in a before each.
let user = {
schemas:'["urn:ietf:params:scim:schemas:core:2.0:User"]',
userName: 'John',
userId: null,
groupID: null
};
describe('Deactivating a user ', () => {
beforeEach(() => {
cy.createUserPatch(user).then((newUser) => {
return user.userId = newUser.id;
});
});
....
Each time I run this test.
I want the value of the email to be increased.
First test -> 0freddie.doe#example.com
Second test -> 1freddie.doe#example.com
Third test -> 2freddie.doe#example.com
etc...
Cypress clears variables between tests, but a few ways to preserve data have been suggested in other questions (e.g write data to file).
Since you already use Cypress.env(name) to access environment variables you could use Cypress.env(name, value) to track the prefix.
Cypress.Commands.add('createUserPatch', (user) => {
let prefix = Cypress.env('emailprefix') || 0; // first time it may be undefined
// so "|| 0" initializes it
Cypress.env('emailprefix', ++prefix); // increment and save
cy.request({
...
emails: [{ 'value': prefix+'freddie.doe#example.com','type': 'work','primary': true}],
Note, the prefix value will be preserved between runs, which may or may not be what you want.
To clear it between runs, add a before() which resets the value
before(() => Cypress.env('emailprefix', 0) );
beforeEach(() => {
cy.createUserPatch().then(console.log)
})

Is there a way to grab only a desired string from an object that contains an email? I need to catch only the string before the #

I try to extract only the username from the "userPrincipalName" and then concatenate it into the call of Axios as a parameter.
the "userPrincipalName" Contains email like this apple#foo.com and i need to concatenate only the "apple" ( i mean that I need just the string before the "#")
i dont understand what is my mistake on my split ..?
this is my example :
getData = () => {
const { userPrincipalName } = this.state.azureLoginObject;
this.setState({ isLoading: true, data: [] })
axios.get("https://rallycoding.herokuapp.com/api/music_albums",{ userPrincipalName }.split('#')[0])
.then(res => {
this.setState({
isLoading: false,
data: res.data
});
console.log(res.data);
});
}
assuming that "userPrincipalName" contains email "apple#foo.com" after
const { userPrincipalName } = this.state.azureLoginObject;
you can use the userPrincipalName as it is instead of putting it in { }.
axios.get("https://rallycoding.herokuapp.com/api/music_albums",userPrincipalName.split('#')[0])
It seems like you are using split method on object rather than on string. I have updated the. If doesnot helps you, can you please update the error.
axios.get("https://rallycoding.herokuapp.com/api/music_albums", userPrincipalName.split('#')[0])

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

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)

Typescript - if conditrional inside a map

I am mapping a subset of user data to an object of a refined data set. Inside the map i want to check if a variable is null or undefined, and if yes, then to set this variable to a placeholder value.
The issue I am facing is that declaring an if statement inside the map is causing an error, but even though a map can have an index as a parameter, how can we use it functionally with a conditional Statement? Any insight most appreciated.
return this.UserService.search(url)
.map((data) => {
console.log(data);
data.result = <any> data.result.map((user, index) => ({
// if statement causing error here
if(user.name === null || user.name === undefined){
// error with this if condition
},
id: user.id,
name: user.name,
type: user.type,
password: user.password,
}));
return data;
}).map(data => ({
meta: { totalItems: data.size },
data: data.result,
}));
You're attempting to use an object literal as the return type, but naturally, an if statement (or any statement) can't be inside object literal syntax.
So instead, define a function body, which also uses curly braces, and put your code inside with an explicit return statement.
// Starts function body instead of single expression-v
data.result = <any> data.result.map((user, index) => {
if (some_condition) {
return "some value"; // The object?
} else {
return "other value"; // A different object?
}
/*
// I assume these are to be used in the object you return
id: user.id,
name: user.name,
type: user.type,
password: user.password,
*/
});
You can express conditions in literal maps, but it is somewhat ugly.
return {
a: 1,
...(some_condition && {
b: 1,
})
};
As far as i know you can't do that with JUST a map.
however you could follow it up with a filter() function:
const newArray = oldArray.map((value, index) => condition ? value : null).filter(v => v);
you basicaly iterate over each item and then return the value or null depending on your condition.
Now once you have the map you just filter it by removing the null values from the array.
Notice that the original array is not altered and a new one is returned.
thanks for the idea #user8897421 for the idea. i just wanted to turn it into a one liner.

Categories

Resources