axios: how to merge transformRequest - javascript

axios.defaults.transformRequest = [
(data, headers) => {
console.log('default config')
// ...some code
return qs.stringify(data)
}
]
function postData(value) {
axios.post('/xxx', value, {
transformRequest: [data => {
console.log('postData config')
const { aProp, ...rest } = data
if (isX(aProp)) {
return { ...rest, x: aProp }
}
return { ...rest, y: aProp }
}]
})
}
Expected output:
postData config
default config
But only output postData config.
The transformRequest seems like merged by index, not using concat. So how can I make both functions called?

Seems that's not possible like the way you written, as Axios is just overriding the transformRequest property of global config by request specific config.
Please take a look at the code that is in mergeConfig.js
in below code snippets
config2 is request specific config
config1 is global config
var valueFromConfig2Keys = ['url', 'method', 'data'];
var mergeDeepPropertiesKeys = ['headers', 'auth', 'proxy', 'params'];
var defaultToConfig2Keys = [
'baseURL', 'transformRequest', 'transformResponse', 'paramsSerializer',
'timeout', 'timeoutMessage', 'withCredentials', 'adapter', 'responseType', 'xsrfCookieName',
'xsrfHeaderName', 'onUploadProgress', 'onDownloadProgress', 'decompress',
'maxContentLength', 'maxBodyLength', 'maxRedirects', 'transport', 'httpAgent',
'httpsAgent', 'cancelToken', 'socketPath', 'responseEncoding'
];
var directMergeKeys = ['validateStatus'];
Only mergeDeepPropertiesKeys are deep merged like here
function mergeDeepProperties(prop) {
if (!utils.isUndefined(config2[prop])) {
config[prop] = getMergedValue(config1[prop], config2[prop]);
} else if (!utils.isUndefined(config1[prop])) {
config[prop] = getMergedValue(undefined, config1[prop]);
}
}
utils.forEach(mergeDeepPropertiesKeys, mergeDeepProperties);
defaultToConfig2Keys are just overriden by request specific config like below and transformRequest is one of those properties.
utils.forEach(defaultToConfig2Keys, function defaultToConfig2(prop) {
if (!utils.isUndefined(config2[prop])) {
config[prop] = getMergedValue(undefined, config2[prop]);
} else if (!utils.isUndefined(config1[prop])) {
config[prop] = getMergedValue(undefined, config1[prop]);
}
});
PS: I would suggest you to write your own wrapper around axios or you can prepare your data ahead before making the request.

Related

How to pass content of json file as url param

I am trying to learn data parameterization.
I have a json file with 2 entries:
[
{
"accountreference": "4157804914681"
},
{
"accountreference": "4157804925075"
}
]
and I manage to print them into the console. However, I am not able into my http.post.
Is there anything wrong with this:
const url = 'https://api.example-test.com/user-api/accounts/${randomUser.accountreference}/benefit';
Any better way of passing it on?
import http from "k6/http";
import { check, sleep } from "k6";
import { SharedArray } from 'k6/data';
// Test setup
export let options = {
stages: [
{ duration: '3s', target: 1 },
{ duration: '3s', target: 0 }, // scale down. Recovery stage.
],
thresholds: {
// 90% of requests must finish within 400ms, 95% within 800, and 99.9% within 2s.
http_req_duration: ['p(90) < 400', 'p(95) < 800', 'p(99.9) < 2000'],
},
};
const data = new SharedArray('accountRef', function () {
// here you can open files, and then do additional processing or generate the array with data dynamically
const f = JSON.parse(open('./accountRef.json'));
return f; // f must be an array[]
});
export default () => {
const randomUser = data[Math.floor(Math.random() * data.length)];
console.log(`${randomUser.accountreference}`);
const url = 'https://api.example-test.com/user-api/accounts/${randomUser.accountreference}/benefit';
const params = {
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer blahblahPk9tjDdQ`,
},
};
const data1 = "{ \"amount\": 20000, \"external_reference\": \"mba-bcbdac6-024-m-2155667\", \"transaction_attributes\": { \"channel\": \"POP\"}}";
// execute
let res = http.post(url,data1,params);
check(res, {
"Create user response status code is 201": (r) => r.status == 201,
}
);
// Short break between iterations
sleep(1);
};
results
In order to use template strings in javascript, you need to use the ` quotes, not the ' quotes.
// Write this:
const url = `https://api.example-test.com/user-api/accounts/${randomUser.accountreference}/benefit`;
// Not this:
const url = 'https://api.example-test.com/user-api/accounts/${randomUser.accountreference}/benefit';

Proxying an object in Javascript: The results from the proxied function are not being applied

What I am trying to do is intercept a function call, and prepend a header. The header is getting applied, the function itself is getting called, but the results don't have actually body.
code:
'use strict'
const load = require('require.all')
module.exports = ({xr}) => {
const cmds = load({
dir: __dirname,
not: /index\.js$/i
})(xr);
const result = Object.entries(cmds).map(([k,v]) => {
return {
[k] : new Proxy(v, {
get: function (target, prop) {
return (...args) => {
return {
type: 'cmd',
...(target[prop])(args)
}
}
},
})
}
}).reduce((a,b) => Object.assign({},a,b))
return result
}
The original function will return something like:
{
blocks:[...]
}
and I need to prepend this header.
expected output:
{
type: "cmd",
blocks: [...]
}
I would give you what I am getting as JSON except, it chokes on JSON.stringify because of this proxy. However, in my debugger (and my code agrees because it blows up) the only thing there is type: "cmd"
Am I doing this right?

What is the best way for reducing multiple if statement?

I have a helper function that builds object with appropriate query properties. I use this object as a body in my promise request. What is the most elegant way for refactoring multiple if statements? Here is a function:
getQueryParams = (query, pagination, sorting) => {
let queryParam = {}
if (pagination && pagination.pageNumber) {
queryParam.page = `${pagination.pageNumber}`
}
if (pagination && pagination.rowsOnPage) {
queryParam.size = `${pagination.rowsOnPage}`
}
if (query) {
const updatedQuery = encodeURIComponent(query)
queryParam.q = `${updatedQuery}`
}
if (sorting) {
queryParam.sort = `${sorting.isDescending ? '-' : ''}${sorting.name}`
}
return service.get(`/my-url/`, queryParam).then(result => {
return result
})
}
If service checks its parameters (as it should), you could benefit from the default parameters. Something like this:
const getQueryParams = (
query = '',
pagination = {pageNumber: 0, rowsOnPage: 0},
sorting = {isDescending: '', name: ''}
) => {
const queryParam = {
page: pagination.pageNumber,
size: pagination.rowsOnPage,
q: encodeURIComponent(query),
sort: `${sorting.isDescending}${sorting.name}`
}
return ...;
};
A live example to play with at jsfiddle.
This is an idea how it could looks like, but you need to adopt your params before:
const query = new URLSearchParams();
Object.keys(params).forEach(key => {
if (params[key]) {
query.append(key, params[key]);
}
});

Update a property from a string to object on JavaScript without mutation

When iterating through an object and updating it I feel that I am not doing it right. This is the method I have built to do it and I have doubts about record[header] = {label: record[header]};
Does anybody have a better solution to avoid mutation records array?
setAfterRecords(preview: any): void {
const { columns: headers } = preview;
const { rows: records } = preview;
records.map((record, i) => {
headers.forEach(header => {
record[header] = {
label: record[header],
};
});
return record;
});
this.after = { headers, records };
}
Thank you.
The following should do it. It uses the new-ish object spread operator (... on {}). It's like Object.assign() but in a more concise syntax.
setAfterRecords(preview: any): void {
const { columns: headers, rows: records } = preview;
// Build a new array of records.
const newRecords = records.map(record => {
// Build a new record object, adding in each header.
return headers.reduce((c, header) => {
// This operation shallow-copies record from the initial value or
// previous operation, adding in the header.
return { ...c, [header]: { label: record[header] } }
}, record)
})
this.after = { headers, records: newRecords };
}

normalizr v3 and JSON api

I want to normalise the responses I receive from an API. A typical response could look something like this:
// Get all projects
{data:[
{
id: 1
...
team:{
data: {
id:15
...
}
}
},
{
id:2,
....
},
{
id:3,
...
}
]}
How do I write my schemas so that it removes the 'data' container?
Currently, my schema looks like:
export const project = new schema.Entity('projects', {
team: team, // team omitted
},
{
processStrategy: (value, parent, key) => parent.data
}
)
export const arrayOfProjects = new schema.Array(project)
And I am using it like:
const normalizedProjects = normalize(jsonResponse, arrayOfProjects)
normalizedProjects then looks like this:
{
entities:{
projects:{
undefined:{
0:{
team:{
data:{
id:15,
...
}
}
},
1:{...},
2:{...}.
...
50:{...},
}
}
},
result:[] // length is 0
}
I'm not sure why the list of projects is contained in 'undefined', either?
I also use json_api schema.
How about like this?
const projectsSchema = new schema.Entity('projects', {}, {
processStrategy: processStrategy
});
export const processStrategy = (value, parent, key) => {
const attr = value.attributes;
delete value.attributes;
return { ...value, ...attr };
};
export const fetchProjectsSchema = {
data: [projectsSchema]
}
Each of your entity schema that you want to have the data omitted (or anything else fundamentalyl changed) needs to include a processStrategy that you write to remove or change any data. (see more examples in the tests)

Categories

Resources