-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.js
More file actions
121 lines (101 loc) · 3.61 KB
/
Copy pathmain.js
File metadata and controls
121 lines (101 loc) · 3.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// Main application entrypoint with advanced configurations, security, monitoring, and dev features
const express = require('express');
const mongoose = require('mongoose');
const cookieParser = require('cookie-parser');
const helmet = require('helmet');
const morgan = require('morgan');
const rateLimit = require('express-rate-limit');
const compression = require('compression');
const cors = require('cors');
const swaggerUi = require('swagger-ui-express');
const YAML = require('yamljs');
const promClient = require('prom-client');
const fs = require('fs');
const path = require('path');
require('dotenv').config();
const PORT = process.env.PORT || 3000;
const MONGO_URI = process.env.MONGO_URI || 'mongodb://127.0.0.1:27017/library';
const CORS_ORIGIN = process.env.CORS_ORIGIN || 'http://localhost:4200';
// App initalization and configuration
const app = express();
app.use(helmet());
app.use(morgan('combined'));
app.use(rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // limit each IP to 100 requests
message: 'Too many requests, please try again later.'
}));
app.use(express.urlencoded({ extended: true, limit: '10kb' })); // parse URL-encoded
app.use(cookieParser());
app.use(cors({
origin: CORS_ORIGIN,
credentials: true,
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization']
}));
// Prometheus metrics
promClient.collectDefaultMetrics();
const httpRequestDurationMicroseconds = new promClient.Histogram({
name: 'http_request_duration_ms',
help: 'Duration of HTTP requests in ms',
labelNames: ['method', 'route', 'status_code'],
buckets: [50, 100, 200, 300, 400, 500, 1000]
});
app.get('/metrics', async (req, res) => {
res.set('Content-Type', promClient.register.contentType);
res.end(await promClient.register.metrics());
});
// Request timing middleware
app.use((req, res, next) => {
const end = httpRequestDurationMicroseconds.startTimer();
res.on('finish', () => {
end({ method: req.method, route: req.route ? req.route.path : req.originalUrl, status_code: res.statusCode });
});
next();
});
// Swagger API
const swaggerDocument = YAML.load(path.join(__dirname, 'docs', 'openapi.yaml'));
app.use('/docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument));
const booksRouter = require('./routes/booksRoutes');
const userRouter = require('./routes/userRoutes');
app.use('/v1/books', booksRouter);
app.use('/v1/users', userRouter);
// Health check endpoints
app.get('/healthz', (req, res) => res.status(200).send({ status: 'OK' }));
app.get('/readyz', (req, res) => res.status(200).send({ database: mongoose.connection.readyState }));
// 404 handler
app.use((req, res, next) => {
res.status(404).json({ error: 'Not Found' });
});
console.error(err.stack);
res.status(err.status || 500).json({
error: err.message || 'Internal Server Error'
});
});
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => console.log('MongoDB connected'))
.catch(err => {
console.error('MongoDB connection error:', err);
process.exit(1);
});
const server = app.listen(PORT, () => {
console.log(`Server listening on http://localhost:${PORT}`);
});
const shutdown = () => {
console.log('Received kill signal, shutting down gracefully');
server.close(() => {
console.log('Closed out remaining connections');
mongoose.connection.close(false, () => {
console.log('MongoDb connection closed');
process.exit(0);
});
});
setTimeout(() => {
console.error('Could not close connections in time, forcing shut down');
process.exit(1);
}, 10000);
};
process.on('SIGTERM', shutdown);
process.on('SIGINT', shutdown);