Smithery Logo
MCPsSkillsDocsPricing
Login
Smithery Logo

Accelerating the Agent Economy

Resources

DocumentationPrivacy PolicySystem Status

Company

PricingAboutBlog

Connect

© 2026 Smithery. All rights reserved.

    alinaqi

    nodejs-backend

    alinaqi/nodejs-backend
    Coding
    467
    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

    Node.js backend patterns with Express/Fastify, repositories

    SKILL.md

    Node.js Backend Skill


    Project Structure

    project/
    ├── src/
    │   ├── core/                   # Pure business logic
    │   │   ├── types.ts            # Domain types
    │   │   ├── errors.ts           # Domain errors
    │   │   └── services/           # Pure functions
    │   │       ├── user.ts
    │   │       └── order.ts
    │   ├── infra/                  # Side effects
    │   │   ├── http/               # HTTP layer
    │   │   │   ├── server.ts       # Server setup
    │   │   │   ├── routes/         # Route handlers
    │   │   │   └── middleware/     # Express middleware
    │   │   ├── db/                 # Database
    │   │   │   ├── client.ts       # DB connection
    │   │   │   ├── repositories/   # Data access
    │   │   │   └── migrations/     # Schema migrations
    │   │   └── external/           # Third-party APIs
    │   ├── config/                 # Configuration
    │   │   └── index.ts            # Env vars, validated
    │   └── index.ts                # Entry point
    ├── tests/
    │   ├── unit/
    │   └── integration/
    ├── package.json
    └── CLAUDE.md
    

    API Design

    Route Handler Pattern

    // routes/users.ts
    import { Router } from 'express';
    import { z } from 'zod';
    import { createUser } from '../../core/services/user';
    import { UserRepository } from '../db/repositories/user';
    
    const CreateUserSchema = z.object({
      email: z.string().email(),
      name: z.string().min(1).max(100),
    });
    
    export function createUserRoutes(userRepo: UserRepository): Router {
      const router = Router();
    
      router.post('/', async (req, res, next) => {
        try {
          const input = CreateUserSchema.parse(req.body);
          const user = await createUser(input, userRepo);
          res.status(201).json(user);
        } catch (error) {
          next(error);
        }
      });
    
      return router;
    }
    

    Dependency Injection at Composition Root

    // index.ts
    import { createApp } from './infra/http/server';
    import { createDbClient } from './infra/db/client';
    import { UserRepository } from './infra/db/repositories/user';
    import { createUserRoutes } from './infra/http/routes/users';
    
    async function main(): Promise<void> {
      const db = await createDbClient();
      const userRepo = new UserRepository(db);
      
      const app = createApp({
        userRoutes: createUserRoutes(userRepo),
      });
      
      app.listen(3000);
    }
    

    Error Handling

    Domain Errors

    // core/errors.ts
    export class DomainError extends Error {
      constructor(
        message: string,
        public readonly code: string,
        public readonly statusCode: number = 400
      ) {
        super(message);
        this.name = 'DomainError';
      }
    }
    
    export class NotFoundError extends DomainError {
      constructor(resource: string, id: string) {
        super(`${resource} with id ${id} not found`, 'NOT_FOUND', 404);
      }
    }
    
    export class ValidationError extends DomainError {
      constructor(message: string) {
        super(message, 'VALIDATION_ERROR', 400);
      }
    }
    

    Global Error Handler

    // middleware/errorHandler.ts
    import { ErrorRequestHandler } from 'express';
    import { DomainError } from '../../core/errors';
    import { ZodError } from 'zod';
    
    export const errorHandler: ErrorRequestHandler = (err, req, res, next) => {
      if (err instanceof DomainError) {
        return res.status(err.statusCode).json({
          error: { code: err.code, message: err.message },
        });
      }
    
      if (err instanceof ZodError) {
        return res.status(400).json({
          error: { code: 'VALIDATION_ERROR', details: err.errors },
        });
      }
    
      console.error('Unexpected error:', err);
      return res.status(500).json({
        error: { code: 'INTERNAL_ERROR', message: 'Something went wrong' },
      });
    };
    

    Database Patterns

    Repository Pattern

    // db/repositories/user.ts
    import { Kysely } from 'kysely';
    import { Database, User } from '../types';
    
    export class UserRepository {
      constructor(private db: Kysely<Database>) {}
    
      async findById(id: string): Promise<User | null> {
        return this.db
          .selectFrom('users')
          .where('id', '=', id)
          .selectAll()
          .executeTakeFirst() ?? null;
      }
    
      async create(data: Omit<User, 'id' | 'createdAt'>): Promise<User> {
        return this.db
          .insertInto('users')
          .values(data)
          .returningAll()
          .executeTakeFirstOrThrow();
      }
    }
    

    Transactions

    async function transferFunds(
      fromId: string,
      toId: string,
      amount: number,
      db: Kysely<Database>
    ): Promise<void> {
      await db.transaction().execute(async (trx) => {
        await trx
          .updateTable('accounts')
          .set((eb) => ({ balance: eb('balance', '-', amount) }))
          .where('id', '=', fromId)
          .execute();
    
        await trx
          .updateTable('accounts')
          .set((eb) => ({ balance: eb('balance', '+', amount) }))
          .where('id', '=', toId)
          .execute();
      });
    }
    

    Configuration

    Validated Config

    // config/index.ts
    import { z } from 'zod';
    
    const ConfigSchema = z.object({
      NODE_ENV: z.enum(['development', 'production', 'test']),
      PORT: z.coerce.number().default(3000),
      DATABASE_URL: z.string().url(),
      API_KEY: z.string().min(1),
    });
    
    export type Config = z.infer<typeof ConfigSchema>;
    
    export function loadConfig(): Config {
      return ConfigSchema.parse(process.env);
    }
    

    Testing

    Unit Tests (Core)

    // tests/unit/services/user.test.ts
    import { createUser } from '../../../src/core/services/user';
    
    describe('createUser', () => {
      it('creates user with valid data', async () => {
        const mockRepo = {
          create: jest.fn().mockResolvedValue({ id: '1', email: 'test@example.com' }),
          findByEmail: jest.fn().mockResolvedValue(null),
        };
    
        const result = await createUser({ email: 'test@example.com', name: 'Test' }, mockRepo);
    
        expect(result.email).toBe('test@example.com');
        expect(mockRepo.create).toHaveBeenCalledTimes(1);
      });
    });
    

    Integration Tests (API)

    // tests/integration/users.test.ts
    import request from 'supertest';
    import { createTestApp, createTestDb } from '../helpers';
    
    describe('POST /users', () => {
      let app: Express;
      let db: TestDb;
    
      beforeAll(async () => {
        db = await createTestDb();
        app = createTestApp(db);
      });
    
      afterAll(async () => {
        await db.destroy();
      });
    
      it('creates user and returns 201', async () => {
        const response = await request(app)
          .post('/users')
          .send({ email: 'new@example.com', name: 'New User' });
    
        expect(response.status).toBe(201);
        expect(response.body.email).toBe('new@example.com');
      });
    });
    

    Node.js Anti-Patterns

    • ❌ Callback hell - use async/await
    • ❌ Unhandled promise rejections - always catch or let error handler catch
    • ❌ Blocking the event loop - offload heavy computation
    • ❌ Secrets in code - use environment variables
    • ❌ SQL string concatenation - use parameterized queries
    • ❌ No input validation - validate at API boundary
    • ❌ Console.log in production - use proper logger
    • ❌ No graceful shutdown - handle SIGTERM
    • ❌ Monolithic route files - split by resource
    Recommended Servers
    Vercel Grep
    Vercel Grep
    Supabase
    Supabase
    InstantDB
    InstantDB
    Repository
    alinaqi/claude-bootstrap
    Files