jh941213/my-claude-code-asset/fastapi-templates

Claude Code and agent skill by jh941213/my-claude-code-asset

Trust tier 2
  • community
LLM review pending
Source check pending

Checking that the SKILL.md file is still in the repository.

새 FastAPI 프로젝트의 구조·설정·DB 세션·인증·테스트 뼈대를 잡을 때. Triggers - FastAPI, FastAPI 프로젝트 생성, FastAPI 템플릿, FastAPI 설정. Django·Flask·Node API에는 쓰지 않는다.

Install

npx vskill@latest install jh941213/my-claude-code-asset/fastapi-templates

SKILL.md

FastAPI Project Templates

FastAPI project structure with async SQLAlchemy 2.0, Pydantic v2, dependency injection, JWT auth, and tests.

Size it to the project. The layout below is for a service that will grow several resources. A small API keeps routes, schemas and queries in a few modules; add services/·repositories/ layers only when the project already uses them or the user asks. In an existing project, follow its structure instead of this one.

When to Use This Skill

  • Starting new FastAPI projects from scratch
  • Implementing async REST APIs with Python
  • Building high-performance web services and microservices
  • Creating async applications with PostgreSQL, MongoDB
  • Setting up API projects with proper structure and testing

Core Concepts

1. Project Structure

Recommended Layout:

app/
├── api/ # API routes
│ ├── v1/
│ │ ├── endpoints/
│ │ │ ├── users.py
│ │ │ ├── auth.py
│ │ │ └── items.py
│ │ └── router.py
│ └── dependencies.py # Shared dependencies
├── core/ # Core configuration
│ ├── config.py
│ ├── security.py
│ └── database.py
├── models/ # Database models
│ ├── user.py
│ └── item.py
├── schemas/ # Pydantic schemas
│ ├── user.py
│ └── item.py
├── services/ # Business logic
│ ├── user_service.py
│ └── auth_service.py
├── repositories/ # Data access
│ ├── user_repository.py
│ └── item_repository.py
└── main.py # Application entry
2. Dependency Injection

FastAPI's built-in DI system using Depends:

  • Database session management
  • Authentication/authorization
  • Shared business logic
  • Configuration injection
3. Async Patterns

Proper async/await usage:

  • Async route handlers
  • Async database operations
  • Async background tasks
  • Async middleware

Implementation Patterns

Pattern 1: Complete FastAPI Application
python
# main.py
from fastapi import FastAPI, Depends
from fastapi.middleware.cors import CORSMiddleware
from contextlib import asynccontextmanager
from app.core.config import get_settings
from app.core.database import engine
settings = get_settings()
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Startup before `yield`, shutdown after."""
yield
await engine.dispose()
app = FastAPI(
title="API Template",
version="1.0.0",
lifespan=lifespan
)
# CORS: list real origins. "*" together with credentials lets any site call the API as the user.
app.add_middleware(
CORSMiddleware,
allow_origins=settings.CORS_ORIGINS,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Include routers
from app.api.v1.router import api_router
app.include_router(api_router, prefix="/api/v1")
# core/config.py
from pydantic_settings import BaseSettings, SettingsConfigDict
from functools import lru_cache
class Settings(BaseSettings):
"""Application settings."""
model_config = SettingsConfigDict(env_file=".env")
DATABASE_URL: str
SECRET_KEY: str
ACCESS_TOKEN_EXPIRE_MINUTES: int = 30
API_V1_STR: str = "/api/v1"
CORS_ORIGINS: list[str] = ["http://localhost:3000"]
@lru_cache()
def get_settings() -> Settings:
return Settings()
# core/database.py
from collections.abc import AsyncIterator
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
from sqlalchemy.orm import DeclarativeBase
from app.core.config import get_settings
settings = get_settings()
engine = create_async_engine(settings.DATABASE_URL) # e.g. postgresql+asyncpg://...
AsyncSessionLocal = async_sessionmaker(engine, expire_on_commit=False)
class Base(DeclarativeBase):
pass
async def get_db() -> AsyncIterator[AsyncSession]:
"""One session per request; commit on success, roll back on error."""
async with AsyncSessionLocal() as session:
try:
yield session
await session.commit()
except Exception:
await session.rollback()
raise
Pattern 2: CRUD Repository Pattern
python
# repositories/base_repository.py
from typing import Any, Generic, TypeVar, Type, Optional, List
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from pydantic import BaseModel
ModelType = TypeVar("ModelType")
CreateSchemaType = TypeVar("CreateSchemaType", bound=BaseModel)
UpdateSchemaType = TypeVar("UpdateSchemaType", bound=BaseModel)
class BaseRepository(Generic[ModelType, CreateSchemaType, UpdateSchemaType]):
"""Base repository for CRUD operations."""
def __init__(self, model: Type[ModelType]):
self.model = model
async def get(self, db: AsyncSession, id: int) -> Optional[ModelType]:
"""Get by ID."""
result = await db.execute(
select(self.model).where(self.model.id == id)
)
return result.scalars().first()
async def get_multi(
self,
db: AsyncSession,
skip: int = 0,
limit: int = 100
) -> List[ModelType]:
"""Get multiple records."""
result = await db.execute(
select(self.model).order_by(self.model.id).offset(skip).limit(limit)
)
return list(result.scalars().all())
async def create(
self,
db: AsyncSession,
obj_in: CreateSchemaType | dict[str, Any]
) -> ModelType:
"""Create new record."""
data = obj_in if isinstance(obj_in, dict) else obj_in.model_dump()
db_obj = self.model(**data)
db.add(db_obj)
await db.flush()
await db.refresh(db_obj)
return db_obj
async def update(
self,
db: AsyncSession,
db_obj: ModelType,
obj_in: UpdateSchemaType | dict[str, Any]
) -> ModelType:
"""Update record."""
update_data = obj_in if isinstance(obj_in, dict) else obj_in.model_dump(exclude_unset=True)
for field, value in update_data.items():
setattr(db_obj, field, value)
await db.flush()
await db.refresh(db_obj)
return db_obj
async def delete(self, db: AsyncSession, id: int) -> bool:
"""Delete record."""
obj = await self.get(db, id)
if obj:
await db.delete(obj)
return True
return False
# repositories/user_repository.py
from typing import Optional
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.repositories.base_repository import BaseRepository
from app.models.user import User
from app.schemas.user import UserCreate, UserUpdate
class UserRepository(BaseRepository[User, UserCreate, UserUpdate]):
"""User-specific repository."""
async def get_by_email(self, db: AsyncSession, email: str) -> Optional[User]:
"""Get user by email."""
result = await db.execute(
select(User).where(User.email == email)
)
return result.scalars().first()
async def is_active(self, db: AsyncSession, user_id: int) -> bool:
"""Check if user is active."""
user = await self.get(db, user_id)
return user.is_active if user else False
user_repository = UserRepository(User)
Pattern 3: Service Layer
python
# services/user_service.py
from typing import Optional
from sqlalchemy.ext.asyncio import AsyncSession
from app.repositories.user_repository import user_repository
from app.schemas.user import UserCreate, UserUpdate, User
from app.core.security import get_password_hash, verify_password
class UserService:
"""Business logic for users."""
def __init__(self):
self.repository = user_repository
async def create_user(
self,
db: AsyncSession,
user_in: UserCreate
) -> User:
"""Create new user with hashed password."""
# Check if email exists
existing = await self.repository.get_by_email(db, user_in.email)
if existing:
raise ValueError("Email already registered")
# Hash password; pass a dict so the extra column isn't dropped by schema validation
data = user_in.model_dump()
data["hashed_password"] = get_password_hash(data.pop("password"))
return await self.repository.create(db, data)
async def authenticate(
self,
db: AsyncSession,
email: str,
password: str
) -> Optional[User]:
"""Authenticate user."""
user = await self.repository.get_by_email(db, email)
if not user:
return None
if not verify_password(password, user.hashed_password):
return None
return user
async def update_user(
self,
db: AsyncSession,
user_id: int,
user_in: UserUpdate
) -> Optional[User]:
"""Update user."""
user = await self.repository.get(db, user_id)
if not user:
return None
data = user_in.model_dump(exclude_unset=True)
if data.get("password"):
data["hashed_password"] = get_password_hash(data.pop("password"))
return await self.repository.update(db, user, data)
user_service = UserService()
Pattern 4: API Endpoints with Dependencies
python
# api/v1/endpoints/users.py
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession
from typing import List
from app.core.database import get_db
from app.schemas.user import User, UserCreate, UserUpdate
from app.services.user_service import user_service
from app.api.dependencies import get_current_user
router = APIRouter()
@router.post("/", response_model=User, status_code=status.HTTP_201_CREATED)
async def create_user(
user_in: UserCreate,
db: AsyncSession = Depends(get_db)
):
"""Create new user."""
try:
user = await user_service.create_user(db, user_in)
return user
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
@router.get("/me", response_model=User)
async def read_current_user(
current_user: User = Depends(get_current_user)
):
"""Get current user."""
return current_user
@router.get("/{user_id}", response_model=User)
async def read_user(
user_id: int,
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_user)
):
"""Get user by ID."""
user = await user_service.repository.get(db, user_id)
if not user:
raise HTTPException(status_code=404, detail="User not found")
return user
@router.patch("/{user_id}", response_model=User)
async def update_user(
user_id: int,
user_in: UserUpdate,
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_user)
):
"""Update user."""
if current_user.id != user_id:
raise HTTPException(status_code=403, detail="Not authorized")
user = await user_service.update_user(db, user_id, user_in)
if not user:
raise HTTPException(status_code=404, detail="User not found")
return user
@router.delete("/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_user(
user_id: int,
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_user)
):
"""Delete user."""
if current_user.id != user_id:
raise HTTPException(status_code=403, detail="Not authorized")
deleted = await user_service.repository.delete(db, user_id)
if not deleted:
raise HTTPException(status_code=404, detail="User not found")
Pattern 5: Authentication & Authorization
python
# core/security.py (pip install pyjwt "pwdlib[argon2]")
from datetime import datetime, timedelta, timezone
from typing import Optional
import jwt
from pwdlib import PasswordHash
from app.core.config import get_settings
settings = get_settings()
password_hash = PasswordHash.recommended()
ALGORITHM = "HS256"

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 100 of 100Pattern checks on the skill's files.
  • Model reviewNot runA model review is scheduled for the next rescan.

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
118
Repository forks
35
7-day trend score
24

Stars and forks are for the whole GitHub repository, not this skill alone. Refreshed 7 May 2026, 6 months ago.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/jh941213/my-claude-code-asset/fastapi-templates/badge)](https://verified-skill.com/skills/jh941213/my-claude-code-asset/fastapi-templates)

Something wrong with this skill or its page? Tell us.