Розробка бекенду сайту на Node.js (Express)

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.
Розробка та обслуговування будь-яких видів сайтів:
Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Розробка бекенду сайту на Node.js (Express)
Середня
від 1 тижня до 3 місяців
Часті питання
Наші компетенції:
Етапи розробки
Останні роботи
  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851

Розробка веб-бекенду на Node.js (Express)

Express залишається прагматичним вибором для веб-бекенду: мінімум магії, передбачене поведінка, величезна екосистема middleware. Не найшвидший фреймворк (Fastify швидший), не найбагатший на функції (NestJS багатший), але комбінація простоти й гнучкості робить його робочим інструментом для більшості завдань.

Структура проекту

Плоска структура "все файли в routes/" працює до певного масштабу. Зростом потрібна явна багатошарова архітектура:

src/
├── config/
│   ├── env.ts
│   └── database.ts
├── modules/
│   ├── users/
│   │   ├── users.router.ts
│   │   ├── users.service.ts
│   │   ├── users.repository.ts
│   │   └── users.schema.ts
│   ├── products/
│   └── orders/
├── middleware/
│   ├── auth.ts
│   ├── errorHandler.ts
│   └── rateLimit.ts
├── lib/
│   ├── database.ts
│   ├── redis.ts
│   └── mailer.ts
└── app.ts

Налаштування додатку

// src/app.ts
import express from 'express';
import helmet from 'helmet';
import cors from 'cors';
import { pinoHttp } from 'pino-http';

export function createApp() {
  const app = express();

  // Безпека
  app.use(helmet());
  app.use(cors({
    origin: env.ALLOWED_ORIGINS.split(','),
    credentials: true,
  }));

  // Парсинг
  app.use(express.json({ limit: '1mb' }));

  // Логування
  app.use(pinoHttp({ logger }));

  // Роути
  app.use('/api/users', usersRouter);

  // Обробка помилок—має бути останньою
  app.use(errorHandler);

  return app;
}

Конфігурація оточення

// src/config/env.ts
import { z } from 'zod';

const envSchema = z.object({
  NODE_ENV: z.enum(['development', 'production']).default('development'),
  PORT: z.coerce.number().default(3000),
  DATABASE_URL: z.string().url(),
  JWT_SECRET: z.string().min(32),
});

export const env = envSchema.parse(process.env);

Падіння при старті з явним повідомленням про помилку краще ніж кодований comportement під час виконання.

Паттерн Router → Service → Repository

// modules/products/products.router.ts
import { Router } from 'express';
import { ProductsService } from './products.service';

const service = new ProductsService();
export const productsRouter = Router();

productsRouter.get('/', async (req, res, next) => {
  try {
    const result = await service.list(req.query);
    res.json(result);
  } catch (err) { next(err); }
});

productsRouter.post('/', async (req, res, next) => {
  try {
    const product = await service.create(req.body);
    res.status(201).json(product);
  } catch (err) { next(err); }
});
// modules/products/products.service.ts
export class ProductsService {
  private repo = new ProductsRepository();

  async list(query: any) {
    const cacheKey = `products:list:${JSON.stringify(query)}`;
    const cached = await redis.get(cacheKey);
    if (cached) return JSON.parse(cached);

    const result = await this.repo.findMany(query);
    await redis.set(cacheKey, JSON.stringify(result), 'EX', 300);
    return result;
  }

  async create(data: any) {
    const product = await this.repo.create(data);
    // Інвалідація списочного кешу
    const keys = await redis.keys('products:list:*');
    if (keys.length > 0) await redis.del(keys);
    return product;
  }
}

Middleware: валідація, аутентифікація, помилки

// middleware/validate.ts
export function validate(schemas: any) {
  return (req: Request, res: Response, next: NextFunction) => {
    try {
      if (schemas.body) req.body = schemas.body.parse(req.body);
      if (schemas.query) req.query = schemas.query.parse(req.query);
      next();
    } catch (err) {
      return res.status(422).json({
        error: 'Validation failed',
        details: err.flatten().fieldErrors,
      });
    }
  };
}

// middleware/errorHandler.ts
export function errorHandler(err: Error, _req: Request, res: Response) {
  logger.error({ err }, 'Unhandled error');

  if (err instanceof AppError) {
    return res.status(err.statusCode).json({ error: err.message });
  }

  const message = process.env.NODE_ENV === 'production'
    ? 'Internal server error'
    : err.message;

  res.status(500).json({ error: message });
}

JWT аутентифікація

// middleware/auth.ts
export function authenticate(req: Request, res: Response, next: NextFunction) {
  const authHeader = req.headers.authorization;
  if (!authHeader?.startsWith('Bearer ')) {
    return res.status(401).json({ error: 'Unauthorized' });
  }

  const token = authHeader.slice(7);

  try {
    const payload = jwt.verify(token, env.JWT_SECRET);
    req.user = { id: payload.sub, role: payload.role };
    next();
  } catch (err) {
    res.status(401).json({ error: 'Invalid token' });
  }
}

Шар бази даних

// lib/database.ts
import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

export { prisma };

Запуск сервера

// src/server.ts
import { createApp } from './app';
import { env } from './config/env';

const app = createApp();
app.listen(env.PORT, () => {
  console.log(`Server running on port ${env.PORT}`);
});

Таймлайн

Базовий сетап: роути, сервіси, middleware—1 день. Інтеграція БД (Prisma), аутентифікація, CRUD endpoint'и—2–3 дні. Тестування, документація—1 день.