Backend internship assessment project - A real-time meme coin data aggregation service that fetches data from multiple DEX sources, implements caching with Redis, and provides real-time updates via WebSockets.
API Endpoint: https://e-back-ca4c.onrender.com/api/tokens?q=SOL
GitHub Repository: https://github.com/Augustus-118/e_back
This service aggregates real-time cryptocurrency token data from multiple decentralized exchange (DEX) APIs, specifically DexScreener and Jupiter. It implements efficient caching using Redis and provides real-time price updates through WebSocket connections.
The application follows a service-based architecture with clear separation of concerns:
Client Request
|
v
Express API (app.ts)
|
v
Aggregator Service (aggregator.ts)
|
+-- Cache Service (cache.ts) --> Redis
|
+-- Fetcher Service (fetcher.ts) --> External APIs
|
+-- DexScreener API
+-- Jupiter API
1. Data Fetching Layer (fetcher.ts)
- Fetches token data from DexScreener and Jupiter APIs
- Implements User-Agent headers to prevent API blocking
- Uses optional chaining to handle missing data fields safely
- Transforms API responses into a unified TokenData format
2. Caching Layer (cache.ts)
- Connects to Redis Cloud for distributed caching
- Implements 30-second TTL (Time To Live) for cached data
- Reduces external API calls by approximately 95%
- Provides get/set methods with configurable expiration
3. Aggregation Service (aggregator.ts)
- Implements cache-first strategy for optimal performance
- Fetches from both APIs in parallel using Promise.all()
- Merges data from multiple sources intelligently
- Deduplicates tokens using token address as unique identifier
- Prefers DexScreener data when tokens exist in both sources
4. REST API (app.ts)
- Exposes GET /api/tokens endpoint
- Accepts query parameter 'q' for token search
- Returns JSON array of aggregated token data
- Implements error handling with appropriate HTTP status codes
5. WebSocket Server (socket.ts)
- Provides real-time price updates every 10 seconds
- Broadcasts to all connected clients simultaneously
- Implements Socket.io for WebSocket functionality
- Runtime: Node.js v18+
- Language: TypeScript
- Framework: Express.js
- WebSocket: Socket.io
- Cache: Redis (Cloud-hosted)
- HTTP Client: Axios
- Testing: Jest, Supertest
The service fetches data from two sources:
-
DexScreener API - Provides comprehensive trading data including:
- Price in SOL
- Market capitalization
- 24-hour volume
- Liquidity
- Transaction counts
- Price change percentages
-
Jupiter API - Provides token metadata:
- Token addresses
- Token names and symbols
Merging Logic:
- Uses token address (lowercase) as unique identifier
- DexScreener data takes precedence for duplicates (more complete)
- Adds unique tokens found only in Jupiter
- Results in broader token coverage than single-source approach
Strategy: Cache-first with time-based invalidation
Flow:
- Check Redis cache for query key
- If cache hit: Return cached data immediately
- If cache miss: Fetch from APIs, merge, cache, then return
- Cache expires after 30 seconds
Benefits:
- Reduced API call frequency
- Faster response times
- Protection against rate limits
- API failures return empty arrays instead of crashing
- HTTP errors return 500 status with error message
- Missing data fields handled with optional chaining and default values
- All async operations wrapped in try-catch blocks
Retrieves aggregated token data from multiple DEX sources.
Query Parameters:
q(string, optional) - Search query for tokens (default: "SOL")
Example Request:
curl https://e-back-ca4c.onrender.com/api/tokens?q=SOLExample Response:
[
{
"token_address": "0x570A5D26f7765Ecb712C0924E4De545B89fD43dF",
"token_name": "Wrapped Solana",
"token_ticker": "SOL",
"price_sol": 68.02,
"market_cap_sol": 75228,
"volume_sol": 3127.31,
"liquidity_sol": 39240.99,
"transaction_count": 32,
"price_1hr_change": 0,
"protocol": "pancakeswap"
}
]Connect:
const socket = io('https://e-back-ca4c.onrender.com');Listen for updates:
socket.on('price-update', (data) => {
console.log('Received token updates:', data);
});Updates are broadcast every 10 seconds to all connected clients.
- Node.js 18 or higher
- Redis instance (cloud or local)
- Clone the repository:
git clone https://github.com/Augustus-118/e_back.git
cd e_back- Install dependencies:
npm install- Create .env file:
PORT=3000
REDIS_URL=redis://default:password@host:port- Build the project:
npm run build- Start the server:
# Development mode
npm run dev
# Production mode
npm startThe project includes comprehensive unit and integration tests.
Run tests:
npm testRun with coverage:
npm run test:coverageTest Coverage:
- 12 tests total (all passing)
- Covers service logic, API endpoints, caching, and error handling
- Tests use mocking to isolate units and avoid external dependencies
The application is deployed on Render (free tier).
Build Command: npm install && npm run build
Start Command: npm start
Environment Variables:
REDIS_URL- Redis connection stringPORT- Server port (auto-assigned by Render)
e_back/
├── src/
│ ├── __tests__/
│ │ ├── aggregator.test.ts # Service logic tests
│ │ └── api.test.ts # API endpoint tests
│ ├── services/
│ │ ├── fetcher.ts # API data fetching
│ │ ├── cache.ts # Redis caching
│ │ └── aggregator.ts # Data merging logic
│ ├── config.ts # Configuration management
│ ├── types.ts # TypeScript interfaces
│ ├── app.ts # Express routes
│ ├── socket.ts # WebSocket server
│ └── server.ts # Application entry point
├── dist/ # Compiled JavaScript
├── jest.config.js # Test configuration
├── tsconfig.json # TypeScript configuration
└── package.json # Dependencies and scripts
- Type safety catches errors at compile time
- Better IDE support and autocomplete
- Self-documenting code through interfaces
- In-memory storage provides sub-millisecond response times
- TTL feature handles automatic cache invalidation
- Cloud-hosted solution requires no local infrastructure
- Promise.all() executes both API calls simultaneously
- Reduces total wait time from 4 seconds to 2 seconds
- Improves user experience with faster responses
- Push-based updates eliminate need for client polling
- Reduces bandwidth usage
- Provides true real-time experience
- Multi-API data aggregation (DexScreener + Jupiter)
- Redis caching with configurable TTL
- Real-time WebSocket updates
- REST API with filtering support
- Error handling and rate limit consideration
- Token deduplication and merging
- Deployed to free hosting (Render)
- Comprehensive documentation
- Unit and integration tests (12 tests)
- Postman collection included
- Jupiter API provides limited data compared to DexScreener
- Cache invalidation is time-based only (no manual invalidation)
- No authentication or authorization implemented
- Rate limits depend on external API providers
- Add more DEX sources for broader coverage
- Implement cursor-based pagination
- Add filtering by time period (1h, 24h, 7d)
- Implement sorting by various metrics
- Add request rate limiting
- Implement cache warming strategies
Created as part of backend internship assessment.
ISC