home / skills / amnadtaowsoam / cerebraskills / express-rest

express-rest skill

/03-backend-api/express-rest

This skill helps you design robust Express.js REST APIs by applying middleware, routing, validation, and production-ready patterns.

npx playbooks add skill amnadtaowsoam/cerebraskills --skill express-rest

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

Files (1)
SKILL.md
6.7 KB
---
name: Express.js REST API Patterns
description: Comprehensive patterns for building REST APIs with Express.js including middleware, routing, validation, authentication, and production-ready configurations.
---

# Express.js REST API Patterns

## Overview

Express.js is a minimal and flexible Node.js web application framework for building REST APIs, featuring a powerful middleware system, flexible routing, and a large ecosystem.

Express.js consists of:
- **Minimal Core**: Minimal core with a powerful middleware system
- **Flexible Routing**: Flexible routing with route parameters
- **Middleware Stack**: Middleware stack for request/response processing
- **Error Handling**: Built-in error handling
- **Security**: Security middleware and best practices
- **Production-Ready**: Production-ready with clustering and graceful shutdown

## Why This Matters

- **Increase Development Velocity**: Express.js can increase development velocity by 30-50%
- **Reduce Time to Market**: Flexible framework helps reduce time to market
- **Improve Scalability**: Clustering and middleware improve scalability
- **Reduce Maintenance Cost**: Well-structured code reduces maintenance cost
- **Enhance Performance**: Optimized middleware enhances performance

---

## Core Concepts

### 1. Application Setup

```typescript
import express, { Application } from "express"

export function createApp(): Application {
  const app = express()

  // Middleware
  app.use(express.json())

  // Routes
  app.use("/api", routes)

  return app
}
```

### 2. Middleware Pattern

**Middleware Order is Critical:**
1. Security headers (Helmet)
2. CORS
3. Request logging (Morgan)
4. Body parsing
5. Request ID
6. Rate limiting
7. Authentication
8. Routes
9. Error handler (must be last)

```typescript
export function createApp(): Application {
  const app = express()

  // 1. Security headers (first)
  app.use(helmet())

  // 2. CORS
  app.use(cors())

  // 3. Request logging
  app.use(morgan("combined"))

  // 4. Body parsing
  app.use(express.json())
  app.use(express.urlencoded({ extended: true }))

  // 5. Custom middleware
  app.use(requestIdMiddleware)
  app.use(loggingMiddleware)

  // 6. Authentication (before routes)
  app.use(authMiddleware)

  // 7. Routes
  app.use("/api", routes)

  // 8. Error handling (last)
  app.use(errorHandler)

  return app
}
```

### 3. Routing

```typescript
import { Router } from "express"

const router = Router()

// CRUD routes
router.get("/users", userController.getAll)
router.get("/users/:id", userController.getById)
router.post("/users", userController.create)
router.put("/users/:id", userController.update)
router.delete("/users/:id", userController.delete)

export default router
```

### 4. Error Handling

```typescript
export function errorHandler(
  error: Error,
  req: Request,
  res: Response,
  next: NextFunction
): void {
  logger.error(error, { path: req.path, method: req.method })

  if (error instanceof AppError) {
    return res.status(error.statusCode).json({
      success: false,
      message: error.message,
      ...(error.details && { details: error.details }),
    })
  }

  res.status(500).json({
    success: false,
    message: process.env.NODE_ENV === "production"
      ? "Internal server error"
      : error.message,
  })
}
```

### 5. Request Validation

**Express Validator:**
```typescript
import { body, validationResult } from "express-validator"

export const validateUser = [
  body("name")
    .trim()
    .notEmpty()
    .withMessage("Name is required")
    .isLength({ min: 2, max: 50 }),
  body("email")
    .trim()
    .isEmail()
    .withMessage("Invalid email address"),
]

export function handleValidationErrors(
  req: Request,
  res: Response,
  next: NextFunction
): void {
  const errors = validationResult(req)
  if (!errors.isEmpty()) {
    return res.status(400).json({
      success: false,
      message: "Validation failed",
      errors: errors.array(),
    })
  }
  next()
}
```

### 6. Authentication

```typescript
import jwt from "jsonwebtoken"

export function authMiddleware(req: Request, res: Response, next: NextFunction): void {
  const authHeader = req.headers.authorization

  if (!authHeader || !authHeader.startsWith("Bearer ")) {
    throw new UnauthorizedError("No token provided")
  }

  const token = authHeader.substring(7)

  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET!)
    req.user = decoded
    next()
  } catch (error) {
    throw new UnauthorizedError("Invalid token")
  }
}
```

### 7. Rate Limiting

```typescript
import rateLimit from "express-rate-limit"

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100, // limit each IP to 100 requests
  message: "Too many requests from this IP",
})

app.use("/api", limiter)
```

## Quick Start

1. **Initialize Express app:**
   ```bash
   npm init -y
   npm install express typescript @types/express
   ```

2. **Create basic server:**
   ```typescript
   import express from "express"
   const app = express()
   app.listen(3000, () => console.log("Server running"))
   ```

3. **Add middleware:**
   ```bash
   npm install helmet cors morgan
   ```

4. **Create routes:**
   ```typescript
   const router = express.Router()
   router.get("/users", (req, res) => res.json({ users: [] }))
   ```

5. **Start server:**
   ```bash
   npm run dev
   ```

## Production Checklist

- [ ] Use TypeScript for type safety
- [ ] Implement proper middleware order
- [ ] Add security headers with Helmet
- [ ] Configure CORS appropriately
- [ ] Implement authentication and authorization
- [ ] Add rate limiting for abuse prevention
- [ ] Validate input with express-validator or Zod
- [ ] Implement proper error handling
- [ ] Add logging with Winston
- [ ] Use async/await for async operations
- [ ] Test routes with Supertest
- [ ] Add health check endpoint
- [ ] Implement graceful shutdown
- [ ] Use clustering for production
- [ ] Monitor performance and errors

## Anti-patterns

1. **Poor Middleware Order**: Don't order middleware incorrectly
2. **Missing Error Handling**: Don't fail to handle errors appropriately
3. **No Input Validation**: Don't skip input validation
4. **Poor Security**: Don't fail to implement security measures
5. **No Logging**: Don't fail to log requests and errors
6. **Poor Performance**: Don't fail to optimize performance

## Integration Points

- **Error Handling**: `03-backend-api/error-handling`
- **Validation**: `03-backend-api/validation`
- **Middleware**: `03-backend-api/middleware`
- **API Design**: `01-foundations/api-design`
- **Monitoring**: `14-monitoring-observability`

## Further Reading

- [Express.js Documentation](https://expressjs.com/)
- [Express Best Practices](https://github.com/goldbergyoni/nodebestpractices)
- [Express Middleware Guide](https://expressjs.com/en/guide/writing-middleware.html)

Overview

This skill provides practical, production-ready patterns for building REST APIs with Express.js, covering middleware order, routing, validation, authentication, error handling, rate limiting, and deployment patterns. It distills best practices into actionable code patterns and a production checklist to accelerate reliable API development.

How this skill works

It inspects common Express.js concerns and prescribes a clear middleware ordering, reusable route patterns, and standard handlers for validation, authentication, and errors. The skill includes ready-to-use code samples for app setup, middleware composition, CRUD routing, JWT auth, rate limiting, and validation flows so you can drop them into a project and adapt quickly.

When to use it

  • Starting a new REST API with Node.js and Express
  • Refactoring an existing Express app to follow production patterns
  • Adding standardized authentication, validation, or error handling
  • Hardening an API for security, rate limiting, and observability
  • Preparing an app for production with clustering and graceful shutdown

Best practices

  • Enforce middleware order: security headers, CORS, logging, parsing, auth, routes, then error handler
  • Keep controllers thin and move business logic to services for testability
  • Validate every external input with express-validator or Zod before business logic
  • Use centralized error classes and a last-resort error handler that hides internals in production
  • Protect endpoints with JWT-based auth and add rate limits per route or IP

Example use cases

  • Bootstrapping a new user management API with CRUD routes and validation
  • Adding JWT authentication middleware to secure API endpoints
  • Applying rate limiting and Helmet to defend a public API from abuse
  • Implementing a unified error handler to standardize API error responses
  • Converting callback code to async/await and testing routes with Supertest

FAQ

What middleware order should I follow?

Apply security headers and CORS first, then request logging, body parsing, custom middlewares (request id, logging), authentication, routes, and finally the error handler.

How do I handle validation errors consistently?

Use express-validator or Zod at the route level, run a validation error handler that returns a 400 with an errors array, and keep controllers unaware of validation logic.