Skip to content

API Routes Generator - User Guide

This guide shows you how to use the API Routes Generator effectively with practical examples and common patterns.

Customizing Generated Routes

You can control which endpoints are generated and customize their behavior:

Selective Endpoint Generation

from fastedgy.api_route_model import api_route_model

# Enable only list and get endpoints
@api_route_model(list=True, get=True, create=False, patch=False, delete=False)
class ReadOnlyProduct(Model):
    name = fields.CharField(max_length=200)
    price = fields.DecimalField(max_digits=10, decimal_places=2)

    class Meta:
        tablename = "readonly_products"

# Custom endpoint configuration
@api_route_model(
    list=True,
    get=True,
    create={"status_code": 201, "summary": "Create a new product"},
    patch={"summary": "Update product details"},
    delete=False  # Disable delete endpoint
)
class Product(Model):
    name = fields.CharField(max_length=200)
    description = fields.TextField()
    price = fields.DecimalField(max_digits=10, decimal_places=2)

    class Meta:
        tablename = "products"

Built-in Features

Generated endpoints automatically integrate with FastEdgy's advanced features:

  • Pagination - Standard limit/offset pagination with metadata
  • Ordering - Sort by any field including nested relations
  • Query Builder - Advanced filtering with X-Filter header
  • Fields Selector - Control response fields with X-Fields header
# Example combining all features
GET /api/products/?limit=25&order_by=category.name,price:desc
X-Filter: ["&", [["is_active", "=", true], ["price", ">=", 100]]]
X-Fields: name,price,category.name,description

Working with Relationships

ForeignKey relationships

A foreign key points to a single related record. The same field accepts several input forms, including the same operations as collections applied to one record.

Simple mode

For the common cases, set the field to an id, an object or null:

# Link by id
POST /api/products/
{"name": "Smartphone", "category": 1, "price": "599.99"}

# Link by object (id only)
POST /api/products/
{"name": "Smartphone", "category": {"id": 1}, "price": "599.99"}

# Link and update the related record (id plus other properties)
POST /api/products/
{"name": "Smartphone", "category": {"id": 1, "name": "Phones"}, "price": "599.99"}

# Unlink (nullable foreign keys only)
PATCH /api/products/42
{"category": null}

Advanced mode

For the remaining cases, use a single operation [action, value] (the same actions as collections, applied to one record):

Available operations:

Operation Description Example Value
link Link an existing record ["link", 42]
unlink Remove the link (keep record) ["unlink"]
create Create a new record and link it ["create", {"name": "New"}]
update Update the record and link it ["update", {"id": 10, "name": "Updated"}]
delete Delete the record and remove the link ["delete", 15]

When to use each form:

  • id / ["link", id] - Link an existing record
  • object {"id": ...} - Link an existing record (object form)
  • object {"id": ..., ...} / ["update", {...}] - Link a record and update its properties
  • null / ["unlink"] - Remove the link without deleting the record (nullable foreign keys only)
  • ["create", {...}] - Create a record and link it in a single request
  • ["delete", id] - Permanently delete the record and remove the link

Examples:

# Create a related record and link it in a single request
POST /api/products/
{"name": "Smartphone", "category": ["create", {"name": "Phones"}], "price": "599.99"}

# Update the linked record and ensure the link
PATCH /api/products/42
{"category": ["update", {"id": 1, "name": "Renamed"}]}

# Delete the linked record and clear the foreign key
PATCH /api/products/42
{"category": ["delete", 1]}

Required foreign keys

A required (non-nullable) foreign key cannot be unlinked: null and ["unlink"] are rejected.

Foreign keys can be filtered by related fields too:

GET /api/products/
X-Filter: ["category.name", "=", "Electronics"]

GET /api/products/
X-Filter: ["category", "=", 1]

ManyToMany & OneToMany relationships

FastEdgy provides two modes for managing collections of related records.

Simple mode

For small sets or complete replacements, use a simple list of IDs:

# Create with related items
POST /api/products/
{
  "name": "Laptop",
  "tags": [1, 2, 3]
}

# Replace all relations
PATCH /api/products/42
{
  "tags": [4, 5, 6]
}

The simple mode automatically executes a set operation that replaces all existing relations.

Advanced mode

For large collections or partial updates, use granular operations to avoid performance issues:

Performance optimization

When a product has 1000 linked tags and you want to add just one more, simple mode would require sending 1001 IDs and the server would unlink 1000 relations then re-link 1001. Advanced mode lets you send just ["link", 1001] for optimal performance.

Available operations:

Operation Description Example Value
link Add relation to existing record ["link", 42]
unlink Remove relation (keep record) ["unlink", 23]
create Create new record and link it ["create", {"name": "New"}]
update Update record and ensure link ["update", {"id": 10, "name": "Updated"}]
delete Delete record and remove relation ["delete", 15]
set Replace all relations ["set", [1, 2, 3]]
clear Remove all relations ["clear"]

When to use each operation:

  • link - Add one item to a large existing collection without touching others
  • unlink - Remove one item from a large collection
  • set - Reset the entire collection (same as simple mode)
  • clear - Revoke all access or empty the collection
  • create - Create and link in a single operation
  • update - Modify a linked record and ensure the link exists
  • delete - Permanently remove a linked record

Examples:

# Add one item to existing large collection
PATCH /api/products/42
{
  "tags": [["link", 1001]]
}

# Multiple targeted modifications
PATCH /api/products/42
{
  "tags": [
    ["link", 50],
    ["unlink", 23],
    ["update", {"id": 10, "name": "Updated Name"}]
  ]
}

# Create and link in one request
POST /api/products/
{
  "name": "Gaming Laptop",
  "tags": [
    ["link", 1],
    ["create", {"name": "Limited Edition"}]
  ]
}

# Complete reset (equivalent to simple mode)
PATCH /api/products/42
{
  "tags": [["set", [1, 2, 3]]]
}

# Clear all relations
PATCH /api/products/42
{
  "tags": [["clear"]]
}

Operation order:

Operations are executed sequentially in the order provided:

PATCH /api/products/42
{
  "tags": [
    ["clear"],              # 1. Remove all existing tags
    ["link", 1],            # 2. Add tag 1
    ["link", 2],            # 3. Add tag 2
    ["create", {"name": "New Tag"}]  # 4. Create and add new tag
  ]
}

Error responses:

A well-formed operation that targets a missing record returns a 400 Bad Request:

// 400 Bad Request - Record not found
{
  "detail": "Record with id=999 not found in Tag"
}

A malformed operation (wrong shape or unknown action, e.g. ["link"] without a value) no longer matches the typed request schema and is rejected by request validation with a 422 Unprocessable Entity:

// 422 Unprocessable Entity - Invalid operation format
{
  "detail": [
    {
      "type": "...",
      "loc": ["body", "tags", 0],
      "msg": "..."
    }
  ]
}

Data Export

Every model gets automatic export functionality supporting CSV, XLSX, and ODS formats:

# Export with all features support
GET /api/products/export?format=csv&limit=1000
X-Filter: ["is_active", "=", true]
X-Fields: name,price,category.name

Error Handling

Generated endpoints provide consistent error responses:

  • 400 Bad Request: Validation errors with field details
  • 404 Not Found: Item not found
  • 403 Forbidden: Insufficient permissions
  • 422 Unprocessable Entity: Invalid request data

Admin Routes

Create separate admin endpoints with different permissions:

from fastedgy.api_route_model import admin_api_route_model

@admin_api_route_model()  # Separate from regular routes
class AdminUser(Model):
    username = fields.CharField(max_length=150)
    is_staff = fields.BooleanField(default=False)

# Register on separate admin router
admin_router = APIRouter(prefix="/admin/api", dependencies=[Depends(admin_required)])
register_admin_api_route_models(admin_router)

Performance Optimization

Generated endpoints include automatic optimizations:

  • Query Optimization: Automatic select_related() for filtered/selected relations
  • Memory Management: Pagination prevents large dataset memory issues
  • Data Transfer: Field selection reduces response size

Next Steps

Ready for more advanced customization? Check out:

Advanced Usage Guide