Skip to main content
The create:controller command generates a new controller file with your choice of API or templated responses.

Usage

framefox create:controller [name]

Arguments

name
string
The name of the controller in snake_case. If not provided, you’ll be prompted to enter it.

Controller Types

You’ll be prompted to choose between two controller types:

1. API Controller

Creates a controller that returns JSON responses, ideal for REST APIs. Features:
  • JSON response format
  • RESTful endpoints
  • No template rendering
  • Perfect for SPAs and mobile apps

2. Templated Controller

Creates a controller that renders HTML templates. Features:
  • Renders Jinja2 templates
  • Automatic view directory creation
  • Base template file included
  • Server-side rendering

Examples

Interactive Mode

$ framefox create:controller

What is the name of the controller ?(snake_case)
Controller name: user

What type of controller do you want to create?

1. API controller (JSON responses)
2. Templated controller (HTML responses with views)

Controller type: 1

API Controller created successfully: src/controller/user_controller.py

With Name Argument

framefox create:controller product

API Controller Example

Creates src/controller/user_controller.py:
from framefox.core.http.response import Response
from framefox.core.routing.decorator.route import route

"""
Controller: UserController
Generated: 2024-01-15T10:30:00
"""


class UserController:
    @route("/user", methods=["GET"])
    def index(self) -> Response:
        """List all users"""
        return Response.json({
            "users": [],
            "message": "User list"
        })

    @route("/user/<int:id>", methods=["GET"])
    def show(self, id: int) -> Response:
        """Show a specific user"""
        return Response.json({
            "id": id,
            "message": "User details"
        })

    @route("/user", methods=["POST"])
    def create(self) -> Response:
        """Create a new user"""
        return Response.json({
            "message": "User created"
        }, status=201)

    @route("/user/<int:id>", methods=["PUT"])
    def update(self, id: int) -> Response:
        """Update a user"""
        return Response.json({
            "id": id,
            "message": "User updated"
        })

    @route("/user/<int:id>", methods=["DELETE"])
    def delete(self, id: int) -> Response:
        """Delete a user"""
        return Response.json({
            "id": id,
            "message": "User deleted"
        })

Templated Controller Example

Creates src/controller/user_controller.py:
from framefox.core.http.response import Response
from framefox.core.routing.decorator.route import route


class UserController:
    @route("/user", methods=["GET"])
    def index(self) -> Response:
        """Display the user list page"""
        return Response.render("user/index.html", {
            "title": "Users",
            "users": []
        })
And creates templates/user/index.html:
{% extends "base.html" %}

{% block title %}User{% endblock %}

{% block content %}
<div class="container">
    <h1>User Page</h1>
    <p>Welcome to the User controller</p>
</div>
{% endblock %}

File Locations

Controller File

src/controller/{name}_controller.py

Template Directory (Templated Only)

templates/{name}/
  └── index.html

Naming Conventions

Controller names must be in snake_case. The command automatically converts them to PascalCase for class names.
Examples:
Input (snake_case)Class Name (PascalCase)File Name
userUserControlleruser_controller.py
user_profileUserProfileControlleruser_profile_controller.py
api_webhookApiWebhookControllerapi_webhook_controller.py

Validation

The command performs several checks:
  1. Name Format - Must be snake_case
  2. Controller Exists - Prevents overwriting existing controllers
  3. Template Exists - Checks for existing template directories

Error Examples

# Invalid name format
$ framefox create:controller UserController
Invalid name. Must be in snake_case.

# Controller already exists
$ framefox create:controller user
Controller user already exists!

Working with Controllers

Verify Routes

After creating a controller, verify it’s registered:
framefox debug:router

Test the Endpoint

API Controller:
curl http://localhost:8000/user
Templated Controller:
curl http://localhost:8000/user
# or open in browser

Customizing Controllers

After generation, you can:
  1. Add Dependencies - Inject services via constructor
  2. Add Middleware - Apply authentication, validation, etc.
  3. Add More Routes - Use the @route decorator
  4. Customize Response - Modify status codes, headers, etc.

Example with Dependency Injection

from framefox.core.di.decorator.service import service
from src.repository.user_repository import UserRepository

@service
class UserController:
    def __init__(self, user_repository: UserRepository):
        self.user_repository = user_repository
    
    @route("/user", methods=["GET"])
    def index(self) -> Response:
        users = self.user_repository.find_all()
        return Response.json([user.to_dict() for user in users])

Best Practices

  • Use API controllers for frontends (React, Vue, Angular)
  • Use templated controllers for server-side rendered pages
  • Keep controllers thin - move business logic to services
  • Use one controller per resource (users, products, orders, etc.)
  • Follow RESTful conventions for endpoint naming

Next Steps

Create Entity

Generate entities for database models

Create CRUD

Generate complete CRUD operations

Debug Routes

View all registered routes

Build docs developers (and LLMs) love