← Назад к вопросам
Какой используешь стек на backend части проекта?
1.6 Junior🔥 242 комментариев
#Node.js и JavaScript#Soft skills и опыт работы
Комментарии (2)
🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Мой стек для Node.js Backend проекта
Расскажу, какой стек я использую в production проектах и почему эти технологии.
Основной стек (Core)
Express.js — микрофреймворк
const express = require('express');
const app = express();
app.use(express.json());
app.get('/api/health', (req, res) => {
res.json({ status: 'ok' });
});
Выбираю за простоту и огромный ecosystem.
TypeScript — для типизации
import express, { Request, Response } from 'express';
interface User {
id: string;
email: string;
name: string;
}
async function getUser(req: Request, res: Response): Promise<void> {
const userId: string = req.params.id;
const user: User = await User.findById(userId);
res.json(user);
}
Типизация предотвращает ошибки в runtime.
Аутентификация
JWT + Passport.js
const jwt = require('jsonwebtoken');
const passport = require('passport');
passport.use(new LocalStrategy(
async (username, password, done) => {
const user = await User.findOne({ email: username });
if (!user || !user.comparePassword(password)) {
return done(null, false);
}
return done(null, user);
}
));
app.post('/auth/login', (req, res) => {
const token = jwt.sign(
{ userId: user.id, role: user.role },
process.env.JWT_SECRET,
{ expiresIn: '15m' }
);
res.cookie('refreshToken', refreshToken, {
httpOnly: true,
secure: true,
sameSite: 'strict'
});
res.json({ accessToken: token });
});
Валидация
Zod для Schema validation
import { z } from 'zod';
const userSchema = z.object({
email: z.string().email(),
password: z.string().min(8),
name: z.string().min(2)
});
app.post('/api/users', (req, res) => {
const { error, data } = userSchema.safeParse(req.body);
if (error) {
return res.status(400).json({ error: error.errors });
}
const user = createUser(data);
res.json(user);
});
ORM
Prisma или чистый SQL
const prisma = new PrismaClient();
const user = await prisma.user.findUnique({
where: { id: userId },
include: { posts: true }
});
await prisma.user.update({
where: { id: userId },
data: { email: 'new@email.com' }
});
Или SQL с параметризацией:
const { Pool } = require('pg');
const pool = new Pool();
const result = await pool.query(
'SELECT * FROM users WHERE id = $1 AND deleted_at IS NULL',
[userId]
);
Кэширование
Redis
const redis = require('redis');
const client = redis.createClient();
async function getUserCached(userId) {
const key = `user:${userId}`;
const cached = await client.get(key);
if (cached) {
return JSON.parse(cached);
}
const user = await User.findById(userId);
await client.setEx(key, 3600, JSON.stringify(user));
return user;
}
Логирование
Winston
import winston from 'winston';
const logger = winston.createLogger({
level: process.env.LOG_LEVEL || 'info',
format: winston.format.json(),
transports: [
new winston.transports.File({
filename: 'logs/error.log',
level: 'error'
}),
new winston.transports.File({
filename: 'logs/combined.log'
})
]
});
logger.info('Application started', { port: 3000 });
Тестирование
Jest + Supertest
import request from 'supertest';
import app from '../app';
describe('GET /api/users/:id', () => {
it('should return user by id', async () => {
const response = await request(app)
.get('/api/users/123')
.expect(200);
expect(response.body).toHaveProperty('id');
expect(response.body.id).toBe('123');
});
it('should return 404 if not found', async () => {
await request(app)
.get('/api/users/nonexistent')
.expect(404);
});
});
Error Handling
Кастомные Error классы
class AppError extends Error {
constructor(
public statusCode: number,
message: string,
public code?: string
) {
super(message);
}
}
app.use((err: Error, req: Request, res: Response) => {
if (err instanceof AppError) {
return res.status(err.statusCode).json({
error: { code: err.code, message: err.message }
});
}
logger.error('Unhandled error', { error: err.message });
res.status(500).json({
error: { code: 'INTERNAL_SERVER_ERROR' }
});
});
Миграции
Prisma Migrate
npx prisma migrate dev --name create_users
npx prisma migrate deploy
Или SQL миграции
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE INDEX idx_users_email ON users(email);
Rate Limiting & Security
express-rate-limit
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 100
});
app.use('/api/', limiter);
const authLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 5,
skipSuccessfulRequests: true
});
app.post('/auth/login', authLimiter, (req, res) => {});
Helmet.js
const helmet = require('helmet');
app.use(helmet());
Environment Configuration
dotenv
DATABASE_URL=postgresql://user:pass@localhost/db
JWT_SECRET=super_secret_key
REDIS_URL=redis://localhost:6379
NODE_ENV=development
Структура проекта
src/
├── routes/
├── controllers/
├── services/
├── repositories/
├── models/
├── middleware/
├── utils/
├── config/
├── tests/
└── app.ts
Production Checklist
- HTTPS включен
- Rate limiting настроен
- Logging и monitoring активны
- Error handling корректен
- Аутентификация и авторизация
- SQL injection защита
- CSRF protection
- Secrets в environment переменных
- Регулярные обновления зависимостей
- Тесты покрывают критичные пути
- Graceful shutdown настроен
Этот стек проверен на много production проектов и стабилен.