Day: July 15, 2025

  • Structuring FastAPI Projects for Maintainability and Scalability

    Structuring FastAPI Projects for Maintainability and Scalability

    Hi, I’m Fast Eddy! As a backend web developer who spends most of my time with FastAPI, I’ve learned that maintainable, scalable project structure is the foundation of any robust API. Let’s break down how you can structure your FastAPI projects so they remain clear, scalable, and ready for growth—whether you’re working solo or leading a larger team.

    Why Project Structure Matters

    FastAPI makes it super easy to spin up endpoints fast. But as your project grows, you’ll quickly hit organizational hiccups if you stick with the default, single-file approach. Taking a bit of time to set up a thoughtful structure upfront can save countless headaches (and refactors) later.

    Common Project Structure

    Let’s look at a directory layout that works well for most mid- to large-sized projects:

    myfastapiapp/
    │
    ├── app/
    │   ├── __init__.py
    │   ├── main.py            # Application entrypoint
    │   ├── api/               # Routers and API logic
    │   │   ├── __init__.py
    │   │   └── v1/
    │   │       ├── __init__.py
    │   │       ├── endpoints/
    │   │       │   ├── __init__.py
    │   │       │   ├── users.py
    │   │       │   └── items.py
    │   │       └── dependencies.py
    │   ├── core/              # Core app configs, settings, security, etc.
    │   │   ├── __init__.py
    │   │   ├── config.py
    │   │   └── security.py
    │   ├── models/            # Pydantic and ORM models
    │   │   ├── __init__.py
    │   │   ├── user.py
    │   │   └── item.py
    │   ├── crud/              # CRUD operations, DB logic
    │   │   ├── __init__.py
    │   │   ├── user.py
    │   │   └── item.py
    │   ├── db/                # Database session, metadata
    │   │   ├── __init__.py
    │   │   └── session.py
    │   └── utils/             # Utility/helper functions
    │       ├── __init__.py
    │       └── email.py
    ├── tests/
    │   ├── __init__.py
    │   ├── test_users.py
    │   └── test_items.py
    ├── alembic/               # Database migrations (if using Alembic)
    ├── .env
    ├── requirements.txt
    ├── Dockerfile
    └── README.md
    

    Key Principles

    1. Separation of Concerns:

    • Keep endpoints, business logic, and data models in their own modules.
    • Avoid massive files that conglomerate unrelated logic.

    2. API Versioning:

    • Nest endpoints under /api/v1/ (and so on) directories from the start. This simplifies future upgrades and backward compatibility.

    3. Dependency Injection:

    • Place shared dependencies (auth, DB sessions, etc.) in dedicated dependencies.py files.

    4. Config Management:

    • House settings and startup logic in core/ for better organization and single sourcing of truth (read more in my previous article: "Managing Environment Variables in FastAPI Applications").

    5. Utility Layer:

    • Utilities or helpers go in a utils/ folder to keep business logic clean.

    Practical Example: Adding a User Endpoint

    Suppose you want to add /users endpoints. Here’s what you’d do:

    • Create a users.py file under both models/ and crud/ for the schemas and CRUD functions.
    • Add endpoint logic to api/v1/endpoints/users.py.
    • Route all /users requests from your main router file (api/v1/__init__.py).
    • Wire up dependencies in api/v1/dependencies.py as needed.

    Scaling Up

    This structure supports the addition of:

    • More teams or developers (clear file boundaries help code reviews and onboarding)
    • New API versions
    • Plugins or third-party integrations
    • Automated testing in the tests/ directory

    Summary

    Properly structuring your FastAPI application sets you up for easier maintenance, painless scaling, and happier developers. A clear directory layout is the unsung hero of a project’s success.

    Have your own best practices or run into structure headaches recently? Share your thoughts below or ping me on Dev Chat!

    — Fast Eddy

  • Squashing Commits in Git: Cleaning Up Your Project History

    Squashing Commits in Git: Cleaning Up Your Project History

    If you’ve ever ended up with a heap of noisy, work-in-progress (WIP) commits after a coding sprint, you know how messy a project’s commit history can get. Maintaining a clean, readable Git log is critical—especially for collaborative work and open source contributions. Today, I want to walk you through the powerful Git technique of "squashing commits," helping you present a tidy project history without losing important changes.

    Why Squash Commits?

    Squashing is the act of combining multiple consecutive commits into one. This is often used during a Git rebase to clean up a feature branch before merging it into main. It’s particularly helpful for:

    • Reducing noise: Fewer, more meaningful commits make it easier to track project history.
    • Improving clarity: Each squashed commit can reflect a well-defined change or feature.
    • Facilitating code reviews: Reviewers appreciate concise, logical changesets.

    How to Squash Commits

    There are a few ways to squash commits in Git, but the most common method is interactive rebase. Here’s a quick guide:

    1. Start Interactive Rebase

    git rebase -i HEAD~N
    

    Replace N with the number of commits you want to squash (e.g., HEAD~3 for the last 3 commits).

    2. The Interactive Screen

    Your default editor will open a list of the last N commits:

    pick 1a2b3c4 Add initial feature blueprint
    pick 2b3c4d5 Implement feature logic
    pick 3c4d5e6 Fix bug in feature
    

    Change all but the first pick to squash or simply s:

    pick 1a2b3c4 Add initial feature blueprint
    squash 2b3c4d5 Implement feature logic
    squash 3c4d5e6 Fix bug in feature
    

    3. Write a Commit Message

    Git will now prompt you to update the commit message for your new, squashed commit. You can combine all messages, summarize, or write a new concise description.

    4. Complete the Rebase

    Save and close the editor. Git will process the rebase and squash your selected commits into one.

    Best Practices for Squashing Commits

    • Communicate with your team before rebasing shared branches—rewriting history can impact collaborators.
    • Squash in feature branches before merging into main/trunk.
    • Use --autosquash with rebase if you’ve used fixup! or squash! commit prefixes.

    Wrapping Up

    Squashing commits is an essential Git technique for any developer seeking a clean and understandable history. It’s easy to adopt into your workflow and will vastly improve your team’s experience during code reviews and when tracing changes.

    Want more advanced tips? Check out my other articles on Git workflows and histories—let’s keep our repos as clean as our code!

    Happy coding!

    — Joe Git