Merge pull request #18 from hyle-team/feature/extend-get-assets-rates-endpoint-dev
feat: extend get-assets-rates endpoint-dev
This commit is contained in:
commit
5160b593ef
8 changed files with 140 additions and 51 deletions
14
package-lock.json
generated
14
package-lock.json
generated
|
|
@ -15,6 +15,7 @@
|
|||
"dotenv": "^16.0.3",
|
||||
"express": "^4.18.2",
|
||||
"express-rate-limit": "^8.2.1",
|
||||
"express-validator": "^7.3.1",
|
||||
"jimp": "^0.22.8",
|
||||
"jsonwebtoken": "^9.0.0",
|
||||
"nanoid": "^5.1.5",
|
||||
|
|
@ -4280,6 +4281,19 @@
|
|||
"express": ">= 4.11"
|
||||
}
|
||||
},
|
||||
"node_modules/express-validator": {
|
||||
"version": "7.3.1",
|
||||
"resolved": "https://registry.npmjs.org/express-validator/-/express-validator-7.3.1.tgz",
|
||||
"integrity": "sha512-IGenaSf+DnWc69lKuqlRE9/i/2t5/16VpH5bXoqdxWz1aCpRvEdrBuu1y95i/iL5QP8ZYVATiwLFhwk3EDl5vg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"lodash": "^4.17.21",
|
||||
"validator": "~13.15.23"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/express/node_modules/debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
"dotenv": "^16.0.3",
|
||||
"express": "^4.18.2",
|
||||
"express-rate-limit": "^8.2.1",
|
||||
"express-validator": "^7.3.1",
|
||||
"jimp": "^0.22.8",
|
||||
"jsonwebtoken": "^9.0.0",
|
||||
"nanoid": "^5.1.5",
|
||||
|
|
|
|||
|
|
@ -3,6 +3,10 @@ import UserData from '@/interfaces/common/UserData.js';
|
|||
import Currency from '@/schemes/Currency.js';
|
||||
import Pair from '@/schemes/Pair.js';
|
||||
import { Op } from 'sequelize';
|
||||
import GetAssetsPriceRatesBody from '@/interfaces/bodies/dex/GetAssetsPriceRatesBody.js';
|
||||
import GetAssetsPriceRatesRes, {
|
||||
GetAssetsPriceRatesResPriceRate,
|
||||
} from '@/interfaces/responses/dex/GetAssetsPriceRatesRes.js';
|
||||
import User from '../schemes/User.js';
|
||||
import ordersModel from '../models/Orders.js';
|
||||
import dexModel from '../models/Dex.js';
|
||||
|
|
@ -104,10 +108,10 @@ class DexController {
|
|||
return res.status(200).send(result);
|
||||
}
|
||||
|
||||
async getAssetsPriceRates(req: Request, res: Response) {
|
||||
const { assetsIds } = req.body;
|
||||
getAssetsPriceRates = async (req: Request, res: Response<GetAssetsPriceRatesRes>) => {
|
||||
const { assetsIds } = req.body as GetAssetsPriceRatesBody;
|
||||
|
||||
const currencysRows = await Currency.findAll({
|
||||
const currenciesRows = await Currency.findAll({
|
||||
where: {
|
||||
asset_id: {
|
||||
[Op.in]: assetsIds,
|
||||
|
|
@ -115,61 +119,42 @@ class DexController {
|
|||
},
|
||||
});
|
||||
|
||||
if (!currencysRows) {
|
||||
return res.status(200).send({
|
||||
success: false,
|
||||
data: 'Assets with this id doesn`t exists',
|
||||
});
|
||||
}
|
||||
const currencyIds = currenciesRows.map((currency) => currency.id);
|
||||
|
||||
const currencyIds = currencysRows.map((currency) => currency.id);
|
||||
|
||||
const pairsRows = (
|
||||
(await Pair.findAll({
|
||||
where: {
|
||||
first_currency_id: {
|
||||
[Op.in]: currencyIds,
|
||||
},
|
||||
const pairsRows = (await Pair.findAll({
|
||||
where: {
|
||||
first_currency_id: {
|
||||
[Op.in]: currencyIds,
|
||||
},
|
||||
include: [
|
||||
{
|
||||
model: Currency,
|
||||
as: 'first_currency',
|
||||
required: true,
|
||||
attributes: ['asset_id'],
|
||||
},
|
||||
],
|
||||
})) || []
|
||||
).map((pair) => ({
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
asset_id: pair?.first_currency?.asset_id,
|
||||
rate: pair.rate,
|
||||
}));
|
||||
},
|
||||
include: [
|
||||
{
|
||||
model: Currency,
|
||||
as: 'first_currency',
|
||||
required: true,
|
||||
attributes: ['asset_id'],
|
||||
},
|
||||
],
|
||||
})) as (Pair & { first_currency: Currency })[];
|
||||
|
||||
if (!pairsRows || pairsRows.length === 0) {
|
||||
return res.status(200).send({
|
||||
success: false,
|
||||
data: 'Assets with this id doesn`t exists',
|
||||
});
|
||||
}
|
||||
const priceRates: GetAssetsPriceRatesResPriceRate[] = pairsRows.map((pairRow) => {
|
||||
const assetId = pairRow.first_currency.asset_id;
|
||||
|
||||
// const priceRates = await Promise.all(pairsRows.map(async (pair) => {
|
||||
// const currency = await Currency.findOne({ where: {
|
||||
// id: pair.first_currency_id
|
||||
// }})
|
||||
|
||||
// return {
|
||||
// asset_id: currency?.asset_id,
|
||||
// rate: pair.rate
|
||||
// }
|
||||
// }))
|
||||
return {
|
||||
asset_id: assetId,
|
||||
rate: pairRow?.rate ?? null,
|
||||
day_change: pairRow?.coefficient ?? null,
|
||||
day_volume: pairRow?.volume ?? null,
|
||||
day_high: pairRow?.high ?? null,
|
||||
day_low: pairRow?.low ?? null,
|
||||
};
|
||||
});
|
||||
|
||||
return res.status(200).send({
|
||||
success: true,
|
||||
priceRates: pairsRows,
|
||||
priceRates,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
async findPairID(req: Request, res: Response) {
|
||||
const { first, second } = req.body;
|
||||
|
|
|
|||
14
src/interfaces/bodies/dex/GetAssetsPriceRatesBody.ts
Normal file
14
src/interfaces/bodies/dex/GetAssetsPriceRatesBody.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import { body } from 'express-validator';
|
||||
|
||||
interface GetAssetsPriceRatesBody {
|
||||
assetsIds: string[];
|
||||
}
|
||||
|
||||
export const getAssetsPriceRatesValidator = [
|
||||
body('assetsIds')
|
||||
.isArray({ min: 1 })
|
||||
.withMessage('assetsIds must be a non-empty array of strings'),
|
||||
body('assetsIds.*').isString().withMessage('Each assetId must be a string'),
|
||||
];
|
||||
|
||||
export default GetAssetsPriceRatesBody;
|
||||
24
src/interfaces/responses/dex/GetAssetsPriceRatesRes.ts
Normal file
24
src/interfaces/responses/dex/GetAssetsPriceRatesRes.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
export type GetAssetsPriceRatesResPriceRate = {
|
||||
asset_id: string;
|
||||
rate: number | null;
|
||||
day_change: number | null;
|
||||
day_volume: number | null;
|
||||
day_high: number | null;
|
||||
day_low: number | null;
|
||||
};
|
||||
|
||||
export type GetAssetsPriceRatesSuccessRes = {
|
||||
success: true;
|
||||
priceRates: GetAssetsPriceRatesResPriceRate[];
|
||||
};
|
||||
|
||||
export enum GetAssetsPriceRatesErrorCode {}
|
||||
|
||||
export type GetAssetsPriceRatesErrorRes = {
|
||||
success: false;
|
||||
data: GetAssetsPriceRatesErrorCode;
|
||||
};
|
||||
|
||||
type GetAssetsPriceRatesRes = GetAssetsPriceRatesSuccessRes | GetAssetsPriceRatesErrorRes;
|
||||
|
||||
export default GetAssetsPriceRatesRes;
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
import { NextFunction, Request, Response } from 'express';
|
||||
import { ValidationChain, validationResult } from 'express-validator';
|
||||
import { rateLimit } from 'express-rate-limit';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import User from '@/schemes/User';
|
||||
|
|
@ -49,6 +50,49 @@ class Middleware {
|
|||
|
||||
defaultRateLimit = async (req: Request, res: Response, next: NextFunction) =>
|
||||
defaultRateLimitMiddleware(req, res, next);
|
||||
expressValidator(validators: ValidationChain[]) {
|
||||
return [
|
||||
...validators,
|
||||
(req: Request, res: Response, next: NextFunction) => {
|
||||
const errors = validationResult(req);
|
||||
|
||||
if (!errors.isEmpty()) {
|
||||
res.status(500).send({
|
||||
success: false,
|
||||
data: 'Internal error',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
next();
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
expressJSONErrorHandler = (err: Error, req: Request, res: Response, next: NextFunction) => {
|
||||
const isExpressJSONError =
|
||||
err instanceof SyntaxError && 'status' in err && err.status === 400 && 'body' in err;
|
||||
|
||||
if (isExpressJSONError) {
|
||||
res.status(500).send({
|
||||
success: false,
|
||||
data: 'Internal error',
|
||||
});
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
};
|
||||
|
||||
globalErrorHandler = (err: Error, req: Request, res: Response, _next: NextFunction) => {
|
||||
console.error('Global error handler:');
|
||||
console.error(err);
|
||||
res.status(500).send({
|
||||
success: false,
|
||||
data: 'Internal error',
|
||||
});
|
||||
};
|
||||
|
||||
resultGlobalErrorHandler = [this.expressJSONErrorHandler, this.globalErrorHandler];
|
||||
}
|
||||
|
||||
const middleware = new Middleware();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import express from 'express';
|
||||
import { getAssetsPriceRatesValidator } from '@/interfaces/bodies/dex/GetAssetsPriceRatesBody.js';
|
||||
import dexController from '../controllers/dex.controller.js';
|
||||
import middleware from '../middleware/middleware.js';
|
||||
|
||||
|
|
@ -9,7 +10,11 @@ dexRouter.post('/dex/get-pairs-pages-amount', dexController.getPairsPagesAmount)
|
|||
dexRouter.post('/dex/get-pair', dexController.getPair);
|
||||
dexRouter.post('/dex/renew-bot', middleware.verifyToken, dexController.registerBot);
|
||||
dexRouter.post('/dex/volume-stats', dexController.volumeStats);
|
||||
dexRouter.post('/dex/get-assets-price-rates', dexController.getAssetsPriceRates);
|
||||
dexRouter.post(
|
||||
'/dex/get-assets-price-rates',
|
||||
middleware.expressValidator(getAssetsPriceRatesValidator),
|
||||
dexController.getAssetsPriceRates,
|
||||
);
|
||||
dexRouter.post('/dex/find-pair', dexController.findPairID);
|
||||
|
||||
export default dexRouter;
|
||||
|
|
|
|||
|
|
@ -101,6 +101,8 @@ process.on('unhandledRejection', (reason, promise) => {
|
|||
res.send({ success: true, userData: req.body.userData }),
|
||||
);
|
||||
|
||||
app.use(middleware.resultGlobalErrorHandler);
|
||||
|
||||
server.listen(PORT, () => console.log(`Server is running on port ${PORT}`));
|
||||
})();
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue