From 5b06c9899e988034d82d8b9a648bf95e1a2f2052 Mon Sep 17 00:00:00 2001 From: momstrosity Date: Wed, 5 Feb 2025 22:36:55 +0000 Subject: [PATCH 1/3] Add /ethprice API endpoint to fetch Ethereum price from CoinGecko --- app.js | 14 ++++++++------ package.json | 14 ++++++++++---- src/controllers/ethPriceController.js | 14 ++++++++++++++ src/routes/ethPriceRoutes.js | 8 ++++++++ src/services/ethPriceService.js | 16 ++++++++++++++++ tests/ethPriceEndpoint.test.js | 13 +++++++++++++ 6 files changed, 69 insertions(+), 10 deletions(-) create mode 100644 src/controllers/ethPriceController.js create mode 100644 src/routes/ethPriceRoutes.js create mode 100644 src/services/ethPriceService.js create mode 100644 tests/ethPriceEndpoint.test.js diff --git a/app.js b/app.js index 568ffe3..3029196 100644 --- a/app.js +++ b/app.js @@ -1,11 +1,13 @@ const express = require('express'); +const ethPriceRoutes = require('./src/routes/ethPriceRoutes'); + const app = express(); -const port = 3000; +const port = process.env.PORT || 3000; -app.get('/', (req, res) => { - res.send('Hello World!'); -}); +app.use('/api', ethPriceRoutes); app.listen(port, () => { - console.log(`Listening on http://localhost:${port}`); -}); \ No newline at end of file + console.log(`Server running on port ${port}`); +}); + +module.exports = app; \ No newline at end of file diff --git a/package.json b/package.json index 17d7865..f57245c 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,18 @@ { "name": "express-hello-world", "version": "1.0.0", - "description": "一个简单的 Express Hello World 应用", + "description": "Express application with ETH price endpoint", "main": "app.js", "scripts": { - "start": "node app.js" + "start": "node app.js", + "test": "jest" }, "dependencies": { - "express": "^4.18.2" + "express": "^4.18.2", + "node-fetch": "^2.6.1" + }, + "devDependencies": { + "jest": "^27.0.0", + "supertest": "^6.1.6" } -} \ No newline at end of file +} \ No newline at end of file diff --git a/src/controllers/ethPriceController.js b/src/controllers/ethPriceController.js new file mode 100644 index 0000000..e4cf406 --- /dev/null +++ b/src/controllers/ethPriceController.js @@ -0,0 +1,14 @@ +const EthPriceService = require('../services/ethPriceService'); + +class EthPriceController { + static async getEthPrice(req, res) { + try { + const price = await EthPriceService.getEthPriceInUSD(); + res.json({ price }); + } catch (error) { + res.status(500).json({ error: error.message }); + } + } +} + +module.exports = EthPriceController; \ No newline at end of file diff --git a/src/routes/ethPriceRoutes.js b/src/routes/ethPriceRoutes.js new file mode 100644 index 0000000..3733e07 --- /dev/null +++ b/src/routes/ethPriceRoutes.js @@ -0,0 +1,8 @@ +const express = require('express'); +const EthPriceController = require('../controllers/ethPriceController'); + +const router = express.Router(); + +router.get('/ethprice', EthPriceController.getEthPrice); + +module.exports = router; \ No newline at end of file diff --git a/src/services/ethPriceService.js b/src/services/ethPriceService.js new file mode 100644 index 0000000..a6bc03e --- /dev/null +++ b/src/services/ethPriceService.js @@ -0,0 +1,16 @@ +const fetch = require('node-fetch'); + +class EthPriceService { + static async getEthPriceInUSD() { + try { + const response = await fetch('https://api.coingecko.com/api/v3/simple/price?ids=ethereum&vs_currencies=usd'); + const data = await response.json(); + return data.ethereum.usd; + } catch (error) { + console.error('Error fetching ETH price:', error); + throw new Error('Unable to fetch ETH price'); + } + } +} + +module.exports = EthPriceService; \ No newline at end of file diff --git a/tests/ethPriceEndpoint.test.js b/tests/ethPriceEndpoint.test.js new file mode 100644 index 0000000..18dbaf0 --- /dev/null +++ b/tests/ethPriceEndpoint.test.js @@ -0,0 +1,13 @@ +const request = require('supertest'); +const app = require('../app'); + +describe('ETH Price Endpoint', () => { + it('should return ETH price in USD', async () => { + const response = await request(app).get('/api/ethprice'); + + expect(response.statusCode).toBe(200); + expect(response.body).toHaveProperty('price'); + expect(typeof response.body.price).toBe('number'); + expect(response.body.price).toBeGreaterThan(0); + }, 10000); // Increased timeout for external API call +}); \ No newline at end of file From f8428d0f985db79033099c6550ed1dfebb79e341 Mon Sep 17 00:00:00 2001 From: momstrosity Date: Wed, 5 Feb 2025 23:02:31 +0000 Subject: [PATCH 2/3] Add /ethprice API endpoint to fetch Ethereum price from CoinGecko --- src/controllers/ethPriceController.js | 22 ++++++++++++++-------- src/routes/ethPriceRoutes.js | 4 ++-- src/services/ethPriceService.js | 25 ++++++++++++++++--------- tests/ethPriceEndpoint.test.js | 22 ++++++++++++++-------- 4 files changed, 46 insertions(+), 27 deletions(-) diff --git a/src/controllers/ethPriceController.js b/src/controllers/ethPriceController.js index e4cf406..2a3f2bc 100644 --- a/src/controllers/ethPriceController.js +++ b/src/controllers/ethPriceController.js @@ -1,14 +1,20 @@ -const EthPriceService = require('../services/ethPriceService'); +const { fetchEthPrice } = require('../services/ethPriceService'); -class EthPriceController { - static async getEthPrice(req, res) { +async function getEthPrice(req, res) { try { - const price = await EthPriceService.getEthPriceInUSD(); - res.json({ price }); + const price = await fetchEthPrice(); + res.json({ + currency: 'USD', + price: price + }); } catch (error) { - res.status(500).json({ error: error.message }); + res.status(500).json({ + error: 'Unable to fetch ETH price', + details: error.message + }); } - } } -module.exports = EthPriceController; \ No newline at end of file +module.exports = { + getEthPrice +}; \ No newline at end of file diff --git a/src/routes/ethPriceRoutes.js b/src/routes/ethPriceRoutes.js index 3733e07..bfb6c20 100644 --- a/src/routes/ethPriceRoutes.js +++ b/src/routes/ethPriceRoutes.js @@ -1,8 +1,8 @@ const express = require('express'); -const EthPriceController = require('../controllers/ethPriceController'); +const { getEthPrice } = require('../controllers/ethPriceController'); const router = express.Router(); -router.get('/ethprice', EthPriceController.getEthPrice); +router.get('/ethprice', getEthPrice); module.exports = router; \ No newline at end of file diff --git a/src/services/ethPriceService.js b/src/services/ethPriceService.js index a6bc03e..145ffea 100644 --- a/src/services/ethPriceService.js +++ b/src/services/ethPriceService.js @@ -1,16 +1,23 @@ const fetch = require('node-fetch'); -class EthPriceService { - static async getEthPriceInUSD() { +const COINGECKO_API_URL = 'https://api.coingecko.com/api/v3/simple/price'; + +async function fetchEthPrice() { try { - const response = await fetch('https://api.coingecko.com/api/v3/simple/price?ids=ethereum&vs_currencies=usd'); - const data = await response.json(); - return data.ethereum.usd; + const response = await fetch(`${COINGECKO_API_URL}?ids=ethereum&vs_currencies=usd`); + + if (!response.ok) { + throw new Error('Failed to fetch ETH price'); + } + + const data = await response.json(); + return data.ethereum.usd; } catch (error) { - console.error('Error fetching ETH price:', error); - throw new Error('Unable to fetch ETH price'); + console.error('Error fetching ETH price:', error.message); + throw error; } - } } -module.exports = EthPriceService; \ No newline at end of file +module.exports = { + fetchEthPrice +}; \ No newline at end of file diff --git a/tests/ethPriceEndpoint.test.js b/tests/ethPriceEndpoint.test.js index 18dbaf0..c890517 100644 --- a/tests/ethPriceEndpoint.test.js +++ b/tests/ethPriceEndpoint.test.js @@ -1,13 +1,19 @@ const request = require('supertest'); const app = require('../app'); +const { fetchEthPrice } = require('../src/services/ethPriceService'); + +jest.setTimeout(10000); // Increase timeout for network request describe('ETH Price Endpoint', () => { - it('should return ETH price in USD', async () => { - const response = await request(app).get('/api/ethprice'); - - expect(response.statusCode).toBe(200); - expect(response.body).toHaveProperty('price'); - expect(typeof response.body.price).toBe('number'); - expect(response.body.price).toBeGreaterThan(0); - }, 10000); // Increased timeout for external API call + it('should return the current ETH price', async () => { + const response = await request(app).get('/api/ethprice'); + + expect(response.status).toBe(200); + expect(response.body).toHaveProperty('currency', 'USD'); + expect(response.body).toHaveProperty('price'); + + // Price should be a positive number + expect(typeof response.body.price).toBe('number'); + expect(response.body.price).toBeGreaterThan(0); + }); }); \ No newline at end of file From d1f729dd30f7dcfb17762dbe9b8dc5e7bd408e19 Mon Sep 17 00:00:00 2001 From: momstrosity Date: Wed, 5 Feb 2025 23:19:04 +0000 Subject: [PATCH 3/3] Add /ethprice API endpoint to fetch Ethereum USD price from CoinGecko - Implements a new API endpoint to retrieve current Ethereum price - Uses CoinGecko as the price data source - Provides real-time USD price for Ethereum --- app.js | 5 ++--- src/controllers/ethPriceController.js | 22 +++++++----------- src/routes/ethPriceRoutes.js | 4 ++-- src/services/ethPriceService.js | 32 +++++++++++++-------------- tests/ethPriceEndpoint.test.js | 22 +++++++----------- 5 files changed, 36 insertions(+), 49 deletions(-) diff --git a/app.js b/app.js index 3029196..bbe926c 100644 --- a/app.js +++ b/app.js @@ -1,11 +1,10 @@ const express = require('express'); -const ethPriceRoutes = require('./src/routes/ethPriceRoutes'); - const app = express(); -const port = process.env.PORT || 3000; +const ethPriceRoutes = require('./src/routes/ethPriceRoutes'); app.use('/api', ethPriceRoutes); +const port = process.env.PORT || 3000; app.listen(port, () => { console.log(`Server running on port ${port}`); }); diff --git a/src/controllers/ethPriceController.js b/src/controllers/ethPriceController.js index 2a3f2bc..a17cb9a 100644 --- a/src/controllers/ethPriceController.js +++ b/src/controllers/ethPriceController.js @@ -1,20 +1,14 @@ -const { fetchEthPrice } = require('../services/ethPriceService'); +const EthPriceService = require('../services/ethPriceService'); -async function getEthPrice(req, res) { +class EthPriceController { + static async getEthPrice(req, res) { try { - const price = await fetchEthPrice(); - res.json({ - currency: 'USD', - price: price - }); + const ethPrice = await EthPriceService.getEthPrice(); + res.json({ price: ethPrice }); } catch (error) { - res.status(500).json({ - error: 'Unable to fetch ETH price', - details: error.message - }); + res.status(500).json({ error: error.message }); } + } } -module.exports = { - getEthPrice -}; \ No newline at end of file +module.exports = EthPriceController; \ No newline at end of file diff --git a/src/routes/ethPriceRoutes.js b/src/routes/ethPriceRoutes.js index bfb6c20..3733e07 100644 --- a/src/routes/ethPriceRoutes.js +++ b/src/routes/ethPriceRoutes.js @@ -1,8 +1,8 @@ const express = require('express'); -const { getEthPrice } = require('../controllers/ethPriceController'); +const EthPriceController = require('../controllers/ethPriceController'); const router = express.Router(); -router.get('/ethprice', getEthPrice); +router.get('/ethprice', EthPriceController.getEthPrice); module.exports = router; \ No newline at end of file diff --git a/src/services/ethPriceService.js b/src/services/ethPriceService.js index 145ffea..ca2e0af 100644 --- a/src/services/ethPriceService.js +++ b/src/services/ethPriceService.js @@ -1,23 +1,23 @@ const fetch = require('node-fetch'); -const COINGECKO_API_URL = 'https://api.coingecko.com/api/v3/simple/price'; - -async function fetchEthPrice() { +class EthPriceService { + static async getEthPrice() { + const COINGECKO_API_URL = 'https://api.coingecko.com/api/v3/simple/price?ids=ethereum&vs_currencies=usd'; + try { - const response = await fetch(`${COINGECKO_API_URL}?ids=ethereum&vs_currencies=usd`); - - if (!response.ok) { - throw new Error('Failed to fetch ETH price'); - } - - const data = await response.json(); - return data.ethereum.usd; + const response = await fetch(COINGECKO_API_URL); + + if (!response.ok) { + throw new Error('Unable to fetch Ethereum price'); + } + + const data = await response.json(); + return data.ethereum.usd; } catch (error) { - console.error('Error fetching ETH price:', error.message); - throw error; + console.error('Error fetching ETH price:', error); + throw new Error('Failed to retrieve Ethereum price'); } + } } -module.exports = { - fetchEthPrice -}; \ No newline at end of file +module.exports = EthPriceService; \ No newline at end of file diff --git a/tests/ethPriceEndpoint.test.js b/tests/ethPriceEndpoint.test.js index c890517..0a76f45 100644 --- a/tests/ethPriceEndpoint.test.js +++ b/tests/ethPriceEndpoint.test.js @@ -1,19 +1,13 @@ const request = require('supertest'); const app = require('../app'); -const { fetchEthPrice } = require('../src/services/ethPriceService'); - -jest.setTimeout(10000); // Increase timeout for network request describe('ETH Price Endpoint', () => { - it('should return the current ETH price', async () => { - const response = await request(app).get('/api/ethprice'); - - expect(response.status).toBe(200); - expect(response.body).toHaveProperty('currency', 'USD'); - expect(response.body).toHaveProperty('price'); - - // Price should be a positive number - expect(typeof response.body.price).toBe('number'); - expect(response.body.price).toBeGreaterThan(0); - }); + it('should return a valid ETH price', async () => { + const response = await request(app).get('/api/ethprice'); + + expect(response.statusCode).toBe(200); + expect(response.body).toHaveProperty('price'); + expect(typeof response.body.price).toBe('number'); + expect(response.body.price).toBeGreaterThan(0); + }); }); \ No newline at end of file