tcg-api-client
v1.0.1
Published
JavaScript/TypeScript client for the TCG API - Pokemon, Lorcana, Magic: The Gathering
Maintainers
Readme
TCG API Client
Official JavaScript/TypeScript client for the TCG API - supporting Pokemon, Lorcana, and Magic: The Gathering.
Installation
npm install tcg-api-clientQuick Start
import { TcgApiClient } from 'tcg-api-client';
// Uses https://api.tcg-api.eu by default
const client = new TcgApiClient({
apiKey: 'your-api-key' // Optional but recommended for higher rate limits
});
// Get Pokemon cards
const cards = await client.pokemon.getCards();
console.log(cards.items);
// Search Lorcana cards
const results = await client.lorcana.search({ name: 'Elsa' });
console.log(results.items);
// Get Magic sets
const sets = await client.magic.getSets();
console.log(sets.items);Features
- Full TypeScript support
- Built-in caching with pluggable adapters
- Automatic pagination helpers
- Rate limit tracking
- Retry logic for failed requests
- Works in Node.js and browsers
Configuration
const client = new TcgApiClient({
// Base URL of the API (default: 'https://api.tcg-api.eu')
baseUrl: 'https://api.tcg-api.eu',
// API key for higher rate limits (optional)
apiKey: 'your-api-key',
// Request timeout in ms (default: 30000)
timeout: 30000,
// Cache configuration (default: in-memory cache)
cache: new MemoryCache({ maxEntries: 1000 }),
// Or disable caching:
// cache: false,
// Custom TTL per endpoint type (in seconds)
cacheTTL: {
tcgList: 3600, // 1 hour
sets: 3600, // 1 hour
cards: 900, // 15 minutes
search: 900, // 15 minutes
changelog: 300 // 5 minutes
},
// Retry configuration
retry: {
maxRetries: 3,
retryDelay: 1000,
retryOn: [502, 503, 504]
}
});TCG Clients
Access TCG-specific data through dedicated clients:
// Pokemon (English)
client.pokemon.getCards()
client.pokemon.getSets()
client.pokemon.search({ name: 'Pikachu' })
// Pokemon (Japanese)
client.pokemonJa.getCards()
// Pokemon (Chinese Traditional)
client.pokemonZhTw.getCards()
// Lorcana
client.lorcana.getCards()
// Magic: The Gathering
client.magic.getCards()
// Or access any TCG by name
client.tcg('pokemon').getCards()Pagination
Manual Pagination
// Get specific page
const page1 = await client.pokemon.getCards({ page: 1, limit: 50 });
console.log(page1.items); // Cards on this page
console.log(page1.pagination); // { page, limit, total, totalPages, hasNext, hasPrev }
// Get next page
if (page1.pagination.hasNext) {
const page2 = await client.pokemon.getCards({ page: 2, limit: 50 });
}Auto-Fetch All Pages
// Fetch all cards (handles pagination automatically)
const allCards = await client.pokemon.getAllCards();
// With progress callback
const cards = await client.pokemon.getAllCards({
onProgress: (fetched, total) => {
console.log(`Fetched ${fetched}/${total} cards`);
}
});Async Iterator
// Stream cards one at a time
for await (const card of client.pokemon.cardsIterator()) {
console.log(card.name);
}
// With custom page size
for await (const card of client.pokemon.cardsIterator({ limit: 100 })) {
console.log(card.name);
}Search
// Search by various criteria
const results = await client.pokemon.search({
q: 'fire', // General search (name + flavor text)
name: 'Charizard', // Filter by name
set: 'base1', // Filter by set ID
type: 'Fire', // Filter by type
rarity: 'Rare', // Filter by rarity
page: 1,
limit: 20
});
// Get all search results
const allResults = await client.pokemon.searchAll({ name: 'Pikachu' });
// Stream search results
for await (const card of client.pokemon.searchIterator({ type: 'Water' })) {
console.log(card.name);
}Caching
Default In-Memory Cache
import { TcgApiClient, MemoryCache } from 'tcg-api-client';
const client = new TcgApiClient({
cache: new MemoryCache({ maxEntries: 1000 })
});Custom Cache Adapter
Implement the CacheAdapter interface for custom caching (Redis, localStorage, etc.):
import { CacheAdapter, CacheEntry } from 'tcg-api-client';
class RedisCache implements CacheAdapter {
constructor(private redis: Redis) {}
async get<T>(key: string): Promise<CacheEntry<T> | null> {
const data = await this.redis.get(key);
return data ? JSON.parse(data) : null;
}
async set<T>(key: string, data: T, ttl: number): Promise<void> {
await this.redis.setex(key, ttl, JSON.stringify({
data,
timestamp: Date.now(),
ttl
}));
}
async delete(key: string): Promise<void> {
await this.redis.del(key);
}
async clear(): Promise<void> {
const keys = await this.redis.keys('tcg_api:*');
if (keys.length) await this.redis.del(...keys);
}
async has(key: string): Promise<boolean> {
return (await this.redis.exists(key)) === 1;
}
async keys(): Promise<string[]> {
return this.redis.keys('tcg_api:*');
}
}
const client = new TcgApiClient({
cache: new RedisCache(redisClient)
});Cache Management
// Clear all cache
await client.clearCache();
// Clear cache for specific TCG
await client.clearCacheForTcg('pokemon');
// Clear cache for endpoint type
await client.clearCacheForEndpoint('cards');
// Check if caching is enabled
client.isCacheEnabled(); // trueRate Limits
// Check rate limit after any request
const info = client.getRateLimitInfo();
if (info) {
console.log(`Daily: ${info.remainingDaily}/${info.limitDaily}`);
console.log(`Minute: ${info.remainingMinute}/${info.limitMinute}`);
if (info.isNearDailyLimit) {
console.warn('Approaching daily limit!');
}
}Error Handling
import {
TcgApiError,
RateLimitError,
NotFoundError,
ValidationError,
NetworkError
} from 'tcg-api-client';
try {
const card = await client.pokemon.getCard('invalid-id');
} catch (error) {
if (error instanceof NotFoundError) {
console.log('Card not found');
} else if (error instanceof RateLimitError) {
console.log(`Rate limited. Retry after ${error.retryAfter} seconds`);
console.log(`Reset time: ${error.resetTime}`);
} else if (error instanceof ValidationError) {
console.log('Invalid request:', error.message);
} else if (error instanceof NetworkError) {
console.log('Network error:', error.message);
if (error.isTimeout) {
console.log('Request timed out');
}
} else if (error instanceof TcgApiError) {
console.log(`API error (${error.statusCode}): ${error.message}`);
}
}Global Endpoints
// Get list of available TCGs
const tcgs = await client.getTcgList();
// Get statistics for all TCGs
const stats = await client.getStats();
// Get sample cards from all TCGs
const samples = await client.getSamples();Changelog
// Get recent import runs
const recent = await client.getRecentImports(10);
// Get latest changes across all TCGs
const changes = await client.getLatestChanges(100);
// Get changelog for specific TCG
const pokemonChanges = await client.getTcgChangelog('pokemon', 50);
// Get changelog statistics
const stats = await client.getChangelogStats(30); // Last 30 daysTypeScript
Full TypeScript support with comprehensive type definitions:
import type {
PokemonCard,
LorcanaCard,
MagicCard,
TcgSet,
SearchParams,
PaginatedResponse
} from 'tcg-api-client';
// Types are inferred automatically
const cards = await client.pokemon.getCards();
// cards is PaginatedResponse<TcgCard>
const card = await client.pokemon.getCard('base1-4');
// card.card is typed based on the TCGLicense
MIT
