Best Practices
Best Practices
This guide outlines best practices for integrating with the Spreetail Channel Integration API to ensure reliable, efficient, and secure operations.
Authentication
Token Management
✅ DO:
- Cache tokens and reuse them for their full validity period (24 hours)
- Implement automatic token refresh before expiration
- Store tokens securely in memory, not in logs or files
❌ DON'T:
- Request a new token for every API call
- Store tokens in client-side code or public repositories
- Log tokens or include them in error messages
# Good: Cache and reuse tokens
class APIClient:
def __init__(self):
self.token = None
self.token_expires_at = 0
def get_token(self):
if self.token and time.time() < self.token_expires_at - 300:
return self.token
# Refresh token
...Credential Security
✅ DO:
- Use environment variables for credentials
- Rotate secrets regularly
- Use different credentials for development and production
❌ DON'T:
- Hardcode credentials in source code
- Commit credentials to version control
- Share credentials between team members
Request Handling
Idempotency
✅ DO:
- Use unique reference numbers for orders
- Implement idempotency checks for critical operations
- Handle duplicate request errors gracefully
# Good: Check for duplicates before creating
def create_order_safely(order_data):
try:
return create_order(order_data)
except APIError as e:
if e.status_code == 409: # Conflict
# Order already exists, fetch it instead
return get_order_by_reference(order_data['ReferenceNumber'])
raiseValidation
✅ DO:
- Validate all data before sending API requests
- Check required fields and formats
- Verify business rules (e.g., stock availability)
# Good: Validate before API call
def validate_and_create_order(order_data):
# Validate structure
errors = validate_order_structure(order_data)
if errors:
return {"success": False, "errors": errors}
# Check inventory
for item in order_data['OrderItems']:
inventory = get_inventory(sku=item['SKU'])
if inventory['quantity'] < item['Qty']:
return {
"success": False,
"error": f"Insufficient stock for {item['SKU']}"
}
# All validations passed
return create_order(order_data)Error Handling
✅ DO:
- Implement comprehensive error handling
- Use retry logic for transient errors (5xx, 429)
- Log errors with sufficient context
- Handle specific error codes appropriately
❌ DON'T:
- Ignore errors or use generic error handlers
- Retry on client errors (4xx) without fixing the issue
- Retry indefinitely without backoff
Performance
Rate Limiting
✅ DO:
- Respect rate limits (100 requests/minute by default)
- Implement exponential backoff for rate limit errors
- Batch operations when possible
- Cache responses when appropriate
# Good: Rate limit aware client
import time
from collections import deque
class RateLimitedClient:
def __init__(self, max_requests=100, window=60):
self.max_requests = max_requests
self.window = window
self.requests = deque()
def wait_if_needed(self):
now = time.time()
# Remove old requests outside window
while self.requests and self.requests[0] < now - self.window:
self.requests.popleft()
# Wait if at limit
if len(self.requests) >= self.max_requests:
sleep_time = self.window - (now - self.requests[0])
if sleep_time > 0:
time.sleep(sleep_time)
self.requests.append(time.time())Caching
✅ DO:
- Cache inventory data (5-10 minutes)
- Cache authentication tokens
- Cache static reference data
❌ DON'T:
- Cache order creation responses
- Cache data that changes frequently
- Cache without considering TTL
# Good: Cache with TTL
from functools import lru_cache
import time
class CachedInventory:
def __init__(self, ttl=300): # 5 minutes
self.cache = {}
self.ttl = ttl
def get(self, sku):
if sku in self.cache:
data, timestamp = self.cache[sku]
if time.time() - timestamp < self.ttl:
return data
# Fetch fresh data
data = fetch_inventory(sku)
self.cache[sku] = (data, time.time())
return dataData Management
Reference Numbers
✅ DO:
- Use consistent, unique reference number formats
- Include timestamps or sequence numbers
- Prefix with client identifier
# Good: Generate unique reference numbers
import uuid
from datetime import datetime
def generate_reference_number(client_id):
timestamp = datetime.utcnow().strftime('%Y%m%d-%H%M%S')
unique_id = str(uuid.uuid4())[:8]
return f"{client_id}-{timestamp}-{unique_id}"Date Handling
✅ DO:
- Use UTC for all timestamps
- Format dates as ISO 8601 with timezone
- Validate date formats before sending
# Good: Consistent date handling
from datetime import datetime, timezone
def format_date(dt):
"""Format datetime as ISO 8601 UTC string"""
if dt.tzinfo is None:
dt = dt.replace(tzinfo=timezone.utc)
return dt.isoformat().replace('+00:00', 'Z')Monitoring and Logging
Logging
✅ DO:
- Log all API requests and responses (without sensitive data)
- Include request IDs and timestamps
- Log errors with full context
- Use structured logging
# Good: Structured logging
import logging
import json
logger = logging.getLogger(__name__)
def log_api_request(method, endpoint, status_code, duration):
logger.info(json.dumps({
"event": "api_request",
"method": method,
"endpoint": endpoint,
"status_code": status_code,
"duration_ms": duration * 1000,
"timestamp": datetime.utcnow().isoformat()
}))Monitoring
✅ DO:
- Monitor API response times
- Track error rates by type
- Alert on authentication failures
- Monitor rate limit usage
Security
Data Protection
✅ DO:
- Use HTTPS for all API calls
- Never log sensitive data (tokens, secrets, customer data)
- Encrypt sensitive data at rest
- Follow GDPR/data protection regulations
Access Control
✅ DO:
- Use least privilege principle
- Rotate credentials regularly
- Monitor for unauthorized access
- Use separate credentials for different environments
Testing
Test Environment
✅ DO:
- Use test credentials for development
- Test error scenarios
- Test rate limiting behavior
- Validate all error codes
# Good: Comprehensive testing
def test_order_creation():
# Test successful creation
order = create_test_order()
result = create_order(order)
assert result['success'] == True
# Test duplicate detection
result2 = create_order(order)
assert result2['success'] == False
assert 'already exists' in result2['error']
# Test validation errors
invalid_order = {'ReferenceNumber': 'TEST'}
result3 = create_order(invalid_order)
assert result3['success'] == FalseCode Organization
Structure
✅ DO:
- Create reusable API client classes
- Separate authentication logic
- Implement proper error handling
- Use configuration files for settings
# Good: Well-organized client
class SpreetailAPIClient:
def __init__(self, client_id, client_secret, base_url=None):
self.client_id = client_id
self.client_secret = client_secret
self.base_url = base_url or "https://api.spreetaileu.com/api/api/v1"
self.session = requests.Session()
self._token = None
self._token_expires_at = 0
def authenticate(self):
# Authentication logic
...
def create_order(self, order_data):
# Order creation logic
...
def get_inventory(self, sku=None):
# Inventory retrieval logic
...Summary
Following these best practices will help you:
- Improve Reliability: Proper error handling and retry logic
- Enhance Security: Secure credential management
- Optimize Performance: Caching and rate limit awareness
- Maintain Code Quality: Well-structured, testable code
- Ensure Compliance: Data protection and monitoring
For specific questions or advanced use cases, contact [email protected].
Updated 1 day ago
