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 db = new DialogueDB({ apiKey: process.env.DIALOGUE_DB_API_KEY });
async function saveMessageWithRetry(dialogueId: string, content: string, maxRetries = 3) {
const dialogue = await db.getDialogue(dialogueId);
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const message = await dialogue.saveMessage({
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 - wait progressively longer between retries
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 | Wait and retry (progressively longer delays) |
| 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 db.listDialogues({
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 db.listDialogues({
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(dialogue: any, messages: any[]) {
for (const msg of messages) {
await dialogue.saveMessage(msg);
}
}
// Better: Use the bulk method
async function addMessagesBulk(dialogue: any, messages: any[]) {
await dialogue.saveMessages(messages);
}
// Best: Use dialogue creation with messages array
async function createDialogueWithHistory(messages: any[]) {
return await db.createDialogue({
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 db.getDialogue(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 db: DialogueDB;
private requestCount: number = 0;
private windowStart: number = Date.now();
private limit: number = 1000; // requests per minute
constructor(apiKey: string) {
this.db = 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(() =>
db.createDialogue({ messages: [{ role: 'user', content: 'Hello' }] })
);Data Management
Message Size Optimization
Keep messages concise when possible:
typescript
// Avoid: Storing entire documents
await dialogue.saveMessage({
role: 'assistant',
content: entireDocument // 50KB of text
});
// Better: Store summary with reference
await dialogue.saveMessage({
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 db.getDialogue(dialogueId);
// End inactive conversations
const lastMessage = dialogue.lastMessageCreated;
const hoursSinceLastMessage = (Date.now() - new Date(lastMessage).getTime()) / (1000 * 60 * 60);
if (hoursSinceLastMessage > 24) {
await dialogue.end();
console.log(`Ended inactive dialogue ${dialogueId}`);
}
}State Management
Keep state objects focused and minimal:
typescript
// Avoid: Bloated state
await dialogue.saveState({
entireConversationHistory: messages, // Redundant
userProfile: completeUserObject, // Too large
sessionData: everythingEver // Unfocused
});
// Better: Focused state
await dialogue.saveState({
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 db = new DialogueDB({
apiKey: 'sk_live_abc123...' // Exposed in browser!
});
// Use server-side proxy
// Backend (Express.js)
app.post('/api/chat', async (req, res) => {
const db = new DialogueDB({
apiKey: process.env.DIALOGUE_DB_API_KEY // Server-side only
});
const dialogue = await db.getDialogue(req.body.dialogueId);
const result = await dialogue.saveMessage(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(dialogue: any, userInput: string) {
validateMessage(userInput);
return await dialogue.saveMessage({
role: 'user',
content: userInput
});
}Monitoring & Logging
Implement Request Logging
Track API usage for debugging and monitoring:
typescript
class LoggingClient {
private db: DialogueDB;
private logger: any;
constructor(apiKey: string, logger: any) {
this.db = new DialogueDB({ apiKey });
this.logger = logger;
}
async saveMessage(dialogueId: string, message: any) {
const startTime = Date.now();
try {
this.logger.info('Saving message', {
dialogueId,
role: message.role,
contentLength: message.content.length
});
const dialogue = await this.db.getDialogue(dialogueId);
const result = await dialogue.saveMessage(message);
this.logger.info('Message saved successfully', {
dialogueId,
messageId: result.id,
duration: Date.now() - startTime
});
return result;
} catch (error) {
this.logger.error('Failed to save 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__/dialogue-db.ts
export class DialogueDB {
createDialogue = jest.fn();
getDialogue = jest.fn();
listDialogues = jest.fn();
}
// Mock Dialogue instance
export const mockDialogue = {
saveMessage: jest.fn(),
saveMessages: jest.fn(),
loadMessages: jest.fn(),
saveState: jest.fn(),
save: jest.fn(),
};
// yourCode.test.ts
jest.mock('dialogue-db');
describe('Chat Handler', () => {
it('should save message', async () => {
const db = new DialogueDB({});
db.getDialogue.mockResolvedValue(mockDialogue);
mockDialogue.saveMessage.mockResolvedValue({
id: 'msg_123',
content: 'Hello'
});
const result = await handleUserMessage('dialogue_123', 'Hello');
expect(db.getDialogue).toHaveBeenCalledWith('dialogue_123');
expect(mockDialogue.saveMessage).toHaveBeenCalledWith(
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

