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
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';
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?
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]);
}
});
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 };
}
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)