home / skills / doanchienthangdev / omgkit / express

This skill helps you build production Express.js APIs with TypeScript, middleware patterns, authentication, and robust error handling.

npx playbooks add skill doanchienthangdev/omgkit --skill express

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
4.1 KB
---
name: building-express-apis
description: Builds production Express.js APIs with TypeScript, middleware patterns, authentication, and error handling. Use when creating Node.js backends, REST APIs, or Express applications.
---

# Express.js

## Quick Start

```typescript
import express from 'express';
import cors from 'cors';
import helmet from 'helmet';

const app = express();

app.use(helmet());
app.use(cors());
app.use(express.json());

app.get('/api/health', (req, res) => {
  res.json({ status: 'ok' });
});

app.listen(3000);
```

## Features

| Feature | Description | Guide |
|---------|-------------|-------|
| Project Setup | TypeScript config, middleware stack | [SETUP.md](SETUP.md) |
| Routing | Controllers, validation, async handlers | [ROUTING.md](ROUTING.md) |
| Middleware | Auth, validation, error handling | [MIDDLEWARE.md](MIDDLEWARE.md) |
| Database | Prisma/TypeORM integration | [DATABASE.md](DATABASE.md) |
| Testing | Jest, supertest patterns | [TESTING.md](TESTING.md) |
| Deployment | Docker, PM2, production config | [DEPLOYMENT.md](DEPLOYMENT.md) |

## Common Patterns

### Controller Pattern

```typescript
// controllers/users.ts
import { Request, Response, NextFunction } from 'express';
import { UserService } from '../services/UserService';

export class UserController {
  constructor(private userService: UserService) {}

  getAll = async (req: Request, res: Response, next: NextFunction) => {
    try {
      const users = await this.userService.findAll();
      res.json(users);
    } catch (error) {
      next(error);
    }
  };

  getById = async (req: Request, res: Response, next: NextFunction) => {
    try {
      const user = await this.userService.findById(req.params.id);
      if (!user) return res.status(404).json({ error: 'Not found' });
      res.json(user);
    } catch (error) {
      next(error);
    }
  };
}
```

### Error Handler

```typescript
// middleware/errorHandler.ts
import { Request, Response, NextFunction } from 'express';

export class AppError extends Error {
  constructor(
    public statusCode: number,
    message: string,
    public isOperational = true
  ) {
    super(message);
  }
}

export function errorHandler(
  err: Error,
  req: Request,
  res: Response,
  next: NextFunction
) {
  if (err instanceof AppError) {
    return res.status(err.statusCode).json({ error: err.message });
  }

  console.error(err);
  res.status(500).json({ error: 'Internal server error' });
}
```

### Validation Middleware

```typescript
// middleware/validate.ts
import { Request, Response, NextFunction } from 'express';
import { ZodSchema } from 'zod';

export function validate(schema: ZodSchema) {
  return (req: Request, res: Response, next: NextFunction) => {
    const result = schema.safeParse({
      body: req.body,
      query: req.query,
      params: req.params,
    });

    if (!result.success) {
      return res.status(400).json({ errors: result.error.issues });
    }

    next();
  };
}
```

## Workflows

### API Development Workflow

1. Define routes in `routes/index.ts`
2. Create controller with business logic
3. Add validation schemas with Zod
4. Write tests with supertest
5. Document with OpenAPI/Swagger

### Middleware Order

```
1. Security (helmet, cors)
2. Rate limiting
3. Body parsing
4. Logging
5. Authentication
6. Routes
7. 404 handler
8. Error handler
```

## Best Practices

| Do | Avoid |
|----|-------|
| Use async/await with try-catch | Callback patterns |
| Validate all inputs | Trusting client data |
| Use typed request/response | `any` types |
| Centralize error handling | Scattered try-catch |
| Use dependency injection | Direct imports in controllers |

## Project Structure

```
src/
├── app.ts              # Express setup
├── server.ts           # Server entry
├── config/             # Environment config
├── controllers/        # Route handlers
├── middleware/         # Custom middleware
├── routes/             # Route definitions
├── services/           # Business logic
├── utils/              # Helpers
└── types/              # TypeScript types
```

For detailed examples and patterns, see reference files above.

Overview

This skill builds production-ready Express.js APIs using TypeScript, middleware patterns, authentication, validation, and structured error handling. It provides a tested project layout, common controller and middleware patterns, and deployment-ready practices to speed up Node.js backend development. Use it to create maintainable REST APIs with clear separation of concerns and strong typing.

How this skill works

The skill sets up an Express app with a secure middleware stack (helmet, cors, body parsing) and enforces middleware order including rate limiting, logging, authentication, routes, 404, and error handling. It provides controller patterns that use async/await and dependency injection, centralized AppError-based error handling, and a Zod-based validation middleware that validates body, query, and params. You get a recommended project structure, testing approach with Jest and supertest, and deployment guidance for Docker/PM2.

When to use it

  • Starting a new Node.js/Express backend with TypeScript
  • Building REST APIs that need input validation and typed responses
  • Standardizing middleware, authentication, and error handling across services
  • Preparing an API for production deployment with Docker or process managers
  • Writing testable controllers and integration tests with supertest

Best practices

  • Apply middleware in the recommended order: security, rate limiting, parsing, logging, auth, routes, 404, error handler
  • Use Zod schemas to validate body, query, and params and return structured 400 errors
  • Wrap controller logic in try/catch and forward errors to a centralized AppError handler
  • Prefer dependency injection for services to keep controllers testable and decoupled
  • Use typed request/response interfaces and avoid using any for safety

Example use cases

  • Quickly scaffold an authenticated REST API for a web app or SPA
  • Implement route-level validation and consistent error responses for public APIs
  • Add typed service layers and unit tests for business logic using Jest and supertest
  • Prepare an Express service for production with Dockerfile, PM2 configuration, and environment-driven config
  • Integrate Prisma or TypeORM with services while keeping controllers agnostic of database details

FAQ

How does validation work across body, query, and params?

Use the provided validate(schema) middleware which runs a Zod schema against body, query, and params together and returns 400 with issue details on failure.

How should I handle operational vs programming errors?

Throw AppError for known operational errors with statusCode; the centralized errorHandler responds with the provided status and message. Unhandled errors are logged and return 500 to avoid leaking internals.