diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..c521bca3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +node_modules/ +dist/ +.env +*.log +.DS_Store +__pycache__ +.vscode/ +*.swp +.idea/ +coverage/ +.nyc_output/ \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 00000000..b5067a67 --- /dev/null +++ b/package.json @@ -0,0 +1,22 @@ +{ + "name": "coin-gekko-api", + "version": "1.0.0", + "description": "Coin Gekko API for cryptocurrency trading", + "main": "dist/index.js", + "scripts": { + "build": "tsc", + "test": "vitest", + "start": "node dist/index.js" + }, + "keywords": ["cryptocurrency", "trading", "api"], + "author": "", + "license": "ISC", + "devDependencies": { + "@types/node": "^16.11.10", + "typescript": "^4.5.4", + "vitest": "^0.25.3" + }, + "dependencies": { + "axios": "^0.24.0" + } +} \ No newline at end of file diff --git a/src/index.test.ts b/src/index.test.ts new file mode 100644 index 00000000..4eeb32cb --- /dev/null +++ b/src/index.test.ts @@ -0,0 +1,37 @@ +import { describe, it, expect } from 'vitest'; +import { CoinGekkoApi } from './index'; + +describe('CoinGekkoApi', () => { + const api = new CoinGekkoApi(); + + it('should fetch coin data for bitcoin', async () => { + const result = await api.fetchCoinData('bitcoin'); + + expect(result.success).toBe(true); + expect(result.data).toHaveProperty('id', 'bitcoin'); + expect(result.data).toHaveProperty('symbol'); + expect(result.data).toHaveProperty('name'); + expect(result.data.price).toBeGreaterThan(0); + }); + + it('should list top coins', async () => { + const result = await api.listCoins(10); + + expect(result.success).toBe(true); + expect(result.data.length).toBe(10); + + result.data.forEach(coin => { + expect(coin).toHaveProperty('id'); + expect(coin).toHaveProperty('symbol'); + expect(coin).toHaveProperty('name'); + expect(coin.price).toBeGreaterThan(0); + }); + }); + + it('should handle invalid coin id', async () => { + const result = await api.fetchCoinData('non_existent_coin'); + + expect(result.success).toBe(false); + expect(result.error).toBeTruthy(); + }); +}); \ No newline at end of file diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 00000000..980c13e4 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,86 @@ +import axios from 'axios'; +import { CoinData, CoinGekkoApiOptions, FetchResult } from './types'; + +export class CoinGekkoApi { + private baseUrl: string; + private apiKey?: string; + + constructor(options: CoinGekkoApiOptions = {}) { + this.baseUrl = options.baseUrl || 'https://api.coingecko.com/api/v3'; + this.apiKey = options.apiKey; + } + + async fetchCoinData(coinId: string): Promise> { + try { + const response = await axios.get(`${this.baseUrl}/coins/${coinId}`); + + if (response.status !== 200) { + return { + success: false, + data: {} as CoinData, + error: 'Failed to fetch coin data' + }; + } + + const data = response.data; + return { + success: true, + data: { + id: data.id, + symbol: data.symbol, + name: data.name, + price: data.market_data.current_price.usd, + marketCap: data.market_data.market_cap.usd, + volume24h: data.market_data.total_volume.usd + } + }; + } catch (error) { + return { + success: false, + data: {} as CoinData, + error: error instanceof Error ? error.message : 'Unknown error' + }; + } + } + + async listCoins(limit: number = 100): Promise> { + try { + const response = await axios.get(`${this.baseUrl}/coins/markets`, { + params: { + vs_currency: 'usd', + order: 'market_cap_desc', + per_page: limit, + page: 1 + } + }); + + if (response.status !== 200) { + return { + success: false, + data: [], + error: 'Failed to fetch coin list' + }; + } + + const coins: CoinData[] = response.data.map((coin: any) => ({ + id: coin.id, + symbol: coin.symbol, + name: coin.name, + price: coin.current_price, + marketCap: coin.market_cap, + volume24h: coin.total_volume + })); + + return { + success: true, + data: coins + }; + } catch (error) { + return { + success: false, + data: [], + error: error instanceof Error ? error.message : 'Unknown error' + }; + } + } +} \ No newline at end of file diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 00000000..7b7a7492 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,19 @@ +export interface CoinData { + id: string; + symbol: string; + name: string; + price: number; + marketCap: number; + volume24h: number; +} + +export interface CoinGekkoApiOptions { + apiKey?: string; + baseUrl?: string; +} + +export interface FetchResult { + data: T; + success: boolean; + error?: string; +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..aa8d2992 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "es2020", + "module": "commonjs", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "outDir": "./dist", + "rootDir": "./src" + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "**/*.spec.ts"] +} \ No newline at end of file