Appearance
Best Practices
Follow these best practices to build robust, scalable, and efficient applications with DialogueDB.
Error Handling
Implement Comprehensive Error Handling
Always handle errors gracefully in production applications:
typescript
import { DialogueDB } from 'dialogue-db';
const client = new DialogueDB({ apiKey: process.env.DIALOGUE_DB_API_KEY });
async function createMessageWithRetry(dialogueId: string, content: string, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const message = await client.messages.create(dialogueId, {
role: 'user',
content
});
return message;
} catch (error) {
// Handle specific error types
if (error.status === 401) {
throw new Error('Authentication failed - check your API token');
} else if (error.status === 404) {
throw new Error(`Dialogue ${dialogueId} not found`);
} else if (error.status === 429) {
// Rate limited - exponential backoff
if (attempt < maxRetries) {
const delay = Math.pow(2, attempt) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
throw new Error('Rate limit exceeded - try again later');
} else if (error.status >= 500) {
// Server error - retry
if (attempt < maxRetries) {
await new Promise(resolve => setTimeout(resolve, 1000));
continue;
}
throw new Error('Server error - please try again later');
}
// Unknown error
throw error;
}
}
}Common Error Scenarios
| Error Code | Meaning | Action |
|---|---|---|
| 400 | Bad Request | Validate input before sending |
| 401 | Unauthorized | Check API token |
| 404 | Not Found | Verify resource ID |
| 429 | Rate Limited | Implement exponential backoff |
| 500 | Server Error | Retry with backoff |
Performance Optimization
Pagination Strategy
Always use pagination for large datasets:
typescript
async function getAllDialogues() {
const allDialogues = [];
let nextToken = null;
do {
const { items, next } = await client.dialogues.list({
limit: 100,
next: nextToken
});
allDialogues.push(...items);
nextToken = next;
} while (nextToken);
return allDialogues;
}
// Better: Process in chunks
async function processDialoguesInChunks(processor: (dialogues: any[]) => Promise<void>) {
let nextToken = null;
do {
const { items, next } = await client.dialogues.list({
limit: 100,
next: nextToken
});
// Process this batch
await processor(items);
nextToken = next;
} while (nextToken);
}Batch Message Creation
When adding multiple messages, consider batching:
typescript
// ❌ Avoid: Sequential creation
async function addMessagesSequential(dialogueId: string, messages: any[]) {
for (const msg of messages) {
await client.messages.create(dialogueId, msg);
}
}
// ✅ Better: Parallel creation
async function addMessagesParallel(dialogueId: string, messages: any[]) {
await Promise.all(
messages.map(msg => client.messages.create(dialogueId, msg))
);
}
// ✅ Best: Use dialogue creation with messages array
async function createDialogueWithHistory(messages: any[]) {
return await client.dialogues.create({
messages: messages
});
}Caching Strategies
Cache frequently accessed dialogues:
typescript
class DialogueCache {
private cache: Map<string, { dialogue: any; timestamp: number }> = new Map();
private ttl: number = 5 * 60 * 1000; // 5 minutes
async get(dialogueId: string): Promise<any> {
const cached = this.cache.get(dialogueId);
if (cached && Date.now() - cached.timestamp < this.ttl) {
return cached.dialogue;
}
const dialogue = await client.dialogues.get(dialogueId);
this.cache.set(dialogueId, {
dialogue,
timestamp: Date.now()
});
return dialogue;
}
invalidate(dialogueId: string) {
this.cache.delete(dialogueId);
}
}Rate Limiting
Implement Rate Limit Awareness
Track and respect rate limits:
typescript
class RateLimitedClient {
private client: DialogueDB;
private requestCount: number = 0;
private windowStart: number = Date.now();
private limit: number = 1000; // requests per minute
constructor(apiKey: string) {
this.client = new DialogueDB({ apiKey });
}
async request<T>(fn: () => Promise<T>): Promise<T> {
// Reset window if minute has passed
const now = Date.now();
if (now - this.windowStart > 60000) {
this.requestCount = 0;
this.windowStart = now;
}
// Check if we're approaching limit
if (this.requestCount >= this.limit) {
const waitTime = 60000 - (now - this.windowStart);
await new Promise(resolve => setTimeout(resolve, waitTime));
this.requestCount = 0;
this.windowStart = Date.now();
}
this.requestCount++;
return await fn();
}
}
// Usage
const rateLimitedClient = new RateLimitedClient(process.env.DIALOGUE_DB_API_KEY);
const dialogue = await rateLimitedClient.request(() =>
client.dialogues.create({ message: { role: 'user', content: 'Hello' } })
);Data Management
Message Size Optimization
Keep messages concise when possible:
typescript
// ❌ Avoid: Storing entire documents
await client.messages.create(dialogueId, {
role: 'assistant',
content: entireDocument // 50KB of text
});
// ✅ Better: Store summary with reference
await client.messages.create(dialogueId, {
role: 'assistant',
content: 'Here is a summary of the document...',
metadata: {
documentId: 'doc_123',
documentUrl: 'https://example.com/docs/123'
}
});Conversation Lifecycle Management
End conversations when appropriate:
typescript
async function manageConversationLifecycle(dialogueId: string) {
const dialogue = await client.dialogues.get(dialogueId);
// End inactive conversations
const lastMessage = dialogue.lastMessageCreated;
const hoursSinceLastMessage = (Date.now() - new Date(lastMessage).getTime()) / (1000 * 60 * 60);
if (hoursSinceLastMessage > 24) {
await client.dialogues.action(dialogueId, 'end');
console.log(`Ended inactive dialogue ${dialogueId}`);
}
// Compact long conversations
if (dialogue.totalMessages > 50) {
await client.dialogues.action(dialogueId, 'compact');
console.log(`Compacted long dialogue ${dialogueId}`);
}
}State Management
Keep state objects focused and minimal:
typescript
// ❌ Avoid: Bloated state
await client.dialogues.update(dialogueId, {
state: {
entireConversationHistory: messages, // Redundant
userProfile: completeUserObject, // Too large
sessionData: everythingEver // Unfocused
}
});
// ✅ Better: Focused state
await client.dialogues.update(dialogueId, {
state: {
currentIntent: 'book_appointment',
step: 'date_selection',
collectedData: {
date: '2025-01-20',
time: null
}
}
});Security
Token Management
Never expose tokens in client-side code:
typescript
// ❌ NEVER DO THIS
const client = new DialogueDB({
apiKey: 'sk_live_abc123...' // Exposed in browser!
});
// ✅ Use server-side proxy
// Backend (Express.js)
app.post('/api/chat', async (req, res) => {
const client = new DialogueDB({
apiKey: process.env.DIALOGUE_DB_API_KEY // Server-side only
});
const result = await client.messages.create(
req.body.dialogueId,
req.body.message
);
res.json(result);
});
// Frontend
fetch('/api/chat', {
method: 'POST',
body: JSON.stringify({ dialogueId, message })
});Input Validation
Always validate user input:
typescript
function validateMessage(content: string): boolean {
// Check length
if (content.length === 0 || content.length > 100000) {
throw new Error('Message content must be between 1 and 100,000 characters');
}
// Check for malicious content
if (containsMaliciousPatterns(content)) {
throw new Error('Invalid message content');
}
return true;
}
async function createSafeMessage(dialogueId: string, userInput: string) {
validateMessage(userInput);
return await client.messages.create(dialogueId, {
role: 'user',
content: userInput
});
}Monitoring & Logging
Implement Request Logging
Track API usage for debugging and monitoring:
typescript
class LoggingClient {
private client: DialogueDB;
private logger: any;
constructor(apiKey: string, logger: any) {
this.client = new DialogueDB({ apiKey });
this.logger = logger;
}
async createMessage(dialogueId: string, message: any) {
const startTime = Date.now();
try {
this.logger.info('Creating message', {
dialogueId,
role: message.role,
contentLength: message.content.length
});
const result = await this.client.messages.create(dialogueId, message);
this.logger.info('Message created successfully', {
dialogueId,
messageId: result.id,
duration: Date.now() - startTime
});
return result;
} catch (error) {
this.logger.error('Failed to create message', {
dialogueId,
error: error.message,
duration: Date.now() - startTime
});
throw error;
}
}
}Track Metrics
Monitor key performance indicators:
typescript
class MetricsTracker {
private metrics = {
requestCount: 0,
errorCount: 0,
averageResponseTime: 0,
rateLimitHits: 0
};
trackRequest(duration: number, success: boolean) {
this.metrics.requestCount++;
if (!success) this.metrics.errorCount++;
// Update average response time
this.metrics.averageResponseTime =
(this.metrics.averageResponseTime * (this.metrics.requestCount - 1) + duration) /
this.metrics.requestCount;
}
trackRateLimit() {
this.metrics.rateLimitHits++;
}
getMetrics() {
return {
...this.metrics,
errorRate: this.metrics.errorCount / this.metrics.requestCount,
successRate: (this.metrics.requestCount - this.metrics.errorCount) / this.metrics.requestCount
};
}
}Testing
Mock DialogueDB in Tests
typescript
// __mocks__/dialoguedb.ts
export class DialogueDB {
dialogues = {
create: jest.fn(),
get: jest.fn(),
list: jest.fn(),
action: jest.fn()
};
messages = {
create: jest.fn(),
list: jest.fn()
};
}
// yourCode.test.ts
jest.mock('dialoguedb');
describe('Chat Handler', () => {
it('should create message', async () {
const mockClient = new DialogueDB({});
mockClient.messages.create.mockResolvedValue({
id: 'msg_123',
content: 'Hello'
});
const result = await handleUserMessage('dialogue_123', 'Hello');
expect(mockClient.messages.create).toHaveBeenCalledWith(
'dialogue_123',
expect.objectContaining({ content: 'Hello' })
);
});
});Checklist
Before deploying to production:
- [ ] API tokens stored securely (environment variables/secrets manager)
- [ ] Error handling implemented with retries
- [ ] Rate limiting awareness in place
- [ ] Pagination used for all list operations
- [ ] Input validation on all user-provided data
- [ ] Logging and monitoring configured
- [ ] Inactive conversations cleaned up regularly
- [ ] Long conversations compacted or ended
- [ ] Tests cover error scenarios
- [ ] Client-side code uses server proxy (never exposes tokens)
Next Steps
- Complete Examples - Full end-to-end implementations
- API Reference - Detailed endpoint documentation
- Use Cases - Common conversation patterns