Best Practices
This guide outlines best practices for using the Nanonets API effectively and securely.
Security
API Key Management
- Store API Keys Securely
import os
from dotenv import load_dotenv
# Load API key from environment variable
load_dotenv()
API_KEY = os.getenv('NANONETS_API_KEY')
- Rotate API Keys Regularly
def rotate_api_key(old_key):
# Implement your key rotation logic
new_key = generate_new_key()
update_environment(old_key, new_key)
return new_key
- Use Different Keys for Different Environments
API_KEY = os.getenv('NANONETS_API_KEY_PROD') if is_production else os.getenv('NANONETS_API_KEY_DEV')
Request Security
- Use HTTPS Always
url = "https://app.nanonets.com/api/v4/workflows" # Always use HTTPS
- Validate Input Data
def validate_document(file_path):
# Check file size
if os.path.getsize(file_path) > 10 * 1024 * 1024: # 10MB limit
raise ValueError("File too large")
# Check file type
allowed_types = ['.pdf', '.jpg', '.png']
if not any(file_path.lower().endswith(ext) for ext in allowed_types):
raise ValueError(f"Invalid file type. Allowed types: {allowed_types}")
Performance
Optimizing Requests
- Use Connection Pooling
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
session = requests.Session()
retries = Retry(total=5, backoff_factor=0.1)
session.mount('https://', HTTPAdapter(max_retries=retries, pool_connections=100, pool_maxsize=100))
- Implement Caching
from functools import lru_cache
import time
@lru_cache(maxsize=100)
def get_workflow_details(workflow_id, api_key):
url = f"https://app.nanonets.com/api/v4/workflows/{workflow_id}"
response = requests.get(url, auth=HTTPBasicAuth(api_key, ''))
return response.json()
- Batch Processing
def process_documents_batch(file_paths, api_key, workflow_id):
results = []
for file_path in file_paths:
try:
result = process_document(file_path, api_key, workflow_id)
results.append(result)
except Exception as e:
results.append({'error': str(e), 'file': file_path})
return results
Error Handling
- Implement Retry Logic
from tenacity import retry, stop_after_attempt, wait_exponential
@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=4, max=10))
def make_api_request(url, api_key):
response = requests.get(url, auth=HTTPBasicAuth(api_key, ''))
response.raise_for_status()
return response.json()
- Handle Rate Limits
def handle_rate_limit(response):
if response.status_code == 429:
retry_after = int(response.headers.get('Retry-After', 60))
time.sleep(retry_after)
return True
return False
Code Organization
Modular Structure
- Separate Concerns
# config.py
API_CONFIG = {
'base_url': 'https://app.nanonets.com/api/v4',
'timeout': 30,
'max_retries': 3
}
# api_client.py
class NanonetsClient:
def __init__(self, api_key):
self.api_key = api_key
self.session = self._create_session()
def _create_session(self):
session = requests.Session()
session.auth = HTTPBasicAuth(self.api_key, '')
return session
def get_workflows(self):
url = f"{API_CONFIG['base_url']}/workflows"
return self.session.get(url).json()
- Use Context Managers
class APIConnection:
def __init__(self, api_key):
self.api_key = api_key
self.session = None
def __enter__(self):
self.session = requests.Session()
self.session.auth = HTTPBasicAuth(self.api_key, '')
return self
def __exit__(self, exc_type, exc_val, exc_tb):
if self.session:
self.session.close()
Monitoring and Logging
- Implement Structured Logging
import logging
import json
from datetime import datetime
class APILogger:
def __init__(self):
self.logger = logging.getLogger('nanonets_api')
self.logger.setLevel(logging.INFO)
def log_request(self, method, url, status_code, duration):
log_entry = {
'timestamp': datetime.utcnow().isoformat(),
'method': method,
'url': url,
'status_code': status_code,
'duration_ms': duration
}
self.logger.info(json.dumps(log_entry))
- Track Performance Metrics
from time import time
def track_performance(func):
def wrapper(*args, **kwargs):
start_time = time()
result = func(*args, **kwargs)
duration = (time() - start_time) * 1000 # Convert to milliseconds
log_performance_metric(func.__name__, duration)
return result
return wrapper
Testing
- Unit Tests
import unittest
from unittest.mock import patch
class TestNanonetsAPI(unittest.TestCase):
@patch('requests.Session')
def test_get_workflows(self, mock_session):
mock_response = mock_session.return_value.get.return_value
mock_response.json.return_value = {'workflows': []}
client = NanonetsClient('test_key')
result = client.get_workflows()
self.assertEqual(result, {'workflows': []})
- Integration Tests
class TestNanonetsIntegration(unittest.TestCase):
def setUp(self):
self.client = NanonetsClient(os.getenv('TEST_API_KEY'))
def test_document_processing(self):
result = self.client.process_document('test.pdf')
self.assertIn('status', result)
self.assertEqual(result['status'], 'completed')
Need Help?
- Check the API Reference
- Join our Discord community
- Contact support