fastapi-router-py
Create FastAPI routers with CRUD operations, authentication dependencies, and proper response models. Use when building REST API endpoints, creating new routes, implementing CRUD operations, or adding authenticated endpoints in FastAPI applications.
Install
npx skills add https://github.com/microsoft/skills/tree/main/.github/plugins/azure-sdk-python/skills/fastapi-router-py
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install microsoft-skills@llmmart
git clone https://github.com/microsoft/skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole microsoft/skills collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
FastAPI Router
Create FastAPI routers following established patterns with proper authentication, response models, and HTTP status codes.
Quick Start
Copy the template from assets/template.py and replace placeholders:
{{ResourceName}}→ PascalCase name (e.g.,Project){{resource_name}}→ snake_case name (e.g.,project){{resource_plural}}→ plural form (e.g.,projects)
Authentication Patterns
# Optional auth - returns None if not authenticated
current_user: Optional[User] = Depends(get_current_user)
# Required auth - raises 401 if not authenticated
current_user: User = Depends(get_current_user_required)
Response Models
@router.get("/items/{item_id}", response_model=Item)
async def get_item(item_id: str) -> Item:
...
@router.get("/items", response_model=list[Item])
async def list_items() -> list[Item]:
...
HTTP Status Codes
@router.post("/items", status_code=status.HTTP_201_CREATED)
async def create_item(item: ItemCreate) -> Item:
...
@router.delete("/items/{id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_item(id: str) -> None:
...
Integration Steps
- Create router in
src/backend/app/routers/ - Mount in
src/backend/app/main.py - Create corresponding Pydantic models
- Create service layer if needed
- Add frontend API functions
Best Practices
- Pick
deforasync defper endpoint based on whether you call async I/O; do not call blocking I/O from anasync defhandler. - Manage long-lived resources (DB pools, HTTP clients) in
lifespanand inject viaDepends; usewith/async withfor per-request resources.
Reference Files
| File | Contents |
|---|---|
| references/capabilities.md | Additional non-hero capabilities, operation-group coverage, and production checklists. |
Files (skills)
-
assets
-
template.py 4.6 KB
""" {{ResourceName}} Router Handles CRUD operations for {{resource_name}} resources. Template placeholders to replace: - {{ResourceName}} (PascalCase) - {{resource_name}} (snake_case) - {{resource_plural}} (plural snake_case) """ from typing import Optional from fastapi import APIRouter, Depends, HTTPException, Query, status from app.auth.jwt import get_current_user, get_current_user_required from app.models.user import User from app.models.{{resource_name}} import ( {{ResourceName}}, {{ResourceName}}Create, {{ResourceName}}Update, ) from app.services.{{resource_name}}_service import {{ResourceName}}Service router = APIRouter(prefix="/api", tags=["{{resource_plural}}"]) # ============================================================================ # Dependencies # ============================================================================ def get_service() -> {{ResourceName}}Service: """Dependency to get service instance.""" return {{ResourceName}}Service() # ============================================================================ # Endpoints # ============================================================================ @router.get("/{{resource_plural}}", response_model=list[{{ResourceName}}]) async def list_{{resource_plural}}( limit: int = Query(default=50, ge=1, le=100), offset: int = Query(default=0, ge=0), current_user: Optional[User] = Depends(get_current_user), service: {{ResourceName}}Service = Depends(get_service), ) -> list[{{ResourceName}}]: """ List all {{resource_plural}}. - **limit**: Maximum number of items to return (1-100) - **offset**: Number of items to skip """ return await service.list_{{resource_plural}}(limit=limit, offset=offset) @router.get("/{{resource_plural}}/{{{resource_name}}_id}", response_model={{ResourceName}}) async def get_{{resource_name}}( {{resource_name}}_id: str, current_user: Optional[User] = Depends(get_current_user), service: {{ResourceName}}Service = Depends(get_service), ) -> {{ResourceName}}: """ Get a specific {{resource_name}} by ID. Raises 404 if not found. """ result = await service.get_{{resource_name}}_by_id({{resource_name}}_id) if result is None: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="{{ResourceName}} not found", ) return result @router.post( "/{{resource_plural}}", response_model={{ResourceName}}, status_code=status.HTTP_201_CREATED, ) async def create_{{resource_name}}( data: {{ResourceName}}Create, current_user: User = Depends(get_current_user_required), service: {{ResourceName}}Service = Depends(get_service), ) -> {{ResourceName}}: """ Create a new {{resource_name}}. Requires authentication. """ return await service.create_{{resource_name}}(data, current_user.id) @router.patch("/{{resource_plural}}/{{{resource_name}}_id}", response_model={{ResourceName}}) async def update_{{resource_name}}( {{resource_name}}_id: str, data: {{ResourceName}}Update, current_user: User = Depends(get_current_user_required), service: {{ResourceName}}Service = Depends(get_service), ) -> {{ResourceName}}: """ Update an existing {{resource_name}}. Requires authentication and ownership. """ # Verify ownership existing = await service.get_{{resource_name}}_by_id({{resource_name}}_id) if existing is None: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="{{ResourceName}} not found", ) # Optional: Check ownership # if existing.author_id != current_user.id: # raise HTTPException( # status_code=status.HTTP_403_FORBIDDEN, # detail="Not authorized to update this {{resource_name}}", # ) return await service.update_{{resource_name}}({{resource_name}}_id, data) @router.delete( "/{{resource_plural}}/{{{resource_name}}_id}", status_code=status.HTTP_204_NO_CONTENT, ) async def delete_{{resource_name}}( {{resource_name}}_id: str, current_user: User = Depends(get_current_user_required), service: {{ResourceName}}Service = Depends(get_service), ) -> None: """ Delete a {{resource_name}}. Requires authentication and ownership. """ existing = await service.get_{{resource_name}}_by_id({{resource_name}}_id) if existing is None: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="{{ResourceName}} not found", ) await service.delete_{{resource_name}}({{resource_name}}_id)
-
-
references
-
capabilities.md 934 B
# fastapi-router-py capability coverage **SDK/package**: `fastapi` This reference captures additional non-hero capabilities and API breadth so the main `SKILL.md` can stay focused on copy/paste hero flows. ## Hero scenarios covered in SKILL.md - `Quick Start` - `Authentication Patterns` - `Response Models` - `HTTP Status Codes` ## Important non-hero scenarios to include when needed - `Integration Steps` - `Best Practices` ## API breadth checklist - Verify dependency lifetimes (`Depends` with `yield`) for resources like DB connections and HTTP clients. - Confirm request/response validation uses Pydantic models with appropriate field constraints. - Include proper error responses with `HTTPException` and correct status codes. - Avoid blocking I/O in `async def` endpoints; use `run_in_executor` or a thread-pool for sync calls. - Validate middleware, background tasks, and lifespan event patterns for production paths.
-
-
SKILL.md 2.2 KB
--- name: fastapi-router-py description: Create FastAPI routers with CRUD operations, authentication dependencies, and proper response models. Use when building REST API endpoints, creating new routes, implementing CRUD operations, or adding authenticated endpoints in FastAPI applications. license: MIT metadata: author: Microsoft version: "1.0.0" --- # FastAPI Router Create FastAPI routers following established patterns with proper authentication, response models, and HTTP status codes. ## Quick Start Copy the template from [assets/template.py](assets/template.py) and replace placeholders: - `{{ResourceName}}` → PascalCase name (e.g., `Project`) - `{{resource_name}}` → snake_case name (e.g., `project`) - `{{resource_plural}}` → plural form (e.g., `projects`) ## Authentication Patterns ```python # Optional auth - returns None if not authenticated current_user: Optional[User] = Depends(get_current_user) # Required auth - raises 401 if not authenticated current_user: User = Depends(get_current_user_required) ``` ## Response Models ```python @router.get("/items/{item_id}", response_model=Item) async def get_item(item_id: str) -> Item: ... @router.get("/items", response_model=list[Item]) async def list_items() -> list[Item]: ... ``` ## HTTP Status Codes ```python @router.post("/items", status_code=status.HTTP_201_CREATED) async def create_item(item: ItemCreate) -> Item: ... @router.delete("/items/{id}", status_code=status.HTTP_204_NO_CONTENT) async def delete_item(id: str) -> None: ... ``` ## Integration Steps 1. Create router in `src/backend/app/routers/` 2. Mount in `src/backend/app/main.py` 3. Create corresponding Pydantic models 4. Create service layer if needed 5. Add frontend API functions ## Best Practices 1. **Pick `def` or `async def` per endpoint based on whether you call async I/O; do not call blocking I/O from an `async def` handler.** 2. **Manage long-lived resources (DB pools, HTTP clients) in `lifespan` and inject via `Depends`;** use `with`/`async with` for per-request resources. ## Reference Files | File | Contents | |------|----------| | [references/capabilities.md](references/capabilities.md) | Additional non-hero capabilities, operation-group coverage, and production checklists. |
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.