diff --git a/db.json b/db.json index 7e0d3c0a92..6f4a559cce 100644 --- a/db.json +++ b/db.json @@ -1,14 +1,59 @@ { - "posts": [ - { "id": 1, "title": "Post 1" }, - { "id": 2, "title": "Post 2" }, - { "id": 3, "title": "Post 3" } - ], - "comments": [ - { "id": 1, "body": "some comment", "postId": 1 }, - { "id": 2, "body": "some comment", "postId": 1 } - ], - "profile": { - "name": "typicode" - } + "chains": [ + { "id": 1, "name": "Ethereum" }, + { "id": 2, "name": "Binance Smart Chain" }, + { "id": 3, "name": "Polygon" }, + { "id": 4, "name": "Avalanche" }, + { "id": 5, "name": "Fantom" } + ], + "shortNames": [ + { "id": 1, "shortName": "ETH", "chainId": 1 }, + { "id": 2, "shortName": "BSC", "chainId": 2 }, + { "id": 3, "shortName": "MATIC", "chainId": 3 }, + { "id": 4, "shortName": "AVAX", "chainId": 4 }, + { "id": 5, "shortName": "FTM", "chainId": 5 } + ], + "chainIds": [ + { "id": 1, "chainId": 1, "chainIdValue": 1 }, + { "id": 2, "chainId": 2, "chainIdValue": 56 }, + { "id": 3, "chainId": 3, "chainIdValue": 137 }, + { "id": 4, "chainId": 4, "chainIdValue": 43114 }, + { "id": 5, "chainId": 5, "chainIdValue": 250 } + ], + "networks": [ + { "id": 1, "network": "mainnet", "chainId": 1 }, + { "id": 2, "network": "mainnet", "chainId": 2 }, + { "id": 3, "network": "mainnet", "chainId": 3 }, + { "id": 4, "network": "mainnet", "chainId": 4 }, + { "id": 5, "network": "mainnet", "chainId": 5 } + ], + "nativeCurrencies": [ + { "id": 1, "name": "Ether", "symbol": "ETH", "decimals": 18, "chainId": 1 }, + { "id": 2, "name": "Binance Coin", "symbol": "BNB", "decimals": 18, "chainId": 2 }, + { "id": 3, "name": "Matic", "symbol": "MATIC", "decimals": 18, "chainId": 3 }, + { "id": 4, "name": "Avalanche", "symbol": "AVAX", "decimals": 18, "chainId": 4 }, + { "id": 5, "name": "Fantom", "symbol": "FTM", "decimals": 18, "chainId": 5 } + ], + "rpcUrls": [ + { "id": 1, "url": "https://mainnet.infura.io/v3/YOUR-PROJECT-ID", "chainId": 1 }, + { "id": 2, "url": "https://api.mycryptoapi.com/eth", "chainId": 1 }, + { "id": 3, "url": "https://cloudflare-eth.com", "chainId": 1 }, + { "id": 4, "url": "https://bsc-dataseed.binance.org/", "chainId": 2 }, + { "id": 5, "url": "https://bsc-dataseed1.defibit.io/", "chainId": 2 }, + { "id": 6, "url": "https://bsc-dataseed1.ninicoin.io/", "chainId": 2 }, + { "id": 7, "url": "https://rpc-mainnet.maticvigil.com/", "chainId": 3 }, + { "id": 8, "url": "https://rpc-mainnet.matic.network", "chainId": 3 }, + { "id": 9, "url": "https://rpc-mainnet.matic.quiknode.pro", "chainId": 3 }, + { "id": 10, "url": "https://api.avax.network/ext/bc/C/rpc", "chainId": 4 }, + { "id": 11, "url": "https://api.avax-test.network/ext/bc/C/rpc", "chainId": 4 }, + { "id": 12, "url": "https://rpcapi.fantom.network", "chainId": 5 }, + { "id": 13, "url": "https://rpc.fantom.network", "chainId": 5 } + ], + "blockExplorerUrls": [ + { "id": 1, "url": "https://etherscan.io", "chainId": 1 }, + { "id": 2, "url": "https://bscscan.com", "chainId": 2 }, + { "id": 3, "url": "https://polygonscan.com", "chainId": 3 }, + { "id": 4, "url": "https://cchain.explorer.avax.network", "chainId": 4 }, + { "id": 5, "url": "https://ftmscan.com", "chainId": 5 } + ] } diff --git a/package.json b/package.json new file mode 100644 index 0000000000..69781416d9 --- /dev/null +++ b/package.json @@ -0,0 +1,12 @@ +{ + "name": "json-server-demo", + "version": "1.0.0", + "main": "server.js", + "scripts": { + "start": "node server.js" + }, + "dependencies": { + "express": "^4.17.1", + "json-server": "^0.16.3" + } +} diff --git a/server.js b/server.js new file mode 100644 index 0000000000..92b643c59d --- /dev/null +++ b/server.js @@ -0,0 +1,173 @@ +const jsonServer = require('json-server'); +const low = require('lowdb'); +const FileSync = require('lowdb/adapters/FileSync'); +const Memory = require('lowdb/adapters/Memory'); +const fs = require('fs'); +const path = require('path'); + +const app = jsonServer.create(); +const dbFilePath = path.join(__dirname, 'db.json'); +const adapter = process.env.NODE_ENV === 'production' ? new Memory() : new FileSync(dbFilePath); +const db = low(adapter); + +if (process.env.NODE_ENV === 'production') { + const dbData = JSON.parse(fs.readFileSync(dbFilePath, 'utf-8')); + db.defaults(dbData).write(); +} + +const middlewares = jsonServer.defaults(); +app.use(middlewares); +app.use(jsonServer.bodyParser); + +app.use((req, res, next) => { + if (req.method !== 'GET') { + const apiKey = req.headers['x-api-key']; + const expectedApiKey = '12345678910'; + + if (!apiKey || apiKey !== expectedApiKey) { + return res.status(403).json({ error: 'Forbidden' }); + } + } + next(); +}); + +app.post('/chains', (req, res) => { + const newChain = req.body; + const chainId = newChain.id; + + const existingChain = db.get('chains').find({ id: chainId }).value(); + if (existingChain) { + return res.status(400).json({ error: 'Chain with this ID already exists' }); + } + + db.get('chains').push({ id: chainId, name: newChain.name }).write(); + + db.get('shortNames').push({ id: chainId, shortName: newChain.shortName, chainId: chainId }).write(); + db.get('chainIds').push({ id: chainId, chainId: chainId, chainIdValue: newChain.chainIdValue }).write(); + db.get('networks').push({ id: chainId, network: newChain.network, chainId: chainId }).write(); + db.get('nativeCurrencies').push({ + id: chainId, + name: newChain.nativeCurrency.name, + symbol: newChain.nativeCurrency.symbol, + decimals: newChain.nativeCurrency.decimals, + chainId: chainId + }).write(); + newChain.rpcUrls.forEach((url, index) => { + db.get('rpcUrls').push({ id: chainId * 100 + index, url: url, chainId: chainId }).write(); + }); + newChain.blockExplorerUrls.forEach((url, index) => { + db.get('blockExplorerUrls').push({ id: chainId * 100 + index, url: url, chainId: chainId }).write(); + }); + + res.status(201).json(newChain); +}); + +app.put('/chains/:id', (req, res) => { + const chainId = parseInt(req.params.id, 10); + const updatedChain = req.body; + + const chain = db.get('chains').find({ id: chainId }).value(); + if (!chain) { + return res.status(404).json({ error: 'Chain not found' }); + } + + db.get('chains').find({ id: chainId }).assign({ name: updatedChain.name }).write(); + + db.get('shortNames').find({ chainId: chainId }).assign({ shortName: updatedChain.shortName }).write(); + db.get('chainIds').find({ chainId: chainId }).assign({ chainIdValue: updatedChain.chainIdValue }).write(); + db.get('networks').find({ chainId: chainId }).assign({ network: updatedChain.network }).write(); + db.get('nativeCurrencies').find({ chainId: chainId }).assign({ + name: updatedChain.nativeCurrency.name, + symbol: updatedChain.nativeCurrency.symbol, + decimals: updatedChain.nativeCurrency.decimals + }).write(); + + // Удаление старых RPC URLs и блок-эксплореров + db.get('rpcUrls').remove({ chainId: chainId }).write(); + db.get('blockExplorerUrls').remove({ chainId: chainId }).write(); + + // Добавление новых RPC URLs и блок-эксплореров + updatedChain.rpcUrls.forEach((url, index) => { + db.get('rpcUrls').push({ id: chainId * 100 + index, url: url, chainId: chainId }).write(); + }); + updatedChain.blockExplorerUrls.forEach((url, index) => { + db.get('blockExplorerUrls').push({ id: chainId * 100 + index, url: url, chainId: chainId }).write(); + }); + + res.status(200).json(updatedChain); +}); + +app.get('/chains/:id/full', (req, res) => { + const chainId = parseInt(req.params.id, 10); + const chain = db.get('chains').find({ id: chainId }).value(); + if (!chain) { + return res.status(404).json({ error: 'not found' }); + } + + const shortName = db.get('shortNames').find({ chainId: chainId }).value(); + const chainIdValue = db.get('chainIds').find({ chainId: chainId }).value(); + const network = db.get('networks').find({ chainId: chainId }).value(); + const nativeCurrency = db.get('nativeCurrencies').find({ chainId: chainId }).value(); + const rpcUrls = db.get('rpcUrls').filter({ chainId: chainId }).map('url').value(); + const blockExplorerUrls = db.get('blockExplorerUrls').filter({ chainId: chainId }).map('url').value(); + + const fullChainInfo = { + ...chain, + shortName: shortName ? shortName.shortName : null, + chainIdValue: chainIdValue ? chainIdValue.chainIdValue : null, + network: network ? network.network : null, + nativeCurrency: nativeCurrency ? nativeCurrency : null, + rpcUrls: rpcUrls, + blockExplorerUrls: blockExplorerUrls + }; + + res.json(fullChainInfo); +}); + +app.get('/chains/full', (req, res) => { + const chains = db.get('chains').value(); + + const fullChainsInfo = chains.map(chain => { + const chainId = chain.id; + const shortName = db.get('shortNames').find({ chainId: chainId }).value(); + const chainIdValue = db.get('chainIds').find({ chainId: chainId }).value(); + const network = db.get('networks').find({ chainId: chainId }).value(); + const nativeCurrency = db.get('nativeCurrencies').find({ chainId: chainId }).value(); + const rpcUrls = db.get('rpcUrls').filter({ chainId: chainId }).map('url').value(); + const blockExplorerUrls = db.get('blockExplorerUrls').filter({ chainId: chainId }).map('url').value(); + + return { + ...chain, + shortName: shortName ? shortName.shortName : null, + chainIdValue: chainIdValue ? chainIdValue.chainIdValue : null, + network: network ? network.network : null, + nativeCurrency: nativeCurrency ? nativeCurrency : null, + rpcUrls: rpcUrls, + blockExplorerUrls: blockExplorerUrls + }; + }); + + res.json(fullChainsInfo); +}); + +app.get('/chains/:id', (req, res) => { + const chainId = parseInt(req.params.id, 10); + const chain = db.get('chains').find({ id: chainId }).value(); + if (!chain) { + return res.status(404).json({ error: 'not found' }); + } + res.json(chain); +}); + +app.use((req, res, next) => { + req.app.db = db; + next(); +}); + +const router = jsonServer.router(db); +app.use(router); + +const port = process.env.PORT || 3000; +app.listen(port, () => { + console.log(`JSON Server is running on port ${port}`); +}); diff --git a/vercel.json b/vercel.json new file mode 100644 index 0000000000..1def834a00 --- /dev/null +++ b/vercel.json @@ -0,0 +1,15 @@ +{ + "version": 2, + "builds": [ + { + "src": "server.js", + "use": "@vercel/node" + } + ], + "routes": [ + { + "src": "/(.*)", + "dest": "/server.js" + } + ] +}