Guides

Building API design and documentation with FastAPI and Ex...

This guide provides a structured approach to building API-first products with focus on implementation, tooling, and production considerations. Follow these steps to create a scalable, well-documented API product that addresses common developer pain points.

2-3 hours5 steps
1

Define API endpoints with OpenAPI specification

Create a formal OpenAPI 3.1 document that defines all endpoints, request/response formats, and security requirements. Use this as the single source of truth for implementation.

openapi.yaml
openapi: 3.1.0
info:
  title: Product API
  version: 1.0.0
paths:
  /products:
    get:
      summary: List products
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    id: { type: string }
                    name: { type: string }

⚠ Common Pitfalls

  • Not updating the spec after implementation changes
  • Using inconsistent data types between spec and code
2

Implement authentication and rate limiting

Integrate Unkey for API key management and configure rate limits using middleware. Apply these to all endpoints with proper error responses for unauthorized/overaged requests.

from unkey import Unkey

unkey = Unkey(api_key="YOUR_API_KEY")

@app.middleware("http")
def rate_limit(request, call_next):
    key = request.headers.get("Authorization")
    if not unkey.verify_key(key):
        return JSONResponse(status_code=401, content={"error": "Invalid API key"})
    if unkey.rate_limit(key, "products.get", 100):
        return JSONResponse(status_code=429, content={"error": "Rate limit exceeded"})
    return call_next(request)

⚠ Common Pitfalls

  • Not handling rate limit exhaustion gracefully
  • Using weak authentication mechanisms without rotation
3

Implement versioning strategy

Use URL versioning (e.g., /v1/products) and maintain backward compatibility. Document deprecation schedules for outdated versions.

from fastapi import APIRouter

router = APIRouter(prefix="/v1")

@router.get("/products")
def get_products():
    return {"version": "v1", "data": [...]}

⚠ Common Pitfalls

  • Changing request/response formats without deprecation warnings
  • Not maintaining multiple versions in parallel
4

Generate and maintain documentation

Use Swagger UI or ReDoc to auto-generate documentation from the OpenAPI spec. Set up CI/CD to validate spec consistency with implementation.

npx @openapitools/openapi-generator-cli generate -i openapi.yaml -g html -o ./docs

⚠ Common Pitfalls

  • Allowing documentation to become outdated
  • Not testing documentation against actual endpoints
5

Implement usage-based pricing

Integrate Stripe Billing to track API usage metrics. Create pricing tiers that align with your monetization strategy.

import stripe

stripe.api_key = "sk_test_..."

def calculate_cost(usage):
    return stripe.Price.create(
        unit_amount=1000 * usage,
        currency="usd",
        product="prod_123",
        tiers=[
            {"up_to": 1000, "unit_amount": 1000},
            {"up_to": 5000, "unit_amount": 800}
        ]
    )

⚠ Common Pitfalls

  • Not tracking usage metrics accurately
  • Ignoring proration rules for tiered pricing

What you built

By following this implementation sequence, you'll create a production-ready API product that balances developer experience with business requirements. Ensure all components are tested in staging environments before public deployment.