AgentStack
SKILL verified Apache-2.0 Self-run

Python

skill-aps08-fullstack-clean-architecture-python · by aps08

Enforces FastAPI, Dependency Injection, and general Python coding standards based on the repository structure.

No reviews yet
0 installs
3 views
0.0% view→install

Install

$ agentstack add skill-aps08-fullstack-clean-architecture-python

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Python? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Python & FastAPI Coding & Architecture Guidelines

Use this skill when extending the Python backend, writing routes, services, or repositories, or working with core server logic.


1. FastAPI & Dependency Injection

We use dependency-injector for wiring application components together.

  • Wiring: The container is defined in server/app/core/container.py and wired in server/app/main.py.
  • Dependency injection in Routes:
  • Decorate endpoints with @inject (from dependency_injector.wiring).
  • Create clean dependency type aliases using Annotated and Depends(Provide[Container.service_name]).
  • Example:

```python TodoServiceDep = Annotated[TodoService, Depends(Provide[Container.todo_service])]

@router.get("/todos/") @inject async def list_todos(service: TodoServiceDep): ... ```

  • No Direct Instantiation: Do not manually instantiate services or repositories; resolve them via the container.

2. FastAPI Route & Handler Best Practices

Use Annotated

Always prefer the Annotated style for parameter and dependency declarations.

from typing import Annotated
from fastapi import Path, Query

@router.get("/items/{item_id}")
async def read_item(
    item_id: Annotated[UUID, Path(description="The item ID")],
    q: Annotated[str | None, Query(max_length=50)] = None,
):
    ...

Return Types & response_model

  • Specify explicit return type annotations (-> Model) for FastAPI validation, filtering, and serialization (running Pydantic's Rust-based serialization).
  • If the returned object differs from the API response contract (e.g. returning a database model that needs filtering/serialization to a public schema), use response_model on the router decorator instead:
@router.get("/todos/{todo_id}", response_model=Todo)
async def get_todo(todo_id: UUID) -> Any:
    ...

No Ellipsis (...) for Required Fields

Do not use ... as a default value for required fields or query parameters.

# CORRECT
async def create_item(item: Item, project_id: Annotated[int, Query()]): ...

# INCORRECT
async def create_item(item: Item, project_id: Annotated[int, Query(...)]): ...

Declaring APIRouters

Prefer defining path prefixes and tags on the router itself, rather than in include_router():

router = APIRouter(prefix="/todos", tags=["todos"])

Async vs Sync Handlers

  • Use async def only when calling await-compatible non-blocking code.
  • If a route calls blocking code (like synchronous DB queries or filesystem operations), use standard def instead of async def so FastAPI runs it in an external threadpool.

Do not use Pydantic RootModel

Instead, use regular type annotations with Annotated and validation utilities:

@router.post("/items/")
async def create_items(items: Annotated[list[int], Field(min_length=1), Body()]):
    return items

One HTTP Method Per Function

Keep handler functions dedicated to a single HTTP operation. Do not use @router.api_route for multiple methods in a single function.


3. Layered Architecture

Always structure backend logic using the established 3-layer architecture:

  1. Routes/Endpoints (app/routes): Parse requests, validate inputs via Pydantic, call services, and handle HTTP routing. Keep business logic out of this layer.
  2. Services (app/services): Implement business logic, orchestration, and validation checks. Inherit from BaseService for CRUD operations.
  3. Repositories (app/repositories): Handle raw database persistence and queries using SQLAlchemy. Inherit from BaseRepository.

4. Database Scopes & Transactions

  • Scoped Sessions: Uses async_scoped_session keyed by a unique request-based UUID context variable.
  • Transactions:
  • Service-level or middleware-level functions run within async with db.session_scope(): to ensure automatic rollback on failure and commit on success.
  • Always perform queries asynchronously (e.g. await session.execute(...)).
  • Timezones: Use timezone-aware datetime objects (TIMESTAMP(timezone=True)) or Pydantic UTC validation.

5. Code Quality & Type Safety

  • Type Annotations: Annotate all function signatures and variables. Use Annotated, TypeVar, and Generic for generic classes like repositories.
  • Pydantic Models: Define explicit request/response schemas under app/schemas/.
  • Ensure they map accurately to database models.
  • Configure model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True, from_attributes=True) for camelCase serialization support.
  • Error Handling: Centralize errors using specific exceptions defined in app/core/exceptions.py (e.g. NotFoundError, DuplicatedError).

6. Background Tasks

  • Always use BackgroundTasks when sending emails or other long-running tasks to prevent user delays in response to user requests.

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.