Skip to content

ibonn/tatami

Repository files navigation

Tatami Logo

Build Status Docs Status PyPI - Downloads PyPI - Version


The clean, modular Python web floorplan.

Tatami is a minimal, convention-powered web framework that builds your application from the ground up — guided by your directory structure, not boilerplate or ceremony.

Like traditional tatami mats that structure a Japanese room, Tatami lets you define the shape and flow of your web app naturally, simply by laying things out.


✨ Features

  • 🔁 Automatic routing from file and folder structure
  • 📦 Service injection via convention
  • 🧩 Auto-loaded middleware, templates, and static assets
  • 📖 Live OpenAPI docs (ReDoc, Swagger, RapiDoc)
  • 🧠 Auto-generated endpoint documentation from docstrings and README
  • Zero-config startup — just run your app directory

🚀 Quick Start

pip install tatami

Create a new project:

tatami create myproject

Run your project:

tatami run myproject

Your API will be available at http://localhost:8000 with automatic docs at /docs/swagger.

🧠 Philosophy

Tatami is designed for:

  • Structure-first design: Routes and services emerge from file layout.
  • Simplicity: Eliminate configuration and glue code.
  • Alignment: Your docs, code, and architecture reflect each other.

It's like FastAPI and Flask had a minimalist, Spring Boot-inspired child.

📚 Documentation

You can access the whole documentation for Tatami here

By the way, Tatami automatically generates your application’s documentation at the following endpoints:

  • /openapi.json - OpenAPI specification
  • /docs/swagger - Swagger UI
  • /docs/redoc - ReDoc
  • /docs/rapidoc - RapiDoc

🔌 Example

Using decorators (recommended):

from tatami import get, post, router
from pydantic import BaseModel

class User(BaseModel):
    name: str
    age: int

class Users(router('/users')):
    @get('/')
    def list_users(self):
        """Returns all users in the system."""
        return [{"id": 1, "name": "Alice", "age": 30}]

    @post('/')
    def create_user(self, user: User):
        """Creates a new user."""
        return {"message": f"Created user {user.name}"}

    @get('/{user_id}')
    def get_user(self, user_id: int):
        """Get a specific user by ID."""
        return {"id": user_id, "name": "Alice", "age": 30}

Using convention-based routing:

# In routers/users.py
class Users:
    def get_users(self):
        """List all users"""
        return [{"id": 1, "name": "Alice"}]
    
    def post_user(self, user: User):
        """Create a new user"""
        return {"created": user.name}

This automatically creates:

  • GET /users/
  • POST /users/
  • GET /users/{user_id}

...with full OpenAPI schemas generated automatically.

🌱 Still Early

Tatami is experimental. Expect breaking changes, rapid iteration, and exciting ideas.

Contributions, feedback, and issue reports are more than welcome.