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

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

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Разработка бэкенда сайта на Node.js (Koa)
Средняя
от 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 (Koa)

Koa — минималистичный фреймворк от создателей Express, переосмысленный под async/await. Там где Express требует next() и колбеки, Koa работает через async/await и middleware-стек, который выполняется по принципу «луковицы»: запрос проходит middleware сверху вниз, потом ответ — снизу вверх.

Выбирают Koa тогда, когда нужна полная свобода выбора библиотек без мнений фреймворка, но с нормальной обработкой async-кода в отличие от Express.

Как работает middleware

import Koa from 'koa'
import Router from '@koa/router'

const app = new Koa()

// Middleware логирования — оборачивает всё ниже
app.use(async (ctx, next) => {
  const start = Date.now()
  await next()  // выполняет всё остальное
  const ms = Date.now() - start
  console.log(`${ctx.method} ${ctx.url} - ${ctx.status} - ${ms}ms`)
})

// Error handling
app.use(async (ctx, next) => {
  try {
    await next()
  } catch (err) {
    ctx.status = err.statusCode || err.status || 500
    ctx.body = {
      error: process.env.NODE_ENV === 'production' ? 'Internal Server Error' : err.message
    }
    ctx.app.emit('error', err, ctx)
  }
})

Это принципиальное отличие от Express: в Koa после await next() вы возвращаетесь обратно в middleware с доступом к финальному состоянию ответа. В Express это невозможно без хаков.

Роутинг

@koa/router — официальный роутер:

import Router from '@koa/router'
import bodyParser from '@koa/bodyparser'

const router = new Router({ prefix: '/api/v1' })

// Middleware для конкретного роута
router.get('/products',
  authenticate,
  async (ctx) => {
    const { page = 1, limit = 20 } = ctx.query
    const offset = (page - 1) * limit

    const [items, total] = await Promise.all([
      db.query('SELECT * FROM products LIMIT $1 OFFSET $2', [limit, offset]),
      db.query('SELECT COUNT(*) FROM products')
    ])

    ctx.body = {
      data: items.rows,
      pagination: {
        page: Number(page),
        limit: Number(limit),
        total: Number(total.rows[0].count)
      }
    }
  }
)

router.post('/products', authenticate, requireRole('admin'), async (ctx) => {
  const data = ctx.request.body
  // ctx.request.body доступен через @koa/bodyparser
  const product = await ProductService.create(data)
  ctx.status = 201
  ctx.body = product
})

app
  .use(bodyParser())
  .use(router.routes())
  .use(router.allowedMethods())  // автоматически обрабатывает OPTIONS и 405

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

src/
  index.js          # точка входа
  app.js            # создание koa-приложения
  middleware/
    auth.js
    errorHandler.js
    requestLogger.js
    validate.js     # валидация через zod или joi
  routes/
    index.js        # агрегирует роутеры
    products.js
    users.js
    orders.js
  services/
    products.js
    users.js
  models/           # или repositories/
  config/
  utils/

Валидация через Zod

Koa не включает валидацию — подключаем Zod:

import { z } from 'zod'

const createProductSchema = z.object({
  name: z.string().min(2).max(255),
  price: z.number().positive(),
  categoryId: z.number().int().positive(),
  description: z.string().optional(),
  attributes: z.record(z.unknown()).optional()
})

// Middleware-фабрика для валидации body
const validateBody = (schema) => async (ctx, next) => {
  const result = schema.safeParse(ctx.request.body)
  if (!result.success) {
    ctx.status = 422
    ctx.body = { errors: result.error.flatten().fieldErrors }
    return
  }
  ctx.validatedBody = result.data
  await next()
}

router.post('/products',
  authenticate,
  validateBody(createProductSchema),
  async (ctx) => {
    const product = await ProductService.create(ctx.validatedBody)
    ctx.status = 201
    ctx.body = product
  }
)

Session и аутентификация

JWT через koa-jwt или вручную через jsonwebtoken:

import jwt from 'jsonwebtoken'

const authenticate = async (ctx, next) => {
  const authHeader = ctx.headers.authorization
  if (!authHeader?.startsWith('Bearer ')) {
    ctx.throw(401, 'No token provided')
  }

  try {
    const token = authHeader.slice(7)
    ctx.state.user = jwt.verify(token, process.env.JWT_SECRET)
    await next()
  } catch {
    ctx.throw(401, 'Invalid or expired token')
  }
}

Сессии через koa-session + Redis store:

import session from 'koa-session'
import RedisStore from 'koa-redis'

app.keys = [process.env.SESSION_SECRET]
app.use(session({
  store: RedisStore({ client: redisClient }),
  maxAge: 86400000 * 7,  // 7 дней
  httpOnly: true,
  secure: process.env.NODE_ENV === 'production',
  sameSite: 'strict'
}, app))

Загрузка файлов

@koa/multer для multipart:

import multer from '@koa/multer'
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3'

const upload = multer({
  storage: multer.memoryStorage(),
  limits: { fileSize: 10 * 1024 * 1024 }, // 10 MB
  fileFilter: (req, file, cb) => {
    if (!file.mimetype.startsWith('image/')) {
      return cb(new Error('Only images allowed'))
    }
    cb(null, true)
  }
})

router.post('/upload',
  authenticate,
  upload.single('file'),
  async (ctx) => {
    const file = ctx.file
    const key = `uploads/${Date.now()}-${file.originalname}`

    await s3.send(new PutObjectCommand({
      Bucket: process.env.S3_BUCKET,
      Key: key,
      Body: file.buffer,
      ContentType: file.mimetype
    }))

    ctx.body = { url: `https://${process.env.CDN_HOST}/${key}` }
  }
)

Когда Koa не подходит

Koa — хорошая база, но требует самостоятельной сборки: нет встроенной валидации, нет swagger-генерации, нет DI. Если проект растёт и нужна структура — лучше Fastify (производительность + схемы) или NestJS (архитектура). Koa остаётся актуальным для небольших API, прокси-серверов и проектов, где команда хочет полный контроль без фреймворк-магии.

Сроки разработки

  • Проектирование + базовый стек: роуты, middleware, подключение БД — 3–5 дней
  • Бизнес-логика CRUD + аутентификация — 1–2 недели
  • Интеграции (email, файлы, платёжки) — 1–2 недели по необходимости
  • Тестирование (jest + supertest) — 3–5 дней

Простой API для сайта-визитки, лендинга или небольшого корпоративного сайта: 3–6 недель. Koa быстро стартует, но требует аккуратности в организации кода — без архитектурных соглашений проект быстро превращается в «Express-спагетти нового поколения».