Skip to content

Commit b64f457

Browse files
committed
feat: initial enterprise-grade Node.js REST API reference architecture
0 parents  commit b64f457

15,742 files changed

Lines changed: 1862340 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.example

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Server Configuration
2+
PORT=3000
3+
NODE_ENV=development
4+
5+
# Sentry Monitoring (Optional)
6+
SENTRY_DSN=
7+
8+
# Database Configuration
9+
# Replace with your MongoDB connection string
10+
MONGODB_URI=mongodb://localhost:27017/reference-db
11+
12+
# Security
13+
ALLOWED_ORIGINS=http://localhost:4200,https://yourdomain.com
14+
API_KEY=your_secret_api_key_here

.github/workflows/ci.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name: Node.js CI
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
jobs:
10+
build-and-test:
11+
runs-on: ubuntu-latest
12+
13+
strategy:
14+
matrix:
15+
node-version: [24.x]
16+
17+
steps:
18+
- uses: actions/checkout@v4
19+
20+
- name: Use Node.js ${{ matrix.node-version }}
21+
uses: actions/setup-node@v4
22+
with:
23+
node-version: ${{ matrix.node-version }}
24+
cache: 'npm'
25+
26+
- name: Install dependencies
27+
run: npm ci
28+
29+
- name: Run security audit
30+
run: npm audit --audit-level=high
31+
32+
- name: Run tests
33+
run: npm test
34+
35+
- name: Build project
36+
run: npm run build

.husky/pre-commit

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Husky pre-commit hook
2+
# Ensures all code is audited and tested before commit
3+
4+
echo "Running pre-commit checks..."
5+
6+
# 1. Audit check
7+
npm audit || echo "Warning: Audit failed, but continuing..."
8+
9+
# 2. Test check
10+
npm test

Dockerfile

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Stage 1: Build
2+
FROM node:24-alpine AS builder
3+
4+
WORKDIR /app
5+
6+
# Copy package files
7+
COPY package*.json ./
8+
9+
# Install dependencies
10+
RUN npm ci
11+
12+
# Copy source code
13+
COPY . .
14+
15+
# Build the project
16+
RUN npm run build
17+
18+
# Stage 2: Production
19+
FROM node:24-alpine
20+
21+
WORKDIR /app
22+
23+
# Copy built assets and production dependencies
24+
COPY --from=builder /app/dist ./dist
25+
COPY --from=builder /app/package*.json ./
26+
27+
# Install only production dependencies
28+
RUN npm ci --omit=dev
29+
30+
# Set Environment Variables
31+
ENV NODE_ENV=production
32+
ENV PORT=3000
33+
34+
# Expose port
35+
EXPOSE 3000
36+
37+
# Start the application
38+
# Note: In production, ensure the .env file is provided or environment variables are set in the platform
39+
CMD ["node", "dist/index.js"]

README.md

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# Node.js REST API Reference Architecture
2+
3+
> **A production-ready, highly optimized, and modular Node.js REST API blueprint built with TypeScript.**
4+
5+
This repository serves as a "masterclass" reference for architecting professional-grade backends. It demonstrates a clean separation of concerns, robust security practices, and a scalable project structure that follows the absolute latest industry standards.
6+
7+
## 🚀 Architectural Highlights
8+
9+
- **TypeScript-First Architecture**: Strictly typed from the ground up, utilizing modern `NodeNext` module resolution for high performance and compatibility.
10+
- **Native Environment Management**: Utilizes the Node.js built-in `--env-file` flag (introduced in v20.6.0), eliminating the need for external packages like `dotenv` and reducing the application's dependency footprint.
11+
- **Modular Layered Design**: Follows the **Route -> Controller -> Service** pattern to ensure testability and clear responsibility boundaries.
12+
- **Centralized Config Management**: Validates environment variables at startup, preventing runtime failures due to missing configuration.
13+
- **Enterprise Middleware Stack**:
14+
- **Async Handler**: Centralized error catching for all async routes.
15+
- **Validation Middleware**: Decoupled, reusable input validation using `express-validator`.
16+
- **Rate Limiting**: Integrated pattern for protecting endpoints from abuse.
17+
- **Global Error Handler**: Standardized JSON responses for all operational and system errors.
18+
- **Security-Hardened**: Pre-configured with:
19+
- **Helmet**: Essential security headers.
20+
- **CORS**: Granular cross-origin resource sharing.
21+
- **Automated Testing Masterclass**:
22+
- **Jest & Supertest**: Integrated integration testing for API endpoints.
23+
- **ESM Test Runner**: Configured to support modern TypeScript ESM module resolution.
24+
- **Cloud-Native & DevOps Ready**:
25+
- **Dockerized**: Multi-stage Dockerfile for optimized production images.
26+
- **GitHub Actions**: Automated CI pipeline for testing, auditing, and building.
27+
- **Google Cloud Build**: Pre-configured `cloudbuild.yaml` for GCP deployments.
28+
- **Clean Architecture Testing**: Demonstrates testing controllers and services in isolation from infrastructure.
29+
- **Input Sanitization**: Express-validator integration for defensive programming.
30+
- **Powered-By Suppression**: Hidden server identification.
31+
- **Performance Optimized**: Includes HTTP compression and lightweight request logging via Morgan.
32+
- **Standardized Error Handling**: Centralized middleware for uniform error responses across the entire API.
33+
34+
## 📁 Project Structure
35+
36+
```
37+
src/
38+
├── api/
39+
│ ├── controllers/ # Business logic orchestration
40+
│ ├── middlewares/ # Global and route-specific guards
41+
│ ├── routes/ # Endpoint definitions and validation mapping
42+
│ └── services/ # Core domain logic and third-party integrations
43+
├── core/
44+
│ ├── config/ # Environment and constant management
45+
│ └── utils/ # Reusable helpers (Loggers, Formatters)
46+
├── app.ts # Express application setup
47+
└── index.ts # Server entry point
48+
```
49+
50+
## 🛠️ Tech Stack
51+
52+
- **Runtime**: Node.js (v24+ recommended)
53+
- **Framework**: Express.js
54+
- **Language**: TypeScript
55+
- **Validation**: Express-validator
56+
- **Security**: Helmet, CORS
57+
- **Logging**: Morgan
58+
59+
## 🚦 Getting Started
60+
61+
### Prerequisites
62+
63+
- Node.js ^24.0.0
64+
- npm or yarn
65+
66+
### Installation
67+
68+
1. Clone the repository:
69+
```bash
70+
git clone <repo-url>
71+
cd node-rest-reference-architecture
72+
```
73+
74+
2. Install dependencies:
75+
```bash
76+
npm install
77+
```
78+
79+
3. Configure Environment Variables:
80+
Create a `.env` file based on the provided patterns.
81+
82+
### Development
83+
84+
Run the development server with automatic reloading:
85+
```bash
86+
npm run dev
87+
```
88+
89+
### Build
90+
91+
Compile the TypeScript source into production-ready JavaScript:
92+
```bash
93+
npm run build
94+
```
95+
96+
## 📜 License
97+
98+
This project is open-sourced under the MIT License.

cloudbuild.yaml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
steps:
2+
# 1. Install dependencies and run tests
3+
- name: 'node:24'
4+
entrypoint: npm
5+
args: ['install']
6+
- name: 'node:24'
7+
entrypoint: npm
8+
args: ['run', 'test']
9+
10+
# 2. Build the Docker image
11+
- name: 'gcr.io/cloud-builders/docker'
12+
args: ['build', '-t', 'gcr.io/$PROJECT_ID/node-rest-reference-architecture:$COMMIT_SHA', '.']
13+
14+
# 3. Push the image to Container Registry
15+
- name: 'gcr.io/cloud-builders/docker'
16+
args: ['push', 'gcr.io/$PROJECT_ID/node-rest-reference-architecture:$COMMIT_SHA']
17+
18+
images:
19+
- 'gcr.io/$PROJECT_ID/node-rest-reference-architecture:$COMMIT_SHA'
20+
21+
options:
22+
logging: CLOUD_LOGGING_ONLY
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
"use strict";
2+
Object.defineProperty(exports, "__esModule", { value: true });
3+
exports.handleInquiry = void 0;
4+
const async_handler_js_1 = require("../middlewares/async-handler.js");
5+
const contact_service_js_1 = require("../services/contact.service.js");
6+
/**
7+
* Controller: Handles HTTP requests, performs validation, and delegates logic to services.
8+
*/
9+
exports.handleInquiry = (0, async_handler_js_1.asyncHandler)(async (req, res) => {
10+
const { name, email, message } = req.body;
11+
// 2. Delegate to Service Layer
12+
const result = await contact_service_js_1.contactService.processInquiry({ name, email, message });
13+
// 3. Return Standardized Response
14+
return res.status(200).json({
15+
status: 'success',
16+
data: result,
17+
message: 'Inquiry received successfully.'
18+
});
19+
});
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
"use strict";
2+
Object.defineProperty(exports, "__esModule", { value: true });
3+
exports.asyncHandler = void 0;
4+
/**
5+
* Higher-order function to wrap async express routes.
6+
* Eliminates the need for repetitive try-catch blocks in controllers.
7+
*/
8+
const asyncHandler = (fn) => (req, res, next) => {
9+
Promise.resolve(fn(req, res, next)).catch(next);
10+
};
11+
exports.asyncHandler = asyncHandler;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
"use strict";
2+
Object.defineProperty(exports, "__esModule", { value: true });
3+
exports.rateLimiter = void 0;
4+
/**
5+
* Basic Rate Limiting Pattern:
6+
* In a production-grade enterprise application, you would use 'express-rate-limit'
7+
* with a Redis store to prevent Brute-Force and DoS attacks.
8+
*/
9+
const rateLimiter = (req, res, next) => {
10+
// Logic for rate limiting (Mocked for reference)
11+
// Check IP vs. hit count in Redis/Memory
12+
const isRateLimited = false; // logic goes here
13+
if (isRateLimited) {
14+
return res.status(429).json({
15+
status: 'error',
16+
message: 'Too many requests, please try again later.'
17+
});
18+
}
19+
next();
20+
};
21+
exports.rateLimiter = rateLimiter;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
"use strict";
2+
Object.defineProperty(exports, "__esModule", { value: true });
3+
exports.validate = void 0;
4+
const express_validator_1 = require("express-validator");
5+
const app_error_js_1 = require("../../core/utils/app-error.js");
6+
/**
7+
* Generic Validation Middleware:
8+
* Checks for express-validator errors and throws a standardized AppError.
9+
*/
10+
const validate = (req, res, next) => {
11+
const errors = (0, express_validator_1.validationResult)(req);
12+
if (errors.isEmpty()) {
13+
return next();
14+
}
15+
// Format the errors into a readable string or pass the array to the error handler
16+
const extractedErrors = [];
17+
errors.array().map(err => extractedErrors.push({ [err.type === 'field' ? err.path : 'unknown']: err.msg }));
18+
throw new app_error_js_1.AppError('Validation Error', 422);
19+
};
20+
exports.validate = validate;

0 commit comments

Comments
 (0)