Skip to content

Commit 806d5b0

Browse files
committed
Created and Implemented health check endpoints
1 parent f46db1b commit 806d5b0

5 files changed

Lines changed: 216 additions & 26 deletions

File tree

README.md

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,100 @@ pnpm lint
7171
pnpm build
7272
```
7373

74+
## Health Check
75+
76+
The server provides health check endpoints for local development and production monitoring:
77+
78+
### Simple Health Check
79+
80+
**Endpoint:** `GET /api/v1/health`
81+
82+
Returns a minimal response suitable for load balancers and uptime monitors:
83+
84+
```json
85+
{
86+
"success": true,
87+
"message": "OK",
88+
"timestamp": "2025-01-15T10:30:00.000Z"
89+
}
90+
```
91+
92+
### Detailed Health Check
93+
94+
**Endpoint:** `GET /api/v1/health/detailed`
95+
96+
Returns comprehensive service status including database connectivity:
97+
98+
```json
99+
{
100+
"success": true,
101+
"message": "Access Layer server is running",
102+
"timestamp": "2025-01-15T10:30:00.000Z",
103+
"version": "1.0.0",
104+
"environment": "development",
105+
"uptime": 12345.67,
106+
"memory": {
107+
"used": 45.23,
108+
"total": 128.5
109+
},
110+
"system": {
111+
"platform": "win32",
112+
"nodeVersion": "v20.10.0"
113+
},
114+
"database": {
115+
"status": "connected",
116+
"responseTime": 12
117+
},
118+
"services": [
119+
{
120+
"name": "API Server",
121+
"status": "healthy"
122+
},
123+
{
124+
"name": "Database",
125+
"status": "healthy"
126+
}
127+
]
128+
}
129+
```
130+
131+
**Response Codes:**
132+
133+
- `200 OK` - All services healthy (or development mode)
134+
- `503 Service Unavailable` - Database disconnected in production
135+
136+
### Usage Examples
137+
138+
**Local Development:**
139+
140+
```bash
141+
curl http://localhost:3000/api/v1/health/detailed
142+
```
143+
144+
**Production Monitoring:**
145+
146+
```bash
147+
curl https://your-domain.com/api/v1/health
148+
```
149+
150+
**Docker/Kubernetes Health Probes:**
151+
152+
```yaml
153+
livenessProbe:
154+
httpGet:
155+
path: /api/v1/health
156+
port: 3000
157+
initialDelaySeconds: 10
158+
periodSeconds: 30
159+
160+
readinessProbe:
161+
httpGet:
162+
path: /api/v1/health/detailed
163+
port: 3000
164+
initialDelaySeconds: 5
165+
periodSeconds: 10
166+
```
167+
74168
## Open source workflow
75169
76170
- Read [CONTRIBUTING.md](./CONTRIBUTING.md) before starting work.

src/app.ts

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import { corsMiddleware } from './middlewares/cors.middleware';
77
import helmet from 'helmet';
88
import morgan from 'morgan';
99
import tspecOptions from './tspec.config';
10-
import { envConfig } from './config';
1110
import { SendMail } from './utils/mail.utils';
1211
import { appRateLimit } from './middlewares/rate.middleware';
1312

@@ -22,31 +21,7 @@ app.use(morgan('combined'));
2221
app.use(express.urlencoded({ extended: true }));
2322
app.use(appRateLimit);
2423

25-
// Health check
26-
app.get('/health', (_, res: Response) => {
27-
const healthData = {
28-
success: true,
29-
message: 'Access Layer server is running',
30-
timestamp: new Date().toISOString(),
31-
version: '1.0.0',
32-
environment: envConfig.MODE || 'development',
33-
uptime: process.uptime(),
34-
memory: {
35-
used:
36-
Math.round((process.memoryUsage().heapUsed / 1024 / 1024) * 100) /
37-
100,
38-
total:
39-
Math.round((process.memoryUsage().heapTotal / 1024 / 1024) * 100) /
40-
100,
41-
},
42-
system: {
43-
platform: process.platform,
44-
nodeVersion: process.version,
45-
},
46-
};
47-
48-
res.status(200).json(healthData);
49-
});
24+
// Health check endpoints are now in /api/v1/health
5025

5126
async function setupTspecDocs() {
5227
try {
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import { Request, Response } from 'express';
2+
import { prisma } from '../../utils/prisma.utils';
3+
import { envConfig } from '../../config';
4+
5+
interface HealthStatus {
6+
success: boolean;
7+
message: string;
8+
timestamp: string;
9+
version: string;
10+
environment: string;
11+
uptime: number;
12+
memory: {
13+
used: number;
14+
total: number;
15+
};
16+
system: {
17+
platform: string;
18+
nodeVersion: string;
19+
};
20+
database?: {
21+
status: 'connected' | 'disconnected';
22+
responseTime?: number;
23+
};
24+
services?: {
25+
name: string;
26+
status: 'healthy' | 'unhealthy';
27+
}[];
28+
}
29+
30+
export const healthCheck = async (_: Request, res: Response): Promise<void> => {
31+
const startTime = Date.now();
32+
33+
try {
34+
// Check database connectivity
35+
let dbStatus: HealthStatus['database'] = {
36+
status: 'disconnected',
37+
};
38+
39+
try {
40+
await prisma.$queryRaw`SELECT 1`;
41+
const dbResponseTime = Date.now() - startTime;
42+
dbStatus = {
43+
status: 'connected',
44+
responseTime: dbResponseTime,
45+
};
46+
} catch (dbError) {
47+
console.error('Database health check failed:', dbError);
48+
dbStatus = {
49+
status: 'disconnected',
50+
};
51+
}
52+
53+
const healthData: HealthStatus = {
54+
success: true,
55+
message: 'Access Layer server is running',
56+
timestamp: new Date().toISOString(),
57+
version: '1.0.0',
58+
environment: envConfig.MODE || 'development',
59+
uptime: process.uptime(),
60+
memory: {
61+
used:
62+
Math.round((process.memoryUsage().heapUsed / 1024 / 1024) * 100) /
63+
100,
64+
total:
65+
Math.round((process.memoryUsage().heapTotal / 1024 / 1024) * 100) /
66+
100,
67+
},
68+
system: {
69+
platform: process.platform,
70+
nodeVersion: process.version,
71+
},
72+
database: dbStatus,
73+
services: [
74+
{
75+
name: 'API Server',
76+
status: 'healthy',
77+
},
78+
{
79+
name: 'Database',
80+
status: dbStatus.status === 'connected' ? 'healthy' : 'unhealthy',
81+
},
82+
],
83+
};
84+
85+
// Return 503 if database is disconnected in production
86+
const overallHealthy =
87+
dbStatus.status === 'connected' ||
88+
envConfig.MODE !== 'production';
89+
90+
res.status(overallHealthy ? 200 : 503).json(healthData);
91+
} catch (error) {
92+
console.error('Health check failed:', error);
93+
res.status(500).json({
94+
success: false,
95+
message: 'Health check failed',
96+
error: error instanceof Error ? error.message : 'Unknown error',
97+
});
98+
}
99+
};
100+
101+
export const simpleHealthCheck = (_: Request, res: Response): void => {
102+
res.status(200).json({
103+
success: true,
104+
message: 'OK',
105+
timestamp: new Date().toISOString(),
106+
});
107+
};
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { Router } from 'express';
2+
import { healthCheck, simpleHealthCheck } from './health.controllers';
3+
4+
const router = Router();
5+
6+
// Detailed health check with database connectivity
7+
router.get('/detailed', healthCheck);
8+
9+
// Simple health check for load balancers
10+
router.get('/', simpleHealthCheck);
11+
12+
export default router;

src/modules/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { Router } from 'express';
22
import authRouter from './auth/auth.routes';
3+
import healthRouter from './health/health.routes';
34

45
const router = Router();
56

7+
router.use('/health', healthRouter);
68
router.use('/auth', authRouter);
79

810
export default router;

0 commit comments

Comments
 (0)