@feizk/rest
v1.0.0
Published
A TypeScript REST client for the Discord API
Maintainers
Readme
@feizk/rest
A TypeScript REST client for the Discord API with advanced rate limiting, error handling, and middleware support.
✨ Features
- 🚀 TypeScript-first with strict type safety and full Discord API type integration
- ⚡ Native fetch HTTP client with zero external dependencies (except Discord types)
- 🛡️ Advanced rate limiting with per-route bucket queuing and global rate limit handling
- 🎯 Intelligent retries with exponential backoff for failed requests
- 📝 Rich error context with developer-friendly messages and actionable suggestions
- 🔧 Extensible middleware system for logging, caching, and custom request/response handling
- 📦 Minimal bundle size with tree-shaking support and optimized builds
📦 Installation
npm install @feizk/rest
# or
yarn add @feizk/rest
# or
pnpm add @feizk/rest🚀 Quick Start
import { RestClient } from '@feizk/rest';
// Initialize the client
const client = new RestClient({
token: 'your-bot-token',
debug: true // Enable debug logging
});
// Make requests
const user = await client.get('/users/@me');
console.log(`Logged in as ${user.data.username}`);
// Send a message
const message = await client.post('/channels/123456789/messages', {
content: 'Hello from @feizk/rest! 👋'
});📚 API Reference
RestClient
Constructor Options
interface RestClientOptions {
token: string; // Discord bot token (required)
version?: number; // API version (default: 10)
baseURL?: string; // API base URL (default: https://discord.com/api)
timeout?: number; // Request timeout in ms (default: 15000)
retries?: number; // Max retry attempts (default: 3)
userAgent?: string; // Custom user agent
headers?: Record<string, string>; // Additional headers
debug?: boolean; // Enable debug logging (default: false)
rateLimitOffset?: number; // Rate limit safety offset in ms (default: 500)
}HTTP Methods
// GET request
const response = await client.get<APIUser>('/users/@me');
// POST request with body
const message = await client.post('/channels/123/messages', {
content: 'Hello, World!'
});
// PATCH request
const updatedUser = await client.patch('/users/@me', {
username: 'NewUsername'
});
// DELETE request
await client.delete('/channels/123/messages/456');
// Generic request with full options
const response = await client.request({
method: 'POST',
path: '/channels/123/messages',
body: { content: 'Hello!' },
query: { limit: 50 },
headers: { 'X-Custom-Header': 'value' },
reason: 'Audit log reason'
});Middleware System
Add hooks to customize request/response handling:
client.addHook({
beforeRequest: async (data) => {
console.log(`📤 ${data.method} ${data.path}`);
},
afterResponse: async (response, data) => {
console.log(`📥 ${response.status} ${data.path}`);
},
onError: async (error, data) => {
console.error(`❌ Error on ${data.path}:`, error.message);
},
onRateLimit: async (info, data) => {
console.warn(`⏱️ Rate limited on ${data.path}, waiting ${info.retryAfter}ms`);
}
});Error Handling
The client provides rich error information with actionable suggestions:
try {
await client.get('/channels/invalid-id/messages');
} catch (error) {
if (error instanceof DiscordAPIError) {
console.log(error.getFullMessage());
// Includes HTTP status, Discord error code, and suggestions
}
}Error Types
RestError: Base error class with request contextDiscordAPIError: Discord API errors with code mapping and suggestionsRateLimitError: Rate limiting errors with retry informationHTTPError: HTTP transport errors
Rate Limiting
The client automatically handles Discord's complex rate limiting:
// Requests are automatically queued and managed per route
const promises = [
client.get('/channels/123/messages'),
client.get('/channels/123/messages'),
client.get('/channels/123/messages'), // These will be queued properly
];
const responses = await Promise.all(promises);🔧 Advanced Usage
File Uploads
const file = {
name: 'image.png',
data: imageBuffer,
contentType: 'image/png'
};
await client.post('/channels/123/messages',
{ content: 'Check out this image!' },
{ files: [file] }
);Custom Configuration
const client = new RestClient({
token: process.env.DISCORD_TOKEN!,
baseURL: 'https://discord.com/api',
version: 10,
timeout: 30000,
retries: 5,
debug: process.env.NODE_ENV === 'development',
rateLimitOffset: 1000, // Extra safety margin
headers: {
'X-My-App': 'MyBot/1.0.0'
}
});Bypassing Rate Limits
// For critical requests (use sparingly)
await client.get('/users/@me', {
bypassRateLimit: true
});🏗️ TypeScript Support
Full TypeScript support with Discord API types:
import type {
RESTGetAPIUserResult,
RESTPostAPIChannelMessageJSONBody,
RESTPostAPIChannelMessageResult
} from '@feizk/rest';
// Fully typed requests and responses
const user = await client.get<RESTGetAPIUserResult>('/users/@me');
const message = await client.post<
RESTPostAPIChannelMessageResult,
RESTPostAPIChannelMessageJSONBody
>('/channels/123/messages', {
content: 'Typed message!'
});🧪 Testing
# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Run tests in watch mode
npm run test:watch🔨 Building
# Build the package
npm run build
# Build in watch mode
npm run dev📝 Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
📜 License
This project is licensed under the MIT License - see the LICENSE file for details.
🙏 Acknowledgments
- Built with discord-api-types for comprehensive Discord API typing
