Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: replace qs lib with native URLSearchParams #736

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 2 additions & 16 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@
"popmotion": "^11.0.5",
"promise-queue": "^2.2.5",
"qrcode": "^1.5.4",
"qs": "^6.13.0",
"rollup-plugin-node-polyfills": "^0.2.1",
"scroll-into-view-if-needed": "^3.1.0",
"semver": "^7.7.1",
Expand Down
49 changes: 49 additions & 0 deletions src/filters/flattenData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* Flatten a nested object into a flat structure with keys representing the path to each value.
* @param {object} obj - The nested object to flatten.
* @param {string} [parentKey=""] - The base key for the current nesting level (used recursively).
* @param {Record<string, any>} [result={}] - The object to store the flattened result (used recursively).
* @returns {Record<string, any>} - A flat object where keys represent the path to the values in the original object.
*
* @example
* const data = {
* name: "John",
* age: 42,
* children: {
* first: {
* name: "Kelvin",
* age: 12,
* },
* second: {
* name: "Henry",
* age: 15,
* },
* },
* };
*
* const flatData = flattenData(data);
* console.log(flatData);
* // {
* // "name": "John",
* // "age": 42,
* // "children[first][name]": "Kelvin",
* // "children[first][age]": 12,
* // "children[second][name]": "Henry",
* // "children[second][age]": 15,
* // }
*/
const flattenData = (obj: Record<string, any>, parentKey: string = "", result: Record<string, any> = {}): Record<string, any> => {
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
const newKey = parentKey ? `${parentKey}[${key}]` : key;
if (typeof obj[key] === "object" && obj[key] !== null && !Array.isArray(obj[key])) {
flattenData(obj[key], newKey, result);
} else {
result[newKey] = obj[key];
}
}
}
return result;
};

export default flattenData;
8 changes: 5 additions & 3 deletions src/lib/bitcoin/doge-api.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import qs from 'qs'

import BtcBaseApi from './btc-base-api'
import { Cryptos } from '../constants'
import BigNumber from '../bignumber'
Expand All @@ -9,6 +7,7 @@ import { ECPairFactory } from 'ecpair'
import * as tinysecp from 'tiny-secp256k1'
import { convertToSmallestUnit } from './bitcoin-utils'
import { dogeIndexer } from '../../lib/nodes'
import flattenData from '@/filters/flattenData'

const ECPairAPI = ECPairFactory(tinysecp)

Expand Down Expand Up @@ -157,8 +156,11 @@ export default class DogeApi extends BtcBaseApi {

/** Executes a POST request to the DOGE API */
_post(url, data) {
const flatData = flattenData(data);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain why this is needed? Preferably with examples.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems overengineered. I'd prefer to use native URLSearchParams (or alternative) functionality, instead of a custom function.

Copy link
Collaborator Author

@skranee skranee Mar 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is needed because native URLSearchParams can not work with nested objects, it can only process flat ones. So if the 'data' object is going to have some depth, the params would look like that
image
image

Copy link
Collaborator Author

@skranee skranee Mar 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In qs lib it's processed by default up to object's depth = 5, but while using native URLSearchParams you should either be sure that the object is always flat or flatten it on your own to avoid results as are shown on the screenshot.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, if I'm not mistaken, a native flat() method is only available for arrays in JS. If we're working with object, we have to flatten the object using your own functions (that's also what I've got while searching the answer on stack overflow and through AI requests).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get your point, but does the BTC, DASH or DOGE APIs use nested params? Perhaps we don't this at all.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IDK about that honestly, will do a research later

const params = new URLSearchParams(flatData);

return dogeIndexer
.useClient((client) => client.post(url, qs.stringify(data), POST_CONFIG))
.useClient((client) => client.post(url, params.toString(), POST_CONFIG))
.then((response) => response.data)
}

Expand Down