Best Practices 
This guide covers best practices for integrating PocketDNS into your application.
Performance 
API Request Optimization 
Batch Operations 
When possible, batch API operations to reduce latency:
javascript
// Instead of multiple individual requests
const domains = await Promise.all([
  getDomainDetails(domainId1),
  getDomainDetails(domainId2),
  getDomainDetails(domainId3)
]);
// Use batch endpoint when available
const domains = await getBatchDomains([domainId1, domainId2, domainId3]);Caching User Sessions 
Cache user sessions to avoid unnecessary API calls:
javascript
class SessionCache {
  constructor(ttl = 20 * 60 * 1000) { // 20 minutes
    this.cache = new Map();
    this.ttl = ttl;
  }
  get(userIdentifier) {
    const cached = this.cache.get(userIdentifier);
    if (cached && Date.now() - cached.timestamp < this.ttl) {
      return cached.session;
    }
    return null;
  }
  set(userIdentifier, session) {
    this.cache.set(userIdentifier, {
      session,
      timestamp: Date.now()
    });
  }
  clear(userIdentifier) {
    this.cache.delete(userIdentifier);
  }
}
const sessionCache = new SessionCache();Connection Pooling 
Use connection pooling for high-traffic applications:
javascript
const https = require('https');
const agent = new https.Agent({
  keepAlive: true,
  keepAliveMsecs: 30000,
  maxSockets: 50
});
const fetch = require('node-fetch');
const pocketDNSFetch = (url, options = {}) => {
  return fetch(url, { ...options, agent });
};Frontend Optimization 
Lazy Loading 
Load the PocketDNS iframe only when needed:
jsx
import React, { useState, lazy, Suspense } from 'react';
const PocketDNSEmbed = lazy(() => import('./PocketDNSEmbed'));
const DomainManagement = () => {
  const [showEmbed, setShowEmbed] = useState(false);
  return (
    <div>
      {!showEmbed ? (
        <button onClick={() => setShowEmbed(true)}>
          Manage Domains
        </button>
      ) : (
        <Suspense fallback={<div>Loading...</div>}>
          <PocketDNSEmbed />
        </Suspense>
      )}
    </div>
  );
};Preloading Sessions 
Preload user sessions for better UX:
javascript
// Preload session when user navigates to domain page
const preloadSession = async (userIdentifier) => {
  if (!sessionCache.get(userIdentifier)) {
    const session = await createUserSession(userIdentifier);
    sessionCache.set(userIdentifier, session);
  }
};User Experience 
Loading States 
Always provide clear loading states:
jsx
const PocketDNSEmbed = ({ userIdentifier }) => {
  const [state, setState] = useState('loading'); // loading, ready, error
  return (
    <div className="pocketdns-container">
      {state === 'loading' && (
        <div className="loading-state">
          <div className="spinner" />
          <p>Setting up your domain interface...</p>
        </div>
      )}
      {state === 'error' && (
        <div className="error-state">
          <p>Unable to load domain interface. Please try again.</p>
          <button onClick={retry}>Retry</button>
        </div>
      )}
      {state === 'ready' && (
        <iframe src={loginUrl} {...iframeProps} />
      )}
    </div>
  );
};Error Handling 
Provide helpful error messages:
javascript
const handleAPIError = (error, context) => {
  const errorMessages = {
    401: 'Authentication failed. Please check your API key.',
    403: 'Insufficient permissions for this operation.',
    404: 'The requested resource was not found.',
    429: 'Rate limit exceeded. Please try again later.',
    500: 'Server error. Please try again later.'
  };
  const message = errorMessages[error.status] || 'An unexpected error occurred.';
  
  console.error(`PocketDNS API Error (${context}):`, error);
  
  return {
    message,
    status: error.status,
    context,
    timestamp: new Date().toISOString()
  };
};Responsive Design 
Ensure the embed works on all devices:
css
.pocketdns-embed {
  width: 100%;
  height: 600px;
  min-height: 400px;
  border: none;
  border-radius: 8px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
@media (max-width: 768px) {
  .pocketdns-embed {
    height: 500px;
    border-radius: 4px;
  }
}
@media (max-width: 480px) {
  .pocketdns-embed {
    height: 400px;
    border-radius: 0;
  }
}Security 
API Key Management 
Never expose API keys client-side:
javascript
// ❌ Wrong - API key exposed
const session = await fetch('https://api.pocketdns.com/api/v1/users', {
  headers: {
    'Authorization': 'Bearer sk_live_...' // NEVER DO THIS
  }
});
// ✅ Correct - API key on server
const session = await fetch('/api/pocketdns/session', {
  method: 'POST',
  body: JSON.stringify({ userIdentifier })
});Input Validation 
Always validate user input:
javascript
const validateUserIdentifier = (identifier) => {
  if (!identifier || typeof identifier !== 'string') {
    throw new Error('User identifier is required and must be a string');
  }
  if (identifier.length > 255) {
    throw new Error('User identifier too long');
  }
  if (!/^[a-zA-Z0-9_-]+$/.test(identifier)) {
    throw new Error('User identifier contains invalid characters');
  }
  return identifier.trim();
};Rate Limiting 
Implement client-side rate limiting:
javascript
class RateLimiter {
  constructor(maxRequests = 100, windowMs = 60000) {
    this.requests = [];
    this.maxRequests = maxRequests;
    this.windowMs = windowMs;
  }
  canMakeRequest() {
    const now = Date.now();
    this.requests = this.requests.filter(time => now - time < this.windowMs);
    return this.requests.length < this.maxRequests;
  }
  recordRequest() {
    this.requests.push(Date.now());
  }
}
const rateLimiter = new RateLimiter(100, 60000); // 100 requests per minuteMonitoring 
Request Logging 
Log all API requests for debugging:
javascript
const logAPIRequest = (method, url, status, duration, error = null) => {
  const logData = {
    timestamp: new Date().toISOString(),
    method,
    url,
    status,
    duration,
    error: error?.message,
    userAgent: navigator?.userAgent
  };
  if (process.env.NODE_ENV === 'development') {
    console.log('PocketDNS API Request:', logData);
  } else {
    // Send to your logging service
    sendToLogger(logData);
  }
};Health Checks 
Monitor API health:
javascript
const checkAPIHealth = async () => {
  try {
    const start = Date.now();
    const response = await fetch('https://api.pocketdns.com/health');
    const duration = Date.now() - start;
    
    return {
      status: response.ok ? 'healthy' : 'unhealthy',
      responseTime: duration,
      timestamp: new Date().toISOString()
    };
  } catch (error) {
    return {
      status: 'error',
      error: error.message,
      timestamp: new Date().toISOString()
    };
  }
};Error Tracking 
Track errors for analysis:
javascript
const trackError = (error, context) => {
  const errorData = {
    message: error.message,
    stack: error.stack,
    context,
    userIdentifier: getCurrentUser()?.id,
    url: window.location.href,
    timestamp: new Date().toISOString()
  };
  // Send to error tracking service
  if (window.Sentry) {
    Sentry.captureException(error, { extra: errorData });
  } else {
    console.error('PocketDNS Error:', errorData);
  }
};Code Organization 
Service Layer Pattern 
Organize API calls in a service layer:
javascript
// services/pocketdns.js
class PocketDNSService {
  constructor(apiKey, baseUrl) {
    this.apiKey = apiKey;
    this.baseUrl = baseUrl;
    this.cache = new Map();
  }
  async createUserSession(userIdentifier, email) {
    const cacheKey = `session_${userIdentifier}`;
    const cached = this.cache.get(cacheKey);
    
    if (cached && this.isSessionValid(cached)) {
      return cached;
    }
    const session = await this.apiRequest('POST', '/users', {
      user_identifier: userIdentifier,
      email
    });
    this.cache.set(cacheKey, session);
    return session;
  }
  async getUserDomains(userIdentifier) {
    return this.apiRequest('GET', `/users/${userIdentifier}/domains`);
  }
  async apiRequest(method, endpoint, data = null) {
    const url = `${this.baseUrl}/api/v1${endpoint}`;
    const options = {
      method,
      headers: {
        'Authorization': `Bearer ${this.apiKey}`,
        'Content-Type': 'application/json'
      }
    };
    if (data) {
      options.body = JSON.stringify(data);
    }
    const start = Date.now();
    try {
      const response = await fetch(url, options);
      const duration = Date.now() - start;
      
      if (!response.ok) {
        throw new Error(`API request failed: ${response.statusText}`);
      }
      const result = await response.json();
      logAPIRequest(method, url, response.status, duration);
      return result;
    } catch (error) {
      const duration = Date.now() - start;
      logAPIRequest(method, url, 0, duration, error);
      throw error;
    }
  }
  isSessionValid(session) {
    const expiryTime = new Date(session.expires_at).getTime();
    return Date.now() < expiryTime - 300000; // 5 minutes buffer
  }
}
export default PocketDNSService;Environment Configuration 
Use environment-specific configurations:
javascript
// config/pocketdns.js
const config = {
  development: {
    apiUrl: 'https://api.sandbox.pocketdns.com',
    embedUrl: 'https://embed.sandbox.pocketdns.com',
    apiKey: process.env.POCKETDNS_SANDBOX_API_KEY
  },
  production: {
    apiUrl: 'https://api.pocketdns.com',
    embedUrl: 'https://embed.pocketdns.com',
    apiKey: process.env.POCKETDNS_API_KEY
  }
};
export const getPocketDNSConfig = () => {
  const env = process.env.NODE_ENV || 'development';
  return config[env];
};Testing Best Practices 
- Use Sandbox Environment: Always test in sandbox before production
- Mock API Responses: Create mocks for reliable testing
- Test Error Scenarios: Verify error handling works correctly
- Integration Tests: Test the complete user flow
- Performance Testing: Measure API response times
- Accessibility Testing: Ensure the embed is accessible
