Build Elevate

API

Express.js REST API with authentication, rate limiting, security headers, and database integration

API Application

The API application is a secure, production-ready Express.js backend that provides RESTful endpoints for the Web application. It integrates with Better Auth for authentication, Prisma for database access, and Upstash Redis for rate limiting.

Overview

  • Framework: Express.js with TypeScript
  • Location: apps/api
  • Authentication: Better Auth with session management
  • Database: PostgreSQL via Prisma (shared db package)
  • Rate Limiting: Upstash Redis
  • Port: http://localhost:4000

Architecture

The API uses shared packages from the monorepo:

Features

Security

  • Helmet - Sets secure HTTP headers (XSS, CSRF, etc.)
  • CORS - Configurable cross-origin resource sharing with origin whitelist
  • Rate Limiting - Global and per-user rate limits via Upstash Redis
  • Authentication - Better Auth session verification on protected routes
  • Input Validation - Type-safe request validation with TypeScript

Performance & Observability

  • Morgan - HTTP request logging for debugging
  • Health Checks - Readiness and liveness endpoints
  • Error Handling - Centralized error handling with proper HTTP status codes

Database Integration

  • Prisma ORM - Type-safe database queries
  • Connection Pooling - Efficient database connection management
  • Migrations - Version-controlled schema changes

Project Structure

apps/api/
├── src/
│   ├── middleware/          # Express middleware
│   │   ├── auth.ts         # Authentication/session verification
│   │   ├── errorHandler.ts # Centralized error handling
│   │   └── ...
│   ├── routes/             # API route handlers
│   │   ├── health.ts       # Health check endpoints
│   │   ├── users.ts        # User endpoints
│   │   └── ...
│   ├── controllers/        # Business logic
│   ├── services/           # Complex operations
│   ├── config/
│   │   ├── corsOptions.ts  # CORS configuration
│   │   ├── allowedOrigins.ts # Allowed origins list
│   │   └── ...
│   ├── types/              # TypeScript type definitions
│   ├── index.ts            # Server entry point
│   └── env.ts              # Environment variables parsing
├── .env.example            # Environment variables template
├── tsconfig.json           # TypeScript configuration
├── package.json            # Dependencies and scripts
└── Dockerfile.prod         # Production Docker image

Environment Variables

For detailed environment variable setup and configuration, see the Environment Variables Guide.

Copy .env.example to .env.local and fill in the required values following the configuration guide.

Setup & Installation

Follow the Getting Started Guide for complete setup instructions.

Quick summary for the API:

# 1. Install dependencies
pnpm install

# 2. Configure environment variables
cp .env.example .env.local

# 3. Set up database
pnpm db:generate && pnpm db:migrate

# 4. Start development server
pnpm dev

The API server will start at http://localhost:4000.

The development server uses tsx for hot reload, so changes to your code are reflected instantly.

Key Scripts

CommandPurpose
pnpm devStart development server with hot reload
pnpm buildBuild for production
pnpm startStart production server
pnpm lintCheck code quality with ESLint
pnpm formatFormat code with Prettier
pnpm type-checkCheck TypeScript types

See Development Workflow for more commands and options.

Key Files

FilePurpose
src/index.tsServer entry point and middleware setup
src/middleware/auth.tsAuthentication and session verification
src/middleware/errorHandler.tsCentralized error handling
src/config/corsOptions.tsCORS configuration
src/routes/All API endpoint handlers
Dockerfile.prodProduction Docker image

API Endpoints

Health & Status

  • GET /api/health - Health check (always accessible)

Users

  • GET /api/users/session - Get current user session (requires authentication)

For a complete list of endpoints, check the route handlers in src/routes/ or use an API testing tool like Postman or Insomnia.

Security Configuration

CORS

Allowed origins are configured via the ALLOWED_ORIGINS environment variable:

ALLOWED_ORIGINS=http://localhost:3000,https://your-production-domain.com

This is enforced by:

  • src/config/corsOptions.ts - CORS middleware configuration
  • src/config/allowedOrigins.ts - Origin whitelist parsing

Rate Limiting

The API uses Upstash Redis for distributed rate limiting:

# Global rate limit: 100 requests per minute
# User rate limit: 30 requests per minute per user

See @workspace/rate-limit for configuration details.

Authentication Middleware

Protected routes require valid Better Auth session:

router.get("/api/users/session", requireAuth, getUserHandler);

The requireAuth middleware:

  • Ensures the request has a valid Better Auth session
  • Loads the session using getSession if it has not already been resolved
  • Verifies that the user is authenticated before allowing access

After successful authentication, the following properties are available on the request:

req.user; // Authenticated user object
req.session; // Active session information

If authentication fails, the request is rejected with:

401 Unauthorized

Use this middleware on any route that requires an authenticated user.

Development Tips

Hot Reload

Code changes automatically reload the server during development - no manual restart needed.

Database Changes

After modifying schema.prisma, run:

pnpm db:generate
pnpm db:migrate

Testing Endpoints

Use an API client to test endpoints:

# Test health check
curl http://localhost:4000/api/health

# Test with authentication
curl http://localhost:4000/api/users/session \
  --cookie "better-auth.session_token=YOUR_SESSION_COOKIE"

Middleware Order

Middleware is applied in this order:

  1. Security headers (Helmet)
  2. Logging (Morgan)
  3. Body parsing
  4. CORS
  5. Rate limiting
  6. Authentication
  7. Route handlers
  8. Error handling (last)

Type Safety

Always use TypeScript types for:

  • Request/response bodies
  • Database models (from Prisma)
  • Shared utilities (from @workspace/utils)

Building for Production

# Build the application
pnpm build

# Start production server
pnpm start

# Or use Docker
docker-compose -f docker-compose.prod.yml up api

The build process:

  1. Compiles TypeScript to JavaScript
  2. Bundles dependencies
  3. Optimizes for production

Ensure all environment variables (especially BETTER_AUTH_SECRET and UPSTASH_REDIS_REST_TOKEN) are set correctly in production before building.

Troubleshooting

Port Already in Use

See Port Already in Use in the main troubleshooting guide for platform-specific solutions.

Database Connection Errors

See Database Connection Errors in the main troubleshooting guide.

Authentication Middleware Errors

If authentication middleware is failing:

  1. Verify BETTER_AUTH_SECRET matches the Web app (see Authentication Not Working)
  2. Check ALLOWED_ORIGINS includes the Web app URL
  3. Ensure cookies are sent with requests (credentials: 'include')
  4. Check src/middleware/auth.ts for implementation details

Rate Limiting Not Working

# Verify Upstash Redis credentials
# Check UPSTASH_REDIS_REST_URL and UPSTASH_REDIS_REST_TOKEN
# Test Redis connection:
curl -H "Authorization: Bearer $UPSTASH_REDIS_REST_TOKEN" \
  https://YOUR_REDIS_ENDPOINT.upstash.io/get/test

CORS Errors

# Verify ALLOWED_ORIGINS includes the Web app domain
# Example: ALLOWED_ORIGINS=http://localhost:3000

# Check browser console for specific error
# Ensure credentials are sent: fetch(url, { credentials: 'include' })

Build Fails

# Clear build cache
rm -rf dist

# Rebuild
pnpm build

# Check for TypeScript errors
pnpm type-check

For deployment information, see the Deployment Guide.

On this page