Best Practices
Tips and patterns for building production applications
Best Practices
Follow these best practices to build reliable, efficient applications with the NovaKit API.
API Key Security
Never expose your API key in client-side code or public repositories.
Do:
- Store API keys in environment variables
- Use server-side API routes to proxy requests
- Rotate keys periodically
- Use minimal scopes
Don't:
- Commit keys to git
- Include keys in client-side JavaScript
- Share keys in logs or error messages
# Good: Use environment variables
import os
api_key = os.environ.get("NOVAKIT_API_KEY")
# Bad: Hardcoded key
api_key = "sk_live_abc123..." # Never do this!Request Optimization
Batch When Possible
# Instead of multiple single requests
for prompt in prompts:
generate_image(prompt) # 10 requests
# Use batch parameters where supported
generate_images(prompts, n=10) # 1 requestCache Responses
import hashlib
import json
def get_cached_or_fetch(prompt, cache):
cache_key = hashlib.md5(prompt.encode()).hexdigest()
if cache_key in cache:
return cache[cache_key]
result = make_api_request(prompt)
cache[cache_key] = result
return resultUse Appropriate Models
| Task | Recommended Model |
|---|---|
| Simple chat | openai/gpt-4o-mini |
| Complex reasoning | openai/gpt-4o |
| Quick drafts | fal-ai/hidream-i1-fast |
| Production images | fal-ai/flux/dev |
Rate Limit Management
import time
from collections import deque
class RateLimiter:
def __init__(self, requests_per_minute=60):
self.requests_per_minute = requests_per_minute
self.request_times = deque()
def wait_if_needed(self):
now = time.time()
minute_ago = now - 60
# Remove old timestamps
while self.request_times and self.request_times[0] < minute_ago:
self.request_times.popleft()
# Wait if at limit
if len(self.request_times) >= self.requests_per_minute:
sleep_time = self.request_times[0] - minute_ago
time.sleep(sleep_time)
self.request_times.append(now)
limiter = RateLimiter(60)
for request in requests:
limiter.wait_if_needed()
make_request(request)Error Recovery
def robust_generate(prompt, max_retries=3):
"""Generate with automatic retry and fallback."""
errors = []
for attempt in range(max_retries):
try:
return generate(prompt)
except RateLimitError as e:
time.sleep(e.retry_after)
errors.append(e)
except QuotaExceededError:
raise # Can't retry this
except APIError as e:
if e.status_code >= 500:
time.sleep(2 ** attempt)
errors.append(e)
else:
raise
# All retries failed - try fallback model
try:
return generate(prompt, model="fallback-model")
except Exception:
raise errors[-1]Prompt Engineering
Be Specific
# Vague prompt
"A dog"
# Better prompt
"A golden retriever playing fetch in a sunny park,
photorealistic, shallow depth of field"Use System Messages
messages = [
{
"role": "system",
"content": "You are a helpful coding assistant. Provide concise, "
"working code examples. Always include error handling."
},
{"role": "user", "content": "Write a function to fetch JSON from a URL"}
]Test and Iterate
def optimize_prompt(base_prompt, test_inputs, scorer):
"""A/B test prompts to find the best version."""
variants = [
base_prompt,
f"Be concise. {base_prompt}",
f"{base_prompt} Think step by step.",
]
scores = {}
for variant in variants:
results = [run(variant, input) for input in test_inputs]
scores[variant] = sum(scorer(r) for r in results)
return max(scores, key=scores.get)Monitoring
Log Request Metrics
import logging
import time
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("novakit")
def logged_request(endpoint, data):
start = time.time()
try:
result = make_request(endpoint, data)
duration = time.time() - start
logger.info(
f"Request to {endpoint} succeeded in {duration:.2f}s, "
f"credits used: {result.get('usage', {}).get('credits_used', 0)}"
)
return result
except Exception as e:
duration = time.time() - start
logger.error(f"Request to {endpoint} failed after {duration:.2f}s: {e}")
raiseTrack Usage
class UsageTracker:
def __init__(self):
self.total_credits = 0
self.requests = 0
def track(self, response):
usage = response.get("usage", {})
self.total_credits += usage.get("credits_used", 0)
self.requests += 1
def report(self):
return {
"total_credits": self.total_credits,
"total_requests": self.requests,
"avg_credits_per_request": self.total_credits / max(1, self.requests)
}Checklist
Before going to production:
- API keys stored securely in environment variables
- Error handling with retries and backoff
- Rate limiting to stay within quota
- Request logging and monitoring
- Timeout handling for long operations
- Graceful degradation for failures
- User-friendly error messages
- Caching where appropriate