Quickstart Guide

Catzilla Logo

This guide will get you up and running with Catzilla in minutes. By the end, you’ll have a working web server with routes, path parameters, JSON responses, and organized code structure.

Installation

Install Catzilla from PyPI using pip:

pip install catzilla

System Requirements: - Python 3.8+ (3.9+ recommended) - Windows, macOS, or Linux - No additional dependencies required

For development with the latest features:

git clone https://github.com/rezwanahmedsami/catzilla.git
cd catzilla
pip install -e .

Hello World

Let’s start with the simplest possible Catzilla application:

# hello.py
from catzilla import App

app = App()

@app.get("/")
def home(request):
    return "Hello, World!"

if __name__ == "__main__":
    app.listen(8000)

Save this as hello.py and run it:

python hello.py

Visit http://localhost:8000 and you’ll see “Hello, World!”.

What’s happening: - App() creates a new Catzilla application instance - @app.get("/") registers a route handler for GET requests to the root path - app.listen(8000) starts the server on port 8000

Decorator-Based Routing

Catzilla uses decorators to define routes. Each HTTP method has its own decorator:

from catzilla import App, JSONResponse

app = App()

@app.get("/")
def home(request):
    return "Welcome to my API!"

@app.post("/users")
def create_user(request):
    return JSONResponse({"message": "User created!"})

@app.put("/users/{user_id}")
def update_user(request):
    user_id = request.path_params["user_id"]
    return JSONResponse({"message": f"User {user_id} updated!"})

@app.delete("/users/{user_id}")
def delete_user(request):
    user_id = request.path_params["user_id"]
    return JSONResponse({"message": f"User {user_id} deleted!"})

if __name__ == "__main__":
    app.listen(8000)

Supported HTTP Methods: - @app.get() - GET requests - @app.post() - POST requests - @app.put() - PUT requests - @app.delete() - DELETE requests - @app.patch() - PATCH requests - @app.head() - HEAD requests - @app.options() - OPTIONS requests

Dynamic Path Parameters

Capture dynamic segments from URLs using path parameters:

from catzilla import App, JSONResponse

app = App()

# Single parameter
@app.get("/users/{user_id}")
def get_user(request):
    user_id = request.path_params["user_id"]
    return JSONResponse({"user_id": user_id, "name": f"User {user_id}"})

# Multiple parameters
@app.get("/users/{user_id}/posts/{post_id}")
def get_user_post(request):
    user_id = request.path_params["user_id"]
    post_id = request.path_params["post_id"]
    return JSONResponse({
        "user_id": user_id,
        "post_id": post_id,
        "title": f"Post {post_id} by User {user_id}"
    })

# Mixed static and dynamic segments
@app.get("/api/v1/users/{user_id}/profile")
def get_user_profile(request):
    user_id = request.path_params["user_id"]
    return JSONResponse({
        "user_id": user_id,
        "profile": {"bio": "Software developer", "location": "Earth"}
    })

if __name__ == "__main__":
    app.listen(8000)

Test these endpoints: - GET /users/123 → Returns user 123 - GET /users/456/posts/789 → Returns post 789 by user 456 - GET /api/v1/users/123/profile → Returns user 123’s profile

Request and Response Usage

Catzilla provides powerful request and response objects for handling HTTP interactions:

Working with Requests:

from catzilla import App, JSONResponse

app = App()

@app.post("/users")
def create_user(request):
    # Access request body (automatically parsed JSON)
    data = request.json()

    # Access query parameters
    page = request.query_params.get("page", "1")
    limit = request.query_params.get("limit", "10")

    # Access headers
    content_type = request.headers.get("Content-Type")
    user_agent = request.headers.get("User-Agent")

    return JSONResponse({
        "received_data": data,
        "page": page,
        "limit": limit,
        "content_type": content_type,
        "user_agent": user_agent
    })

@app.get("/search")
def search(request):
    # Query parameters from URL like /search?q=python&category=programming
    query = request.query_params.get("q", "")
    category = request.query_params.get("category", "all")

    return JSONResponse({
        "query": query,
        "category": category,
        "results": [f"Result for '{query}' in {category}"]
    })

if __name__ == "__main__":
    app.listen(8000)

Response Types:

from catzilla import App, JSONResponse, HTMLResponse, Response

app = App()

@app.get("/json")
def json_endpoint(request):
    # JSON response with automatic Content-Type header
    return JSONResponse({"message": "Hello JSON!"})

@app.get("/html")
def html_endpoint(request):
    # HTML response with automatic Content-Type header
    return HTMLResponse("""
        <html>
            <body>
                <h1>Hello HTML!</h1>
                <p>This is an HTML response.</p>
            </body>
        </html>
    """)

@app.get("/text")
def text_endpoint(request):
    # Plain text response (string return)
    return "Hello, plain text!"

@app.get("/custom")
def custom_endpoint(request):
    # Custom response with specific status and headers
    return Response(
        body="Custom response",
        status_code=201,
        content_type="text/plain",
        headers={"X-Custom-Header": "Custom Value"}
    )

if __name__ == "__main__":
    app.listen(8000)

Router Groups for Organization

As your application grows, organize routes using Router Groups:

from catzilla import App, JSONResponse, RouterGroup

app = App()

# Create router groups with prefixes
api_router = RouterGroup(prefix="/api/v1", tags=["api"])
admin_router = RouterGroup(prefix="/admin", tags=["admin"])

# Add routes to the API group
@api_router.get("/users")
def list_users(request):
    return JSONResponse({"users": ["alice", "bob", "charlie"]})

@api_router.get("/users/{user_id}")
def get_user(request):
    user_id = request.path_params["user_id"]
    return JSONResponse({"user_id": user_id, "name": f"User {user_id}"})

@api_router.post("/users")
def create_user(request):
    data = request.json()
    return JSONResponse({"message": "User created", "data": data})

# Add routes to the admin group
@admin_router.get("/stats")
def admin_stats(request):
    return JSONResponse({"total_users": 3, "active_sessions": 15})

@admin_router.get("/health")
def health_check(request):
    return JSONResponse({"status": "healthy", "uptime": "24h"})

# Register router groups with the main app
app.include_router(api_router)
app.include_router(admin_router)

# Main app routes (no prefix)
@app.get("/")
def home(request):
    return JSONResponse({
        "message": "Welcome to the API",
        "endpoints": {
            "api": "/api/v1/users",
            "admin": "/admin/stats"
        }
    })

if __name__ == "__main__":
    app.listen(8000)

This creates the following routes: - GET / → Home page - GET /api/v1/users → List users - GET /api/v1/users/{user_id} → Get specific user - POST /api/v1/users → Create user - GET /admin/stats → Admin statistics - GET /admin/health → Health check

Running via CLI

For production deployment, you can run Catzilla applications via command line:

# Run with default settings (port 8000)
python -m catzilla app:app

# Specify custom port
python -m catzilla app:app --port 3000

# Run with host binding
python -m catzilla app:app --host 0.0.0.0 --port 8080

Where app:app refers to: - app - the Python module name (app.py) - app - the variable name of your Catzilla App instance

Example app.py for CLI usage:

# app.py
from catzilla import App, JSONResponse

app = App()

@app.get("/")
def home(request):
    return JSONResponse({"message": "Hello from CLI!"})

@app.get("/health")
def health(request):
    return JSONResponse({"status": "ok"})

# No need for if __name__ == "__main__" when using CLI

Then run:

python -m catzilla app:app --port 8000

Next Steps

You now have the fundamentals! Here’s what to explore next:

  • Error Handling: Learn about custom error handlers and production-mode error responses

  • Advanced Routing: Explore complex path patterns and route organization

  • Performance: Discover Catzilla’s C-accelerated routing performance

  • Testing: Write tests for your Catzilla applications

  • Deployment: Deploy to production with proper configuration

Complete Example Application:

Here’s a more comprehensive example that demonstrates all the concepts:

# complete_app.py
from catzilla import App, JSONResponse, HTMLResponse, RouterGroup

# Create app with production-mode error handling
app = App(production=True)

# API router group
api = RouterGroup(prefix="/api/v1", tags=["api"])

@api.get("/users")
def list_users(request):
    page = int(request.query_params.get("page", "1"))
    limit = int(request.query_params.get("limit", "10"))

    users = [f"user_{i}" for i in range((page-1)*limit, page*limit)]
    return JSONResponse({
        "users": users,
        "page": page,
        "limit": limit,
        "total": 1000
    })

@api.get("/users/{user_id}")
def get_user(request):
    user_id = request.path_params["user_id"]
    return JSONResponse({
        "id": user_id,
        "name": f"User {user_id}",
        "email": f"user{user_id}@example.com"
    })

@api.post("/users")
def create_user(request):
    data = request.json()
    return JSONResponse({
        "message": "User created successfully",
        "user": data
    }, status_code=201)

# Register the API router
app.include_router(api)

# Main routes
@app.get("/")
def home(request):
    return HTMLResponse("""
        <html>
            <head><title>Catzilla API</title></head>
            <body>
                <h1>Welcome to Catzilla API</h1>
                <p>Available endpoints:</p>
                <ul>
                    <li>GET /api/v1/users - List users</li>
                    <li>GET /api/v1/users/{id} - Get user</li>
                    <li>POST /api/v1/users - Create user</li>
                </ul>
            </body>
        </html>
    """)

@app.get("/health")
def health_check(request):
    return JSONResponse({"status": "healthy"})

if __name__ == "__main__":
    print("Starting Catzilla server on http://localhost:8000")
    app.listen(8000)

Save this as complete_app.py and run:

python complete_app.py

Or use the CLI:

python -m catzilla complete_app:app

Ready for more? Check out the getting-started guide for detailed explanations and the examples section for real-world use cases.