NovaKitv1.0

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 request

Cache 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 result

Use Appropriate Models

TaskRecommended Model
Simple chatopenai/gpt-4o-mini
Complex reasoningopenai/gpt-4o
Quick draftsfal-ai/hidream-i1-fast
Production imagesfal-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}")
        raise

Track 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

On this page