Smithery Logo
MCPsSkillsDocsPricing
Login
Smithery Logo

Accelerating the Agent Economy

Resources

DocumentationPrivacy PolicySystem Status

Company

PricingAboutBlog

Connect

© 2026 Smithery. All rights reserved.

    primadetaautomation

    backend-development-patterns

    primadetaautomation/backend-development-patterns
    Coding
    5
    1 installs

    About

    SKILL.md

    Install

    Install via Skills CLI

    or add to your agent
    • Claude Code
      Claude Code
    • Codex
      Codex
    • OpenClaw
      OpenClaw
    • Cursor
      Cursor
    • Amp
      Amp
    • GitHub Copilot
      GitHub Copilot
    • Gemini CLI
      Gemini CLI
    • Kilo Code
      Kilo Code
    • Junie
      Junie
    • Replit
      Replit
    • Windsurf
      Windsurf
    • Cline
      Cline
    • Continue
      Continue
    • OpenCode
      OpenCode
    • OpenHands
      OpenHands
    • Roo Code
      Roo Code
    • Augment
      Augment
    • Goose
      Goose
    • Trae
      Trae
    • Zencoder
      Zencoder
    • Antigravity
      Antigravity
    ├─
    ├─
    └─

    About

    API design, database patterns, REST/GraphQL, microservices architecture, and backend best practices

    SKILL.md

    Backend Development Patterns Skill

    Overview

    This skill provides comprehensive backend development patterns including API design, database architecture, authentication, and scalable backend systems.

    When to Use This Skill

    • Designing and implementing REST/GraphQL APIs
    • Database schema design and optimization
    • Backend service architecture
    • Microservices patterns
    • Data layer implementation

    Core API Design Principles (Level 1 - Always Loaded)

    REST API Best Practices

    URL Structure:

    ✅ GOOD - Resource-oriented URLs
    GET    /api/users           # List users
    GET    /api/users/:id       # Get specific user
    POST   /api/users           # Create user
    PUT    /api/users/:id       # Update user (full replace)
    PATCH  /api/users/:id       # Update user (partial)
    DELETE /api/users/:id       # Delete user
    
    # Nested resources
    GET    /api/users/:id/orders      # Get user's orders
    POST   /api/users/:id/orders      # Create order for user
    
    ❌ BAD - Verb-based URLs
    GET    /api/getUser?id=123
    POST   /api/createUser
    POST   /api/updateUser
    POST   /api/deleteUser
    

    HTTP Status Codes:

    // Success responses
    200 OK              // Successful GET, PUT, PATCH, DELETE
    201 Created         // Successful POST
    204 No Content      // Successful DELETE (no response body)
    
    // Client errors
    400 Bad Request     // Invalid input data
    401 Unauthorized    // Missing or invalid authentication
    403 Forbidden       // Valid auth but insufficient permissions
    404 Not Found       // Resource doesn't exist
    409 Conflict        // Resource conflict (e.g., duplicate email)
    422 Unprocessable   // Validation errors
    
    // Server errors
    500 Internal Error  // Unexpected server error
    503 Service Unavail // Temporary unavailability
    
    // Example usage
    app.post('/api/users', async (req, res) => {
      try {
        const user = await userService.create(req.body);
        res.status(201).json(user); // 201 Created
      } catch (error) {
        if (error instanceof ValidationError) {
          res.status(422).json({ error: error.message }); // 422 Validation
        } else if (error instanceof ConflictError) {
          res.status(409).json({ error: error.message }); // 409 Conflict
        } else {
          res.status(500).json({ error: 'Internal server error' }); // 500
        }
      }
    });
    

    Request/Response Format:

    // ✅ GOOD - Consistent response structure
    interface ApiResponse<T> {
      success: boolean;
      data?: T;
      error?: {
        code: string;
        message: string;
        details?: any;
      };
      meta?: {
        timestamp: string;
        requestId: string;
      };
    }
    
    // Success response
    {
      "success": true,
      "data": {
        "id": "123",
        "email": "user@example.com",
        "name": "John Doe"
      },
      "meta": {
        "timestamp": "2025-01-15T10:30:00Z",
        "requestId": "req_abc123"
      }
    }
    
    // Error response
    {
      "success": false,
      "error": {
        "code": "VALIDATION_ERROR",
        "message": "Invalid email format",
        "details": {
          "field": "email",
          "value": "invalid-email"
        }
      },
      "meta": {
        "timestamp": "2025-01-15T10:30:00Z",
        "requestId": "req_abc123"
      }
    }
    

    Database Design Patterns

    Schema Design Best Practices:

    -- ✅ GOOD - Proper constraints and indexes
    
    CREATE TABLE users (
      id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
      email VARCHAR(255) NOT NULL UNIQUE,
      name VARCHAR(100) NOT NULL,
      password_hash VARCHAR(255) NOT NULL,
      created_at TIMESTAMP NOT NULL DEFAULT NOW(),
      updated_at TIMESTAMP NOT NULL DEFAULT NOW()
    );
    
    -- Index frequently queried fields
    CREATE INDEX idx_users_email ON users(email);
    CREATE INDEX idx_users_created_at ON users(created_at);
    
    -- Foreign key relationships
    CREATE TABLE orders (
      id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
      user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
      total DECIMAL(10, 2) NOT NULL CHECK (total >= 0),
      status VARCHAR(50) NOT NULL DEFAULT 'pending',
      created_at TIMESTAMP NOT NULL DEFAULT NOW(),
      updated_at TIMESTAMP NOT NULL DEFAULT NOW()
    );
    
    CREATE INDEX idx_orders_user_id ON orders(user_id);
    CREATE INDEX idx_orders_status ON orders(status);
    
    -- ❌ BAD - No constraints, poor naming
    CREATE TABLE user_table (
      id INT,
      mail VARCHAR(1000),
      data TEXT
    );
    

    Query Optimization:

    // ✅ GOOD - Efficient query with specific fields
    async function getUserOrders(userId: string) {
      return db.query(`
        SELECT
          o.id,
          o.total,
          o.status,
          o.created_at
        FROM orders o
        WHERE o.user_id = $1
        ORDER BY o.created_at DESC
        LIMIT 20
      `, [userId]);
    }
    
    // ❌ BAD - SELECT * and no limit
    async function getUserOrders(userId: string) {
      return db.query(`
        SELECT * FROM orders WHERE user_id = $1
      `, [userId]);
    }
    
    // ✅ GOOD - Avoid N+1 queries with JOIN
    async function getUsersWithOrders() {
      const result = await db.query(`
        SELECT
          u.id as user_id,
          u.name,
          u.email,
          json_agg(
            json_build_object(
              'id', o.id,
              'total', o.total,
              'status', o.status
            )
          ) as orders
        FROM users u
        LEFT JOIN orders o ON u.id = o.user_id
        GROUP BY u.id, u.name, u.email
      `);
    
      return result.rows;
    }
    

    Repository Pattern

    // Generic repository interface
    interface Repository<T> {
      findById(id: string): Promise<T | null>;
      findAll(options?: FindOptions): Promise<T[]>;
      create(data: Partial<T>): Promise<T>;
      update(id: string, data: Partial<T>): Promise<T>;
      delete(id: string): Promise<boolean>;
    }
    
    // Implementation for User entity
    class UserRepository implements Repository<User> {
      constructor(private db: Database) {}
    
      async findById(id: string): Promise<User | null> {
        const result = await this.db.query(
          'SELECT * FROM users WHERE id = $1',
          [id]
        );
        return result.rows[0] ? this.mapToUser(result.rows[0]) : null;
      }
    
      async findByEmail(email: string): Promise<User | null> {
        const result = await this.db.query(
          'SELECT * FROM users WHERE email = $1',
          [email]
        );
        return result.rows[0] ? this.mapToUser(result.rows[0]) : null;
      }
    
      async create(data: CreateUserDto): Promise<User> {
        const result = await this.db.query(
          `INSERT INTO users (email, name, password_hash)
           VALUES ($1, $2, $3)
           RETURNING *`,
          [data.email, data.name, data.passwordHash]
        );
        return this.mapToUser(result.rows[0]);
      }
    
      async update(id: string, data: Partial<User>): Promise<User> {
        const updates: string[] = [];
        const values: any[] = [];
        let paramCount = 1;
    
        Object.entries(data).forEach(([key, value]) => {
          updates.push(`${key} = $${paramCount}`);
          values.push(value);
          paramCount++;
        });
    
        values.push(id);
    
        const result = await this.db.query(
          `UPDATE users
           SET ${updates.join(', ')}, updated_at = NOW()
           WHERE id = $${paramCount}
           RETURNING *`,
          values
        );
    
        return this.mapToUser(result.rows[0]);
      }
    
      private mapToUser(row: any): User {
        return {
          id: row.id,
          email: row.email,
          name: row.name,
          createdAt: row.created_at,
          updatedAt: row.updated_at,
        };
      }
    }
    

    Service Layer Pattern

    // Business logic layer
    class UserService {
      constructor(
        private userRepo: UserRepository,
        private emailService: EmailService,
        private cacheService: CacheService,
        private logger: Logger
      ) {}
    
      async createUser(dto: CreateUserDto): Promise<User> {
        // 1. Validate input
        this.validateUserDto(dto);
    
        // 2. Check for duplicates
        const existing = await this.userRepo.findByEmail(dto.email);
        if (existing) {
          throw new ConflictError('Email already registered');
        }
    
        // 3. Hash password
        const passwordHash = await bcrypt.hash(dto.password, 12);
    
        // 4. Create user
        const user = await this.userRepo.create({
          email: dto.email,
          name: dto.name,
          passwordHash,
        });
    
        // 5. Send welcome email (async, don't block)
        this.emailService.sendWelcomeEmail(user.email)
          .catch(err => this.logger.error('Failed to send welcome email', err));
    
        // 6. Invalidate cache
        await this.cacheService.delete(`users:all`);
    
        // 7. Log event
        this.logger.info('User created', { userId: user.id });
    
        return user;
      }
    
      async getUserById(id: string): Promise<User> {
        // Try cache first
        const cacheKey = `user:${id}`;
        const cached = await this.cacheService.get<User>(cacheKey);
    
        if (cached) {
          return cached;
        }
    
        // Fetch from database
        const user = await this.userRepo.findById(id);
    
        if (!user) {
          throw new NotFoundError('User not found');
        }
    
        // Cache for 5 minutes
        await this.cacheService.set(cacheKey, user, 300);
    
        return user;
      }
    
      private validateUserDto(dto: CreateUserDto): void {
        if (!validator.isEmail(dto.email)) {
          throw new ValidationError('Invalid email format');
        }
    
        if (dto.password.length < 8) {
          throw new ValidationError('Password must be at least 8 characters');
        }
    
        if (dto.name.trim().length < 2) {
          throw new ValidationError('Name must be at least 2 characters');
        }
      }
    }
    

    Authentication & Authorization

    JWT Authentication

    import jwt from 'jsonwebtoken';
    
    interface JwtPayload {
      userId: string;
      email: string;
      role: string;
    }
    
    class AuthService {
      private readonly JWT_SECRET = process.env.JWT_SECRET!;
      private readonly JWT_EXPIRES_IN = '1h';
      private readonly REFRESH_TOKEN_EXPIRES_IN = '7d';
    
      generateAccessToken(user: User): string {
        const payload: JwtPayload = {
          userId: user.id,
          email: user.email,
          role: user.role,
        };
    
        return jwt.sign(payload, this.JWT_SECRET, {
          expiresIn: this.JWT_EXPIRES_IN,
          algorithm: 'HS256',
        });
      }
    
      generateRefreshToken(user: User): string {
        return jwt.sign(
          { userId: user.id },
          this.JWT_SECRET,
          { expiresIn: this.REFRESH_TOKEN_EXPIRES_IN }
        );
      }
    
      verifyToken(token: string): JwtPayload {
        try {
          return jwt.verify(token, this.JWT_SECRET) as JwtPayload;
        } catch (error) {
          throw new UnauthorizedError('Invalid or expired token');
        }
      }
    }
    
    // Middleware
    function authenticateJWT(req: Request, res: Response, next: NextFunction) {
      const authHeader = req.headers.authorization;
    
      if (!authHeader?.startsWith('Bearer ')) {
        return res.status(401).json({ error: 'Missing authentication token' });
      }
    
      const token = authHeader.substring(7);
    
      try {
        const payload = authService.verifyToken(token);
        req.user = payload;
        next();
      } catch (error) {
        return res.status(401).json({ error: 'Invalid token' });
      }
    }
    
    // Authorization middleware
    function requireRole(...roles: string[]) {
      return (req: Request, res: Response, next: NextFunction) => {
        if (!req.user) {
          return res.status(401).json({ error: 'Unauthorized' });
        }
    
        if (!roles.includes(req.user.role)) {
          return res.status(403).json({ error: 'Insufficient permissions' });
        }
    
        next();
      };
    }
    
    // Usage
    app.get('/api/admin/users', authenticateJWT, requireRole('admin'), async (req, res) => {
      // Only authenticated admins can access
      const users = await userService.getAllUsers();
      res.json(users);
    });
    

    API Versioning

    // URL-based versioning
    app.use('/api/v1', v1Routes);
    app.use('/api/v2', v2Routes);
    
    // v1 route (old)
    v1Router.get('/users/:id', async (req, res) => {
      const user = await userService.getUser(req.params.id);
      res.json(user); // Old response format
    });
    
    // v2 route (new - includes additional fields)
    v2Router.get('/users/:id', async (req, res) => {
      const user = await userService.getUser(req.params.id);
      const enriched = await userService.enrichUserData(user);
      res.json(enriched); // New response format with more data
    });
    

    Pagination & Filtering

    // Query parameters for pagination
    interface PaginationParams {
      page: number;
      limit: number;
      sortBy?: string;
      sortOrder?: 'asc' | 'desc';
      filters?: Record<string, any>;
    }
    
    async function getUsers(params: PaginationParams) {
      const { page = 1, limit = 20, sortBy = 'created_at', sortOrder = 'desc' } = params;
    
      const offset = (page - 1) * limit;
    
      const result = await db.query(`
        SELECT * FROM users
        WHERE email LIKE $1
        ORDER BY ${sortBy} ${sortOrder}
        LIMIT $2 OFFSET $3
      `, [`%${params.filters?.email || ''}%`, limit, offset]);
    
      const countResult = await db.query('SELECT COUNT(*) FROM users');
      const total = parseInt(countResult.rows[0].count);
    
      return {
        data: result.rows,
        pagination: {
          page,
          limit,
          total,
          totalPages: Math.ceil(total / limit),
          hasNext: page * limit < total,
          hasPrev: page > 1,
        },
      };
    }
    
    // API endpoint
    app.get('/api/users', async (req, res) => {
      const result = await getUsers({
        page: parseInt(req.query.page as string) || 1,
        limit: parseInt(req.query.limit as string) || 20,
        sortBy: req.query.sortBy as string,
        sortOrder: req.query.sortOrder as 'asc' | 'desc',
        filters: req.query.filters as any,
      });
    
      res.json(result);
    });
    

    Rate Limiting

    import rateLimit from 'express-rate-limit';
    
    // Global rate limit
    const limiter = rateLimit({
      windowMs: 15 * 60 * 1000, // 15 minutes
      max: 100, // 100 requests per window
      message: 'Too many requests, please try again later',
      standardHeaders: true,
      legacyHeaders: false,
    });
    
    app.use('/api/', limiter);
    
    // Strict limit for authentication endpoints
    const authLimiter = rateLimit({
      windowMs: 15 * 60 * 1000,
      max: 5, // Only 5 login attempts per 15 minutes
      skipSuccessfulRequests: true,
    });
    
    app.post('/api/auth/login', authLimiter, loginHandler);
    

    Detailed Patterns (Level 2 - Load on Request)

    See companion files:

    • graphql-patterns.md - GraphQL schema design and resolvers
    • microservices-patterns.md - Service communication and orchestration
    • caching-strategies.md - Redis patterns and cache invalidation

    Code Examples (Level 3 - Load When Needed)

    See examples directory:

    • examples/rest-api-complete.ts - Full REST API implementation
    • examples/graphql-server.ts - Complete GraphQL setup
    • examples/auth-flow-complete.ts - Authentication implementation

    Integration with Agents

    senior-fullstack-developer:

    • Primary agent for backend implementation
    • Uses these patterns for all API development
    • References for database design

    database-migration-specialist:

    • Uses database patterns for schema design
    • References optimization patterns

    solutions-architect:

    • Uses these patterns for system design
    • Evaluates architecture decisions

    Version 1.0.0 | REST & GraphQL Ready | Scalable Patterns

    Recommended Servers
    Vercel Grep
    Vercel Grep
    Supabase
    Supabase
    InstantDB
    InstantDB
    Repository
    primadetaautomation/primadata-marketplace
    Files