🎯

fastapi-structure-guide

🎯Skill

from chasepassion/skills

VibeIndex|
What it does

Generates a structured FastAPI project with strict layered architecture and clean code practices.

πŸ“¦

Part of

chasepassion/skills(2 items)

fastapi-structure-guide

Installation

πŸ“‹ No install commands found in docs. Showing default command. Check GitHub for actual instructions.
Quick InstallInstall with npx
npx skills add chasepassion/skills --skill fastapi-structure-guide
2Installs
-
AddedFeb 4, 2026

Skill Details

SKILL.md

"Trigger when the user wants to create a new FastAPI project, add new files/folders (features), refactor existing code, or asks about architectural best practices. This skill enforces a strict layered architecture and specific development workflow."

Overview

# FastAPI Structure Guide

Intent

Use this guide whenever generating code for a FastAPI project, specifically when:

  1. Scaffolding a brand new project.
  2. Adding a new feature (e.g., "Add an Order module") which requires creating files across multiple layers.
  3. Refactoring existing code to meet clean architecture standards.

You must strictly adhere to the Core Principles, Project Structure, Development Workflow, and Coding Rules defined below.

---

I. Core Principles

Before writing a single line of code, adhere to these four guiding principles:

  1. Separation of Concerns:
  • API Layer: Responsible only for "Reception" (parsing requests, validating parameters).
  • Service Layer: Responsible for "Business" (logic calculation, decision making).
  • DB/Model Layer: Responsible for "Data" (storage access, shape definition).
  • Rule: Never write business logic inside an API Route function.
  1. Dependency Injection:
  • Do not instantiate components directly (e.g., service = UserService()).
  • Use FastAPI's Depends for injection.
  • Flow: DB Session -> injected into -> Service -> injected into -> API Route.
  1. Config Centralization:
  • Strictly prohibit hardcoded passwords, keys, or URLs in the code.
  • Manage all configurations via Pydantic Settings and read from environment variables (.env).
  1. Mirrored Testing:
  • The test directory structure must mirror the source code directory structure 1:1.
  • Use SQLite In-Memory and Dependency Overrides to mock the real environment.

---

II. Recommended Project Structure

Use this standardized directory structure when creating files or folders:

```text

my-fastapi-project/

β”œβ”€β”€ app/ # Core Application Source

β”‚ β”œβ”€β”€ __init__.py

β”‚ β”œβ”€β”€ main.py # πŸš€ App Entry: Routes mounting, Exception handling

β”‚ β”œβ”€β”€ api/ # 🌐 Interface Layer (Routes)

β”‚ β”‚ β”œβ”€β”€ __init__.py

β”‚ β”‚ └── v1/ # Version Control

β”‚ β”‚ β”œβ”€β”€ __init__.py

β”‚ β”‚ β”œβ”€β”€ api.py # Router Aggregation (Include Routers)

β”‚ β”‚ └── endpoints/ # Specific Business Endpoints

β”‚ β”‚ β”œβ”€β”€ __init__.py

β”‚ β”‚ β”œβ”€β”€ users.py

β”‚ β”‚ └── items.py

β”‚ β”œβ”€β”€ core/ # βš™οΈ Infrastructure Configuration

β”‚ β”‚ β”œβ”€β”€ __init__.py

β”‚ β”‚ β”œβ”€β”€ config.py # Pydantic Settings (Env Config)

β”‚ β”‚ β”œβ”€β”€ logging.py # Logging Config

β”‚ β”‚ └── security.py # Auth/Hashing Tools

β”‚ β”œβ”€β”€ db/ # πŸ—„οΈ Database Layer

β”‚ β”‚ β”œβ”€β”€ __init__.py

β”‚ β”‚ β”œβ”€β”€ session.py # DB Connection & Session Factory

β”‚ β”‚ └── tables.py # SQLAlchemy ORM Definitions (DB Schema)

β”‚ β”œβ”€β”€ models/ # πŸ“ Data Transfer Objects (DTOs)

β”‚ β”‚ β”œβ”€β”€ __init__.py

β”‚ β”‚ β”œβ”€β”€ user.py # Pydantic Models (Request/Response)

β”‚ β”‚ └── item.py

β”‚ └── services/ # 🧠 Business Logic Layer

β”‚ β”œβ”€β”€ __init__.py

β”‚ β”œβ”€β”€ base.py # Optional: Base Service Class

β”‚ β”œβ”€β”€ user_service.py # User-related business logic

β”‚ └── item_service.py

β”œβ”€β”€ tests/ # βœ… Test Cases (Mirrored Structure)

β”‚ β”œβ”€β”€ __init__.py

β”‚ β”œβ”€β”€ conftest.py # Pytest Fixtures (DB override, Client)

β”‚ └── api/

β”‚ └── v1/

β”‚ └── endpoints/

β”‚ └── test_users.py

β”œβ”€β”€ .env # πŸ” Local Env Vars (Gitignored)

β”œβ”€β”€ .gitignore

β”œβ”€β”€ docker-compose.yaml # Local Dev Orchestration

β”œβ”€β”€ Dockerfile # Image Build

β”œβ”€β”€ pyproject.toml # Dependency Management (Recommend uv)

└── README.md

```

Directory Responsibilities

  1. app/api/ (Interface Layer)
  • Responsibility: Handle HTTP protocol specifics only.
  • Contains: Path definitions, HTTP methods (GET/POST), status codes, dependency injection declarations.
  • Input/Output: Pydantic Schemas.
  • Rule: This layer must be "thin". Functions should strictly be 5-10 lines, calling the Service layer and returning results.
  1. app/services/ (Business Logic Layer)
  • Responsibility: The brain of the application. Handles complex business rules, calculations, and permission checks.
  • Contains: CRUD operations, 3rd-party API logic, data processing.
  • Input/Output: Pydantic Schemas or Raw Data -> ORM Objects or Pydantic Schemas.
  • Rule: Service classes must accept Session via __init__ for easy testing mocks.
  1. app/models/ (Data Transfer Object Layer)
  • Responsibility: Define data "shape" and validation rules for the API.
  • Contains: Pydantic Models (BaseModel).
  • Distinction: These are not DB tables. They are for API input/output (e.g., UserCreate vs UserResponse).
  1. app/db/ (Data Access Layer)
  • Responsibility: Physical DB connection and Table definitions.
  • Contains: session.py (Engine/SessionLocal), tables.py (SQLAlchemy Base models/Columns).
  1. app/core/ (Cross-Cutting Concerns)
  • Responsibility: Infrastructure supporting the app.
  • Contains: Config loading (config.py), logging, security tools. Code here is business-agnostic.

---

III. Creation Rules (General Development Workflow)

When implementing a new feature, follow these 5 Standard Steps in order:

Step A: Define Data Storage (Database Layer)

  • Principle: Everything starts with data. Determine how the resource looks in the DB.
  • Action: Add new SQLAlchemy ORM class in db/tables.py (or specific file in db/models/).
  • Naming: PascalCase for Class (Singular), snake_case for Table Name (Plural).

Step B: Define Interaction Contract (Schemas/DTO Layer)

  • Principle: Define how data moves over the network. Validate Input (Create/Update) and Normalize Output (Response).
  • Action: Create a new file in models/.
  • Naming: resource_name.py. Typically includes Create, Update, Response variants.

Step C: Implement Business Logic (Service Layer)

  • Principle: Write the "Verbs". This is the bridge between DB and API.
  • Action: Create a new file in services/.
  • Naming: resource_name_service.py. Class name ends with Service.

Step D: Expose API Interface (API Layer)

  • Principle: Define the entry point for external access.
  • Action: Create a new file in api/v1/endpoints/.
  • Naming: resource_names.py (Plural) to reflect RESTful style.

Step E: Registration & Wiring

  • Principle: New router files are isolated by default; they must be explicitly registered.
  • Action: Modify api/v1/api.py to include the new router.

---

IV. Coding Rules

Rule 1: API Routes Must Be "Dumb"

❌ Wrong (Logic Leakage):

```python

@router.post("/users")

def create_user(user: UserCreate, db: Session = Depends(get_db)):

# Error: Logic and DB ops directly in route

hashed_password = hash_pw(user.password)

db_user = User(email=user.email, password=hashed_password)

db.add(db_user)

db.commit()

return db_user

```

βœ… Correct (Call Service):

```python

@router.post("/users")

def create_user(

user: UserCreate,

service: UserService = Depends(get_user_service) # Injected Service

):

# Correct: Only forwards the request

return service.create_user(user)

```

Rule 2: Service Layer Must Use Dependency Injection

Service classes should not create the DB Session themselves; they must receive it in __init__.

```python

class UserService:

def __init__(self, session: Session):

self.session = session # βœ… Dependency Injection

def create_user(self, data: UserCreate):

# Business logic...

pass

```

Rule 3: Config Must Use Pydantic

Never use os.getenv("KEY") scattered in the code.

```python

# app/core/config.py

class Settings(BaseSettings):

DB_URL: str

SECRET_KEY: str

settings = Settings()

# Usage in other files

from app.core.config import settings

print(settings.DB_URL)

```