A production-ready Express API server built with TypeScript and TypeORM, featuring comprehensive authentication, authorization, file management, and multi-cloud storage integration.
Base API using express-api
- Features
- Tech Stack
- Architecture
- Prerequisites
- Getting Started
- Environment Variables
- Database Setup
- API Documentation
- Project Structure
- Development
- Production Deployment
- Scripts Reference
- Testing
- Contributing
- License
-
Authentication & Authorization
- User registration with email verification
- JWT-based authentication
- Role-based access control (RBAC)
- Session management with device tracking
- Secure password hashing with Argon2
-
User Management
- Complete CRUD operations
- Profile management
- Soft delete support
- Role assignment (User, Admin, Super Admin)
-
File Upload Management
- Multi-cloud storage support (AWS S3, Google Cloud Storage, MinIO)
- Automatic signed URL generation
- File metadata tracking
- Scheduled URL refresh jobs
-
Session Management
- Multi-device login support
- Track user sessions with device and location info
- Automatic session cleanup via scheduled jobs
-
Email Notifications
- User registration verification emails
- SMTP integration with Nodemailer
- Handlebars email templates
- Type Safety - Full TypeScript support with strict typing
- API Documentation - Interactive Swagger/OpenAPI 3.0 documentation
- Code Quality - ESLint + Prettier with pre-configured rules
- Logging - Structured logging with Pino
- Error Handling - Centralized error handling with custom error classes
- Query Builder - Advanced filtering, sorting, and pagination
- Job Scheduling - Background jobs with node-cron
- Security - Helmet, HPP, CORS, Rate limiting
- Docker Support - Production-ready Dockerfile
- Node.js
>= 20.x- JavaScript runtime - TypeScript
5.9+- Type-safe JavaScript - Express.js
4.21.x- Web framework - TypeORM
0.3.27- ORM for TypeScript - PostgreSQL - Primary database
- jsonwebtoken
9.0.2- JWT implementation - argon2
0.41.1- Password hashing - helmet
8.1.0- Security headers - express-rate-limit
8.1.0- Rate limiting - hpp
0.2.3- HTTP Parameter Pollution protection
- zod
4.1.11- Schema validation - multer
1.4.5-lts.1- File upload handling - date-fns
4.1.0- Date manipulation - lodash
4.17.21- Utility functions
- @aws-sdk/client-s3
3.893.0- AWS S3 integration - @google-cloud/storage
7.17.1- Google Cloud Storage - minio
8.0.6- MinIO client
- nodemailer
7.0.6- Email sending - handlebars
4.7.8- Email templates
- pino
9.11.0- Fast JSON logger - node-cron
3.0.3- Job scheduling - swagger-ui-express
5.0.1- API documentation - PM2 - Process manager for production
- ESLint
9.36.0- JavaScript linter - Prettier
3.6.2- Code formatter - Nodemon
3.1.10- Development auto-reload - release-it
18.1.2- Version management
This project follows a layered architecture pattern with clear separation of concerns:
┌──────────────────────────────────────────┐
│ Handler Layer (Controller) │
│ HTTP Request/Response Handling │
└──────────────────────────────────────────┘
↓
┌──────────────────────────────────────────┐
│ Service Layer │
│ Business Logic & Validation │
└──────────────────────────────────────────┘
↓
┌──────────────────────────────────────────┐
│ Repository Layer (TypeORM) │
│ Data Access & Queries │
└──────────────────────────────────────────┘
↓
┌──────────────────────────────────────────┐
│ PostgreSQL Database │
└──────────────────────────────────────────┘
-
Separation of Concerns
- Handlers: HTTP request/response management
- Services: Business logic and validation
- Repositories: Data persistence via TypeORM
-
Middleware Stack
- Request logging (Pino)
- Security headers (Helmet)
- Rate limiting
- CORS configuration
- User agent parsing
- Authentication & authorization
-
Error Handling
- Custom HTTP error classes (400, 401, 403, 404, 500)
- Centralized error middleware
- Validation error handling
- TypeORM-specific error handling
-
Data Validation
- Zod schemas for type-safe validation
- Request/response validation
- Entity validation at service layer
Before you begin, ensure you have the following installed:
- Node.js >= 20.x (Download)
- PostgreSQL >= 14.x (Download)
- npm or yarn or pnpm (Package manager)
- Docker (optional, for containerized deployment)
git clone https://github.com/masb0ymas/express-api-typeorm.git
cd express-api-typeormUsing npm:
npm installUsing yarn:
yarn installUsing pnpm:
pnpm installYou can generate a .env file with secure random secrets:
npm run secretOr manually copy the example file:
cp .env.example .envThen edit .env and configure your settings (see Environment Variables).
Create and initialize the database:
npm run db:syncThis command will:
- Create the database (if it doesn't exist)
- Drop existing schema
- Synchronize schema with entities
- Run migrations and seeders
Alternatively, create the database manually:
# Create database only
npm run db:create
# Reset schema (drop + sync)
npm run db:resetnpm run devThe API will be available at http://localhost:8000
Open your browser and navigate to:
http://localhost:8000/api-docs
This will open the interactive Swagger UI where you can test all endpoints.
Create a .env file in the root directory with the following variables:
NODE_ENV=development
APP_PORT=8000
APP_NAME=express-api-typeorm
APP_URL=http://localhost:8000
APP_DEFAULT_PASS=defaultPassword123TYPEORM_CONNECTION=postgres
TYPEORM_HOST=localhost
TYPEORM_PORT=5432
TYPEORM_USERNAME=postgres
TYPEORM_PASSWORD=your_password
TYPEORM_DATABASE=express_typeorm
TYPEORM_SYNCHRONIZE=false
TYPEORM_LOGGING=false
TYPEORM_ENTITIES=dist/app/database/entity/**/*.js
TYPEORM_MIGRATIONS=dist/app/database/migration/**/*.js
TYPEORM_SUBSCRIBERS=dist/app/database/subscriber/**/*.jsJWT_SECRET=your_jwt_secret_key_here
JWT_EXPIRES=7dMAIL_DRIVER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME=your_email@gmail.com
MAIL_PASSWORD=your_app_password
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=noreply@yourdomain.com
MAIL_FROM_NAME="${APP_NAME}"Choose one storage provider:
STORAGE_PROVIDER=s3
AWS_S3_BUCKET=your-bucket-name
AWS_S3_REGION=us-east-1
AWS_ACCESS_KEY_ID=your_access_key
AWS_SECRET_ACCESS_KEY=your_secret_keySTORAGE_PROVIDER=gcs
GCS_BUCKET=your-bucket-name
GCS_PROJECT_ID=your-project-id
GCS_KEY_FILE=path/to/keyfile.jsonSTORAGE_PROVIDER=minio
MINIO_ENDPOINT=localhost
MINIO_PORT=9000
MINIO_ACCESS_KEY=minioadmin
MINIO_SECRET_KEY=minioadmin
MINIO_BUCKET=your-bucket-name
MINIO_USE_SSL=falseThe database schema includes the following entities:
-
User - User accounts with authentication
- Relationships: Role (Many-to-One), Upload (Many-to-One), Sessions (One-to-Many)
-
Role - User roles for RBAC
- Default roles: User, Admin, Super Admin
-
Session - User session tracking
- Tracks: JWT tokens, device info, IP addresses
-
Upload - File upload metadata
- Supports: AWS S3, Google Cloud Storage, MinIO
# Create database
npm run db:create
# Drop database
npm run db:drop
# Drop schema and sync
npm run db:reset
# Create database + reset schema
npm run db:sync
# Manual TypeORM commands
npx typeorm schema:sync -d ./dist/app/database/connection.js
npx typeorm schema:drop -d ./dist/app/database/connection.jsStart the development server:
npm run devNavigate to:
http://localhost:8000/api-docs
GET / # Hello World
GET /health # Server health and version info
POST /v1/auth/sign-up # User registration
POST /v1/auth/sign-in # User login
GET /v1/auth/verify-session # Verify JWT session
POST /v1/auth/sign-out # User logout
GET /v1/user # List users (paginated, filtered, sorted)
POST /v1/user # Create user (Admin only)
GET /v1/user/:id # Get user by ID
PUT /v1/user/:id # Update user
DELETE /v1/user/:id # Delete user (Admin only)
GET /v1/role # List roles
POST /v1/role # Create role (Admin only)
GET /v1/role/:id # Get role by ID
PUT /v1/role/:id # Update role (Admin only)
DELETE /v1/role/:id # Delete role (Admin only)
POST /v1/upload # Upload file
GET /v1/upload # List uploads
GET /v1/upload/:id # Get upload by ID
DELETE /v1/upload/:id # Delete upload
GET /v1/session # List user sessions
DELETE /v1/session/:id # End session
All list endpoints support:
- Filtering:
?filtered={"field":"value"} - Sorting:
?sorted={"field":"ASC"}or?sorted={"field":"DESC"} - Pagination:
?page=1&pageSize=10
express-api-typeorm/
├── src/
│ ├── main.ts # Application entry point
│ ├── app/
│ │ ├── database/
│ │ │ ├── connection.ts # TypeORM connection
│ │ │ ├── entity/ # Database entities
│ │ │ │ ├── base.ts # Base entity (UUID, timestamps)
│ │ │ │ ├── user.ts
│ │ │ │ ├── role.ts
│ │ │ │ ├── session.ts
│ │ │ │ └── upload.ts
│ │ │ ├── migration/ # Database migrations
│ │ │ ├── schema/ # Zod validation schemas
│ │ │ └── subscriber/ # Entity subscribers
│ │ ├── handler/ # HTTP route handlers
│ │ │ ├── auth.ts
│ │ │ ├── user.ts
│ │ │ ├── role.ts
│ │ │ ├── session.ts
│ │ │ └── upload.ts
│ │ ├── service/ # Business logic layer
│ │ │ ├── base.ts
│ │ │ ├── auth.ts
│ │ │ ├── user.ts
│ │ │ └── ...
│ │ ├── middleware/ # Express middleware
│ │ │ ├── authorization.ts # JWT authentication
│ │ │ ├── error-handle.ts # Global error handler
│ │ │ ├── rate-limit.ts # Rate limiting
│ │ │ └── with-permission.ts # RBAC middleware
│ │ ├── job/ # Scheduled jobs
│ │ │ ├── session.ts # Session cleanup
│ │ │ └── upload.ts # URL refresh
│ │ └── routes/ # Route definitions
│ │ ├── route.ts
│ │ └── v1.ts
│ ├── config/ # Configuration
│ │ ├── env.ts # Environment variables
│ │ ├── app.ts # Express setup
│ │ ├── logger.ts # Pino logger
│ │ ├── hashing.ts # Password hashing
│ │ ├── smtp.ts # Email config
│ │ └── storage.ts # Storage config
│ └── lib/ # Shared utilities
│ ├── async-handler.ts
│ ├── validate.ts
│ ├── http/ # HTTP utilities
│ │ ├── errors/ # Custom error classes
│ │ └── response.ts # Response formatter
│ ├── token/
│ │ └── jwt.ts # JWT utilities
│ ├── query-builder/ # Query helpers
│ ├── storage/ # Storage abstraction
│ ├── smtp/ # Email templates
│ ├── upload/ # File upload
│ ├── swagger/ # API documentation
│ └── constant/ # Application constants
├── public/ # Static assets
│ ├── swagger/ # Swagger files
│ └── email-template/ # Email templates
├── logs/ # Application logs
├── script/
│ └── secret.sh # Environment generator
├── .env.example # Environment template
├── Dockerfile # Docker configuration
├── package.json
├── tsconfig.json
└── README.md
- The
mainbranch uses ES Modules (type: module) - For CommonJS, use the
commonjsbranch
-
Start with hot reload
npm run dev
This command:
- Compiles TypeScript with watch mode
- Automatically restarts on file changes
- Resolves path aliases
-
Code linting
npm run lint
-
Code formatting
npm run format
- Create Entity in
src/app/database/entity/ - Create Schema in
src/app/database/schema/(Zod validation) - Create Service in
src/app/service/ - Create Handler in
src/app/handler/ - Add Routes in
src/app/routes/v1.ts - Run Migration (if needed)
Scheduled jobs are defined in src/app/job/:
- Session Cleanup - Removes expired sessions
- Upload URL Refresh - Updates signed URLs before expiration
Jobs are configured with cron expressions using node-cron.
npm run buildThis creates an optimized production build in the dist/ directory.
NODE_ENV=production node ./dist/main.js# Production
npm run start:production
# Staging
npm run start:stagingPM2 provides:
- Process management
- Auto-restart on crashes
- Load balancing
- Log management
docker build -t yourname/express-api-typeorm:v6.0.0 .docker run -p 8000:8000 \
-e NODE_ENV=production \
-e TYPEORM_HOST=your_db_host \
-e TYPEORM_PASSWORD=your_db_password \
-d yourname/express-api-typeorm:v6.0.0version: '3.8'
services:
api:
image: yourname/express-api-typeorm:v6.0.0
ports:
- "8000:8000"
environment:
- NODE_ENV=production
- TYPEORM_HOST=postgres
- TYPEORM_USERNAME=postgres
- TYPEORM_PASSWORD=password
- TYPEORM_DATABASE=express_typeorm
depends_on:
- postgres
postgres:
image: postgres:15-alpine
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=password
- POSTGRES_DB=express_typeorm
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:Set NODE_ENV to control behavior:
development- Enables Swagger, verbose loggingstaging- Production-like with some debuggingproduction- Optimized, minimal logging, no Swagger
npm run dev # Start with hot reload
npm run build # Build TypeScript
npm run clean # Remove dist folder
npm run secret # Generate .env filenpm run db:create # Create database
npm run db:drop # Drop database
npm run db:schema-sync # Sync schema with entities
npm run db:schema-drop # Drop schema
npm run db:reset # Drop + sync schema
npm run db:sync # Create DB + reset schemanpm start # Run production build
npm run start:staging # Run with PM2 (staging)
npm run start:production # Run with PM2 (production)npm run release # Release new version
npm run release:patch # Release patch version (0.0.x)
npm run release:minor # Release minor version (0.x.0)
npm run release:major # Release major version (x.0.0)
npm run release:pre # Release pre-release (beta)npm test # Run tests (not implemented yet)Testing infrastructure is planned but not yet implemented. The project is set up to support:
- Unit tests (Jest)
- Integration tests
- E2E tests
Contributions to add comprehensive test coverage are welcome!
Contributions are welcome! Please follow these steps:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Use TypeScript
- Follow ESLint rules
- Format code with Prettier
- Write meaningful commit messages
This project is licensed under the MIT License - see the LICENSE.md file for details.
masb0ymas - me@masb0ymas.com
If you find this project helpful, consider supporting:
- Base API structure inspired by express-api
- Built with modern Node.js best practices
- TypeScript for type safety
- TypeORM for elegant database management