supabase
Handles the full Supabase workflow from schema changes to deployment, with built-in security guardrails that catch common traps like RLS...
api-design-expert
Expert-level API design principles, REST, GraphQL, versioning, and API best practices
Full skill instructions
Expert guidance for API design, RESTful principles, GraphQL, versioning strategies, and API best practices.
from fastapi import FastAPI, HTTPException, Query, Path, Header
from pydantic import BaseModel, Field
from typing import List, Optional
from datetime import datetime
from enum import Enum
app = FastAPI(
title="User Management API",
version="1.0.0",
description="RESTful API for user management"
)
# Models
class UserRole(str, Enum):
ADMIN = "admin"
USER = "user"
GUEST = "guest"
class UserCreate(BaseModel):
email: str = Field(..., example="[email protected]")
name: str = Field(..., min_length=1, max_length=100)
role: UserRole = UserRole.USER
class UserResponse(BaseModel):
id: str
email: str
name: str
role: UserRole
created_at: datetime
updated_at: datetime
class Config:
schema_extra = {
"example": {
"id": "123e4567-e89b-12d3-a456-426614174000",
"email": "[email protected]",
"name": "John Doe",
"role": "user",
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-01T00:00:00Z"
}
}
class UserUpdate(BaseModel):
name: Optional[str] = Field(None, min_length=1, max_length=100)
role: Optional[UserRole] = None
# REST Endpoints following best practices
@app.get("/api/v1/users",
response_model=List[UserResponse],
summary="List all users",
tags=["Users"])
async def list_users(
page: int = Query(1, ge=1, description="Page number"),
page_size: int = Query(20, ge=1, le=100, description="Items per page"),
sort: str = Query("created_at", description="Sort field"),
order: str = Query("desc", regex="^(asc|desc)$")
):
"""
Retrieve a paginated list of users.
- **page**: Page number (starts at 1)
- **page_size**: Number of items per page (1-100)
- **sort**: Field to sort by
- **order**: Sort order (asc or desc)
"""
# Implementation
return []
@app.get("/api/v1/users/{user_id}",
response_model=UserResponse,
summary="Get user by ID",
tags=["Users"])
async def get_user(
user_id: str = Path(..., description="User ID")
):
"""Retrieve a specific user by ID."""
# Implementation
raise HTTPException(status_code=404, detail="User not found")
@app.post("/api/v1/users",
response_model=UserResponse,
status_code=201,
summary="Create new user",
tags=["Users"])
async def create_user(user: UserCreate):
"""Create a new user."""
# Implementation
return UserResponse(
id="123e4567-e89b-12d3-a456-426614174000",
email=user.email,
name=user.name,
role=user.role,
created_at=datetime.now(),
updated_at=datetime.now()
)
@app.patch("/api/v1/users/{user_id}",
response_model=UserResponse,
summary="Update user",
tags=["Users"])
async def update_user(
user_id: str = Path(..., description="User ID"),
user: UserUpdate = None
):
"""Partially update a user."""
# Implementation
pass
@app.delete("/api/v1/users/{user_id}",
status_code=204,
summary="Delete user",
tags=["Users"])
async def delete_user(
user_id: str = Path(..., description="User ID")
):
"""Delete a user."""
# Implementation
pass
# Nested resources
@app.get("/api/v1/users/{user_id}/posts",
summary="Get user posts",
tags=["Users", "Posts"])
async def get_user_posts(user_id: str):
"""Retrieve all posts for a specific user."""
return []
from fastapi import APIRouter, Request
# URL Path Versioning (Recommended)
v1_router = APIRouter(prefix="/api/v1")
v2_router = APIRouter(prefix="/api/v2")
@v1_router.get("/users")
async def get_users_v1():
"""Version 1: Returns basic user info"""
return [{"id": 1, "name": "John"}]
@v2_router.get("/users")
async def get_users_v2():
"""Version 2: Returns enhanced user info"""
return [{"id": 1, "name": "John", "email": "[email protected]"}]
# Header Versioning
async def version_from_header(request: Request):
version = request.headers.get("API-Version", "1")
return version
@app.get("/api/users")
async def get_users(version: str = Depends(version_from_header)):
if version == "2":
return get_users_v2()
return get_users_v1()
# Content Negotiation Versioning
@app.get("/api/users")
async def get_users_content_negotiation(
accept: str = Header("application/vnd.api+json; version=1")
):
if "version=2" in accept:
return get_users_v2()
return get_users_v1()
from fastapi import FastAPI, HTTPException
from fastapi.responses import JSONResponse
from pydantic import BaseModel, ValidationError
class ErrorResponse(BaseModel):
error: str
message: str
details: Optional[dict] = None
timestamp: datetime
path: str
@app.exception_handler(HTTPException)
async def http_exception_handler(request: Request, exc: HTTPException):
return JSONResponse(
status_code=exc.status_code,
content=ErrorResponse(
error=exc.status_code,
message=exc.detail,
timestamp=datetime.now(),
path=request.url.path
).dict()
)
@app.exception_handler(ValidationError)
async def validation_exception_handler(request: Request, exc: ValidationError):
return JSONResponse(
status_code=422,
content=ErrorResponse(
error="validation_error",
message="Request validation failed",
details=exc.errors(),
timestamp=datetime.now(),
path=request.url.path
).dict()
)
# Custom business logic errors
class BusinessError(Exception):
def __init__(self, message: str, code: str):
self.message = message
self.code = code
@app.exception_handler(BusinessError)
async def business_error_handler(request: Request, exc: BusinessError):
return JSONResponse(
status_code=400,
content=ErrorResponse(
error=exc.code,
message=exc.message,
timestamp=datetime.now(),
path=request.url.path
).dict()
)
from fastapi import Request, HTTPException
from datetime import datetime, timedelta
import redis
from typing import Dict
class RateLimiter:
def __init__(self, redis_client: redis.Redis):
self.redis = redis_client
async def check_rate_limit(self,
key: str,
max_requests: int,
window_seconds: int) -> Dict:
"""
Token bucket algorithm for rate limiting
"""
now = datetime.now().timestamp()
window_key = f"rate_limit:{key}:{int(now // window_seconds)}"
pipe = self.redis.pipeline()
pipe.incr(window_key)
pipe.expire(window_key, window_seconds)
result = pipe.execute()
request_count = result[0]
if request_count > max_requests:
reset_time = (int(now // window_seconds) + 1) * window_seconds
raise HTTPException(
status_code=429,
detail="Rate limit exceeded",
headers={
"X-RateLimit-Limit": str(max_requests),
"X-RateLimit-Remaining": "0",
"X-RateLimit-Reset": str(reset_time)
}
)
return {
"limit": max_requests,
"remaining": max_requests - request_count,
"reset": (int(now // window_seconds) + 1) * window_seconds
}
# Middleware for rate limiting
@app.middleware("http")
async def rate_limit_middleware(request: Request, call_next):
limiter = RateLimiter(redis_client)
# Get client identifier (IP, API key, etc.)
client_id = request.client.host
try:
rate_info = await limiter.check_rate_limit(
client_id,
max_requests=100,
window_seconds=60
)
response = await call_next(request)
# Add rate limit headers
response.headers["X-RateLimit-Limit"] = str(rate_info["limit"])
response.headers["X-RateLimit-Remaining"] = str(rate_info["remaining"])
response.headers["X-RateLimit-Reset"] = str(rate_info["reset"])
return response
except HTTPException as e:
return JSONResponse(
status_code=e.status_code,
content={"error": e.detail},
headers=e.headers
)
from typing import Dict, List
class HATEOASResponse(BaseModel):
data: dict
links: Dict[str, str]
def create_links(resource_id: str, resource_type: str) -> Dict[str, str]:
"""Create HATEOAS links for a resource"""
return {
"self": f"/api/v1/{resource_type}/{resource_id}",
"update": f"/api/v1/{resource_type}/{resource_id}",
"delete": f"/api/v1/{resource_type}/{resource_id}",
"collection": f"/api/v1/{resource_type}"
}
@app.get("/api/v1/users/{user_id}", response_model=HATEOASResponse)
async def get_user_with_links(user_id: str):
user = get_user_from_db(user_id)
return HATEOASResponse(
data=user,
links={
"self": f"/api/v1/users/{user_id}",
"posts": f"/api/v1/users/{user_id}/posts",
"profile": f"/api/v1/users/{user_id}/profile",
"update": f"/api/v1/users/{user_id}",
"delete": f"/api/v1/users/{user_id}"
}
)
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from jose import JWTError, jwt
from passlib.context import CryptContext
security = HTTPBearer()
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
SECRET_KEY = "your-secret-key"
ALGORITHM = "HS256"
async def verify_token(credentials: HTTPAuthorizationCredentials = Depends(security)):
"""Verify JWT token"""
try:
payload = jwt.decode(
credentials.credentials,
SECRET_KEY,
algorithms=[ALGORITHM]
)
return payload
except JWTError:
raise HTTPException(
status_code=401,
detail="Invalid authentication credentials"
)
@app.get("/api/v1/protected")
async def protected_route(token_payload: dict = Depends(verify_token)):
return {"message": "Access granted", "user": token_payload}
# API Key Authentication
async def verify_api_key(api_key: str = Header(...)):
"""Verify API key"""
if api_key not in valid_api_keys:
raise HTTPException(status_code=403, detail="Invalid API key")
return api_key
❌ Using GET for state-changing operations ❌ Returning inconsistent response formats ❌ No versioning strategy ❌ Poor error messages ❌ No rate limiting ❌ Exposing internal implementation details ❌ Breaking changes without versioning
Handles the full Supabase workflow from schema changes to deployment, with built-in security guardrails that catch common traps like RLS...
Comprehensive guides and best practices for Neon Serverless Postgres, covering setup, connection methods, authentication, and platform APIs.
Guide for setting up and using Firebase Authentication. Use this skill when the user's app requires user sign-in, user management, or secure data access using auth rules.
A skill to evaluate how secure Firestore security rules are. Use this when Firestore security rules are updated to ensure that the generated rules are extremely secure and robust.
Official skill for integrating Firebase AI Logic (Gemini API) into web applications. Covers setup, multimodal inference, structured output, and security.
Complete Better Auth server and client setup with database adapters, session management, plugins, and security configuration.
Deploy and manage projects on Vercel using token-based authentication. Use when working with Vercel CLI using access tokens rather than interactive login — e.g. "deploy to vercel", "set up vercel", "add environment variables to vercel".
Complete Cloudflare platform integration with decision trees for compute, storage, AI, networking, security, and infrastructure-as-code.
Run Azure compliance and security audits with azqr plus Key Vault expiration checks. Covers best-practice assessment, resource review, policy/compliance validation, and security posture checks. WHEN: compliance scan, security audit, BEFORE running azqr (compliance cli tool), Azure best practices, Key Vault expiration check, expired certificates, expiring secrets, orphaned resources, compliance assessment.
Send, read, and manage Gmail messages, drafts, labels, and account settings.
Comprehensive website auditing across 230+ rules in 21 categories including SEO, performance, security, and accessibility.
Shared authentication, CLI syntax, and output formatting patterns for gws Google Workspace commands.
Discover your celebrity doppelgänger with StarByFace!
GeoSpy: Pricing, Features, FAQs, and Alternatives for AI Teams
Detect AI-generated voices to protect against audio fraud.
Ensure Your Content's Originality with AI Plagiarism Checker
Upscale images by 400% without quality loss
Protect your social media from copyright disputes
Accurately Detect AI-Generated Content with TheChecker.AI
Chrome extension that detects and flags AI-generated content