Skip to content
Back to skills

Backend

ASecurity

Generating REST endpoints in FastAPI or Spring Boot (`implementer:build`, `architect:api`)

  • 3 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 1, 2026
ai-agentspythonrustgojavasqlfastapispringtestinggitapi

Works with

  • api

Security analysis

A100/100

Scanned October 1, 2026

npx -y skills add sharmapuneet1510/awesome-prompts --skill backend --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Backend?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Backend
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/sharmapuneet1510-backend/badge)](https://www.skillsdirectory.com/skills/sharmapuneet1510-backend)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: backend
description: Generating REST endpoints in FastAPI or Spring Boot (`implementer:build`, `architect:api`)
---

# Backend API Generation Skill — v1.1

## Quick Card

> Read this card first. Load a section below only when the task needs it.

| | |
|---|---|
| **Use when** | Generating REST endpoints in FastAPI or Spring Boot (`implementer:build`, `architect:api`) |
| **Skip when** | Language idioms alone — load `python_advanced_skill` / `java_advanced_skill` |
| **Inputs** | Endpoint list, auth type, data models, error scenarios, performance targets |
| **Produces** | Routers/controllers, request/response models, service + repository layers, DDL, tests |
| **Steps** | 1. Analyse requirements → 2. Define request/response models → 3. Implement service logic → 4. Wire routes with status codes → 5. Add auth + validation → 6. Test |
| **Done when** | §Validation Checklist passes; every endpoint documents its error responses |
| **Senior defaults** | Sync DB session → plain `def` handler (or go fully async with `AsyncSession`) · PyJWT + pwdlib (Argon2id), not python-jose/passlib · verify a dummy hash for unknown users so timing cannot enumerate accounts · Pydantic v2 `model_config`, never `class Config` · validate at the boundary, trust inside |
| **Load on demand** | §Input · §Output · §Process · §Code Example · §Validation Checklist |
| **Run report** | `html_report_skill` — adds: Endpoint table (method · path · auth · status codes) |
| **Pairs with** | `python_advanced_skill`, `java_advanced_skill`, `database_skill`, `test_skill`, `security_audit_skill` |

---

## Purpose

This skill provides a comprehensive framework for generating production-grade backend APIs across Python (FastAPI) and Java (Spring Boot) ecosystems. It combines the advanced coding standards from `python_advanced_skill` and `java_advanced_skill` with API-specific patterns for route design, input validation, authentication, error handling, and testing.

The skill ensures consistent API contracts, security best practices, and maintainability across different backend platforms.

## Input

### Task Specification
- **API endpoint requirements**: List of endpoints with HTTP methods (GET, POST, PUT, DELETE, PATCH)
- **Authentication type**: JWT, OAuth2, API key, or none
- **Data models**: Entity definitions with relationships and validation rules
- **Business logic**: Core algorithms and business rules to implement
- **Error scenarios**: Expected failure cases and error codes
- **Performance requirements**: Throughput, latency, and concurrency targets

### Context
- **Platform choice**: Python (FastAPI) or Java (Spring Boot)
- **Database**: PostgreSQL, MySQL, MongoDB, or in-memory
- **Existing services**: References to other microservices or external APIs
- **Compliance requirements**: GDPR, PCI-DSS, SOC2, or industry-specific
- **Team expertise**: Current team skill levels and tech preferences

### Tech Stack
- **Python Stack**: FastAPI 0.104+, Pydantic 2.x, SQLAlchemy 2.x, PyJWT for tokens, pwdlib (Argon2) for password hashing — not `python-jose` or `passlib`, both unmaintained
- **Java Stack**: Spring Boot 3.x, Spring Security, Spring Data JPA, jsonwebtoken
- **Shared**: RESTful design patterns, OpenAPI/Swagger documentation, comprehensive testing

## Output

### API Routes
- Fully implemented endpoint handlers with proper HTTP methods and status codes
- Route grouping using routers/controllers for maintainability
- Input/output serialization with Pydantic models (Python) or DTOs (Java)
- Query parameter validation and path parameter extraction

### Data Models
- Domain entities with all relationships defined
- Validation constraints (required fields, length limits, regex patterns)
- Serialization models for API responses
- Change audit fields (created_at, updated_at, created_by, updated_by)

### Service Layer
- Business logic isolated in service classes
- Transaction management and ACID compliance
- Caching strategies for frequently accessed data
- Error handling with custom exceptions

### Database Schemas
- SQL DDL statements for table creation
- Indexes for performance optimization
- Foreign key constraints and relationships
- Migration scripts for schema evolution

### Comprehensive Tests
- Unit tests for business logic with 80%+ code coverage
- Integration tests for API endpoints
- Authentication/authorization tests
- Error scenario validation
- Performance/load tests for critical paths

## Process

### Step 1: Analyze Requirements
- Understand the problem domain and business rules
- Identify all API endpoints and their operations
- Map data models and relationships
- Determine authentication and authorization needs
- List error scenarios and their handling strategies

### Step 2: Design API Contract
- Define endpoint paths following REST conventions (`/api/v1/resource`)
- Specify HTTP methods (GET for reads, POST for creates, PUT/PATCH for updates, DELETE for deletions)
- Design request/response body schemas
- Plan error response format
- Document with OpenAPI/Swagger specs

### Step 3: Implement Data Models
- Create Pydantic models (Python) or JPA entities (Java) with validation
- Include audit fields (created_at, updated_at, created_by)
- Define relationships (one-to-many, many-to-many)
- Add constraints and indexes for performance

### Step 4: Implement Authentication/Authorization
- Set up JWT token generation and validation
- Implement password hashing (Argon2id via pwdlib, or bcrypt)
- Create middleware/filters for route protection
- Design role-based access control (RBAC) if needed

### Step 5: Implement Routes with Input Validation
- Create route handlers/controller methods
- Add Pydantic field validation (Python) or Bean Validation (Java)
- Implement proper error handling with meaningful messages
- Return correct HTTP status codes (200, 201, 204, 400, 401, 403, 404, 409, 500)

### Step 6: Implement Service Layer
- Extract business logic into service classes
- Ensure separation of concerns between routes and business logic
- Handle transactions properly
- Implement proper exception handling

### Step 7: Write Comprehensive Tests
- Unit tests for service layer
- Integration tests for full API flow
- Mock external dependencies
- Test all error scenarios
- Aim for 80%+ code coverage

### Step 8: Document API
- Generate OpenAPI/Swagger documentation
- Document authentication method
- Provide example requests and responses
- Include error code reference

## Code Example: FastAPI Authentication Endpoints

```python
# routes/auth.py
from datetime import datetime, timedelta, timezone
from typing import Optional

from fastapi import APIRouter, HTTPException, status, Depends
import jwt  # PyJWT
from pwdlib import PasswordHash
from pydantic import BaseModel, ConfigDict, EmailStr, Field
from sqlalchemy.orm import Session

from db.database import get_db
from models.user import User
from config import settings

router = APIRouter(prefix="/api/v1/auth", tags=["authentication"])

# Argon2id with pwdlib's recommended parameters
password_hasher = PasswordHash.recommended()

# Verified against when the email is unknown, so a missing user costs the same
# time as a wrong password and response timing cannot enumerate accounts.
DUMMY_HASH = password_hasher.hash("dummy-password-for-timing")

# ============================================================================
# Request/Response Models with Input Validation
# ============================================================================

class RegisterRequest(BaseModel):
    """User registration request with comprehensive validation."""
    
    email: EmailStr = Field(..., description="User email address")
    password: str = Field(
        ...,
        min_length=8,
        max_length=128,
        description="Password (8-128 characters, must contain uppercase, lowercase, digit, special char)"
    )
    first_name: str = Field(..., min_length=1, max_length=100)
    last_name: str = Field(..., min_length=1, max_length=100)
    
    model_config = ConfigDict(json_schema_extra={
        "example": {
            "email": "user@example.com",
            "password": "SecurePass123!",
            "first_name": "John",
            "last_name": "Doe"
        }
    })


class LoginRequest(BaseModel):
    """User login request."""
    
    email: EmailStr = Field(..., description="User email address")
    password: str = Field(..., description="User password")
    
    model_config = ConfigDict(json_schema_extra={
        "example": {
            "email": "user@example.com",
            "password": "SecurePass123!"
        }
    })


class TokenResponse(BaseModel):
    """JWT token response."""
    
    access_token: str = Field(..., description="JWT access token")
    token_type: str = Field(default="bearer", description="Token type")
    expires_in: int = Field(..., description="Token expiration time in seconds")
    
    model_config = ConfigDict(json_schema_extra={
        "example": {
            "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
            "token_type": "bearer",
            "expires_in": 3600
        }
    })


class UserResponse(BaseModel):
    """User response model (safe - no password)."""
    
    id: int
    email: str
    first_name: str
    last_name: str
    created_at: datetime
    
    model_config = ConfigDict(from_attributes=True, json_schema_extra={
        "example": {
            "id": 1,
            "email": "user@example.com",
            "first_name": "John",
            "last_name": "Doe",
            "created_at": "2025-05-20T10:30:00Z"
        }
    })


# ============================================================================
# Helper Functions
# ============================================================================

def hash_password(password: str) -> str:
    """Hash password with Argon2id."""
    return password_hasher.hash(password)


def verify_password(plain_password: str, hashed_password: str) -> bool:
    """Verify password against hash."""
    return password_hasher.verify(plain_password, hashed_password)


def create_access_token(
    data: dict,
    expires_delta: Optional[timedelta] = None
) -> tuple[str, int]:
    """
    Create JWT access token.
    
    Args:
        data: Claims to include in token
        expires_delta: Token expiration time (default: 1 hour)
    
    Returns:
        Tuple of (token, expires_in_seconds)
    
    Raises:
        ValueError: If secret key is not configured
    """
    if not settings.SECRET_KEY:
        raise ValueError("SECRET_KEY not configured")
    
    to_encode = data.copy()
    
    if expires_delta:
        expire = datetime.now(timezone.utc) + expires_delta
    else:
        expire = datetime.now(timezone.utc) + timedelta(hours=1)
    
    to_encode.update({"exp": expire})
    
    encoded_jwt = jwt.encode(
        to_encode,
        settings.SECRET_KEY,
        algorithm=settings.ALGORITHM
    )
    
    expires_in = int(expires_delta.total_seconds()) if expires_delta else 3600
    
    return encoded_jwt, expires_in


def get_user_by_email(db: Session, email: str) -> Optional[User]:
    """Get user from database by email."""
    return db.query(User).filter(User.email == email).first()


# ============================================================================
# Endpoints
# ============================================================================

@router.post(
    "/register",
    response_model=UserResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Register a new user",
    responses={
        201: {"description": "User registered successfully"},
        400: {"description": "Invalid input data"},
        409: {"description": "Email already registered"},
        500: {"description": "Internal server error"}
    }
)
def register(
    request: RegisterRequest,
    db: Session = Depends(get_db)
) -> UserResponse:
    """
    Register a new user account.
    
    - **email**: Must be a valid email address and unique
    - **password**: Must be 8+ characters with uppercase, lowercase, digit, and special character
    - **first_name**: Required, 1-100 characters
    - **last_name**: Required, 1-100 characters
    
    Returns: Created user object (without password)
    
    Raises:
        HTTPException 409: Email already registered
        HTTPException 400: Invalid input validation failed
        HTTPException 500: Database error
    """
    # Check if user already exists
    existing_user = get_user_by_email(db, request.email)
    if existing_user:
        raise HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail=f"Email '{request.email}' is already registered",
            headers={"X-Error-Code": "EMAIL_EXISTS"}
        )
    
    # Validate password strength
    if not _is_strong_password(request.password):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Password must contain uppercase, lowercase, digit, and special character",
            headers={"X-Error-Code": "WEAK_PASSWORD"}
        )
    
    # Create new user
    hashed_password = hash_password(request.password)
    new_user = User(
        email=request.email,
        password_hash=hashed_password,
        first_name=request.first_name,
        last_name=request.last_name,
        created_at=datetime.now(timezone.utc)
    )
    
    try:
        db.add(new_user)
        db.commit()
        db.refresh(new_user)
    except Exception as e:
        db.rollback()
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to create user account",
            headers={"X-Error-Code": "DB_ERROR"}
        ) from e
    
    return UserResponse.model_validate(new_user)


@router.post(
    "/login",
    response_model=TokenResponse,
    status_code=status.HTTP_200_OK,
    summary="User login",
    responses={
        200: {"description": "Login successful, token returned"},
        401: {"description": "Invalid credentials"},
        400: {"description": "Invalid input"},
        500: {"description": "Internal server error"}
    }
)
def login(
    request: LoginRequest,
    db: Session = Depends(get_db)
) -> TokenResponse:
    """
    Authenticate user and return JWT access token.
    
    - **email**: User email address
    - **password**: User password
    
    Returns: JWT access token valid for 1 hour
    
    Raises:
        HTTPException 401: Invalid email or password
        HTTPException 400: Invalid input data
        HTTPException 500: Database or token generation error
    """
    # Always run one hash verification, found or not, so timing does not
    # reveal whether the email is registered.
    user = get_user_by_email(db, request.email)
    password_ok = verify_password(
        request.password, user.password_hash if user else DUMMY_HASH
    )
    if user is None or not password_ok:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid email or password",
            headers={"X-Error-Code": "INVALID_CREDENTIALS", "WWW-Authenticate": "Bearer"}
        )
    
    # Create JWT token
    try:
        token_data = {
            "sub": str(user.id),
            "email": user.email,
            "iat": datetime.now(timezone.utc)
        }
        access_token, expires_in = create_access_token(token_data)
    except ValueError as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="Failed to generate authentication token",
            headers={"X-Error-Code": "TOKEN_ERROR"}
        ) from e
    
    return TokenResponse(
        access_token=access_token,
        token_type="bearer",
        expires_in=expires_in
    )


# ============================================================================
# Helper Functions (continued)
# ============================================================================

def _is_strong_password(password: str) -> bool:
    """
    Validate password strength.
    
    Requirements:
    - Minimum 8 characters
    - At least one uppercase letter
    - At least one lowercase letter
    - At least one digit
    - At least one special character
    
    Args:
        password: Password to validate
    
    Returns:
        True if password meets all requirements
    """
    import re
    
    if len(password) < 8:
        return False
    if not re.search(r"[A-Z]", password):
        return False
    if not re.search(r"[a-z]", password):
        return False
    if not re.search(r"\d", password):
        return False
    if not re.search(r"[!@#$%^&*()_+\-=\[\]{};:,.<>?]", password):
        return False
    
    return True
```

## Validation Checklist

### Endpoint Implementation
- [ ] All endpoints implemented with correct HTTP methods (GET, POST, PUT, DELETE, PATCH)
- [ ] Routes follow RESTful conventions: `/api/v1/{resource}` format
- [ ] Query parameters extracted and validated
- [ ] Path parameters validated and type-checked
- [ ] Response serialization models defined (Pydantic/DTO)

### Input Validation
- [ ] Request models use Pydantic BaseModel (Python) or Bean Validation (Java)
- [ ] Field constraints defined: min/max length, regex patterns, required fields
- [ ] Email validation using EmailStr or custom validator
- [ ] Password validation enforces strength requirements (8+ chars, uppercase, lowercase, digit, special)
- [ ] Numeric ranges validated (positive, non-zero where applicable)
- [ ] Enum constraints for categorical fields
- [ ] Custom validators implemented for complex business rules

### HTTP Status Codes
- [ ] `200 OK` for successful GET, PUT, PATCH requests
- [ ] `201 Created` for successful POST requests (create)
- [ ] `204 No Content` for successful DELETE requests
- [ ] `400 Bad Request` for invalid input (validation errors)
- [ ] `401 Unauthorized` for missing/invalid authentication
- [ ] `403 Forbidden` for insufficient permissions
- [ ] `404 Not Found` for missing resources
- [ ] `409 Conflict` for duplicate resources (email already registered)
- [ ] `500 Internal Server Error` for unexpected server errors

### JWT Token Handling
- [ ] Token generation with proper claims (sub, email, iat, exp)
- [ ] Token expiration set (1 hour standard)
- [ ] Token signature verification on protected routes
- [ ] Refresh token mechanism (optional but recommended)
- [ ] Token rotation on sensitive operations
- [ ] Secure Secret key storage (environment variable, never hardcoded)

### Password Security
- [ ] Password hashing with Argon2id or bcrypt (pwdlib in Python, Spring Security `PasswordEncoder` in Java)
- [ ] Password never stored in plain text
- [ ] Password never logged or returned in API responses
- [ ] Hashing uses appropriate work factors (pwdlib `recommended()` for Argon2id; bcrypt cost 12+)
- [ ] Password verification uses constant-time comparison

### Configuration & Secrets
- [ ] SECRET_KEY stored in environment variables, not in code
- [ ] Database credentials in environment variables
- [ ] JWT algorithm configured (HS256, RS256, etc.)
- [ ] CORS settings configured for frontend access
- [ ] Rate limiting configured for authentication endpoints

### Code Conventions (from python_advanced_skill/java_advanced_skill)
- [ ] Type hints on all function parameters and return types (Python)
- [ ] Docstrings on all public functions (Python) or JavaDoc (Java)
- [ ] Meaningful variable names (no single letters except loop counters)
- [ ] Functions ≤ 20 lines (single responsibility)
- [ ] Classes ≤ 300 lines (separation of concerns)
- [ ] DRY principle: no code duplication
- [ ] Proper exception handling with custom exceptions

### Error Handling
- [ ] All endpoints have try-catch (Python) or try-except (Java) blocks
- [ ] HTTPException used with meaningful messages and error codes
- [ ] Validation errors return 400 with field-level details
- [ ] Authentication errors return 401 with WWW-Authenticate header
- [ ] Duplicate resource errors return 409 with conflict explanation
- [ ] No sensitive data in error messages (e.g., "User not found" instead of database query)
- [ ] Database errors caught and translated to 500 with generic message

## Success Criteria

### Test Coverage
- [ ] **Unit tests**: 80%+ code coverage for service layer
- [ ] **Integration tests**: All API endpoints tested end-to-end
- [ ] **Authentication tests**: JWT validation, token expiration, invalid credentials
- [ ] **Validation tests**: All field validators tested with valid/invalid inputs
- [ ] **Error tests**: All error scenarios return correct status codes
- [ ] **Test naming**: Follow `test_givenXxx_whenYyy_thenZzz()` pattern
- [ ] **Test structure**: Arrange-Act-Assert (AAA) pattern used

### JWT Token Validation
- [ ] Tokens issued with correct claims and expiration
- [ ] Protected endpoints verify token presence and validity
- [ ] Expired tokens rejected with 401
- [ ] Invalid signatures rejected with 401
- [ ] Token claims (sub, email) validated for authorization decisions

### Error Handling Validation
- [ ] All error scenarios tested: validation failure, duplicate, not found, unauthorized
- [ ] Error responses include consistent format: `{"detail": "message", "code": "ERROR_CODE"}`
- [ ] Proper HTTP status codes returned (400, 401, 403, 404, 409, 500)
- [ ] No stack traces or database details exposed in error messages
- [ ] Sensitive operations (login failures) return generic "Invalid credentials"

### Security Validation
- [ ] Passwords hashed with Argon2id or bcrypt (never plaintext)
- [ ] Password strength enforced (8+ chars, mixed case, digit, special char)
- [ ] No sensitive data in logs (no passwords, tokens, API keys)
- [ ] HTTPS required for all endpoints (configured in deployment)
- [ ] CORS properly configured to prevent cross-origin abuse

### Code Quality Validation
- [ ] All functions ≤ 20 lines, all classes ≤ 300 lines
- [ ] Type hints on all function signatures
- [ ] Docstrings on all public functions
- [ ] No code duplication (DRY principle)
- [ ] Meaningful variable names throughout
- [ ] Proper separation of concerns (routes, services, models)

## Internal Calls

This skill directly leverages:

### From `python_advanced_skill`
- **Type hints**: Use on all function parameters and returns (Python FastAPI implementation)
- **Docstring standards**: Comprehensive docstrings on all public functions
- **Exception handling**: Custom exceptions and proper error propagation
- **Code organization**: Service layer pattern with separation of concerns
- **Testing patterns**: Unit tests with AAA (Arrange-Act-Assert), meaningful test names
- **PEP 8 compliance**: Naming conventions, import organization, line lengths

### From `java_advanced_skill`
- **Spring Boot patterns**: Controller-Service-Repository architecture (Java implementation)
- **Bean validation**: @Valid, @NotNull, @Email, custom validators
- **Exception handling**: Custom exceptions extending RuntimeException, @ControllerAdvice
- **Transaction management**: @Transactional for database operations
- **Testing patterns**: Unit/integration tests with Mockito, meaningful test names
- **JavaDoc standards**: Comprehensive JavaDoc on all public classes/methods

## Related Skills

- `code_health_skill.md` - Code quality, error handling, performance patterns
- `error_handling_skill.md` - Comprehensive error handling strategies
- `python_advanced_skill.md` - Python coding standards and patterns
- `java_advanced_skill.md` - Java coding standards and patterns
- `documentation_skill.md` - API documentation and examples
- `logger_skill.md` - Logging standards and practices

## Version History

### v1.0 (2025-05-20)
- Initial release
- FastAPI authentication endpoints (register, login)
- JWT token generation and validation
- Input validation with Pydantic
- Password hashing with Argon2id (pwdlib) or bcrypt
- Comprehensive error handling
- Full validation checklist and success criteria

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…