Розробка Node.js бекенду для мобільних додатків
Мобільна додаток без бекенду — це просто офлайн нотатки. Як тільки з'являються користувачі, синхронізація даних, push-сповіщення, платежі — потрібен сервер. Node.js + TypeScript — прагматичний вибір для більшості мобільних бекендів: швидкий старт, JSON-нативність, величезна екосистема, один язык для команди якщо на фронті теж TypeScript.
Стек та його компоненти
Fastify або Express. Express — звично та документовано везде. Fastify — швидше (у тестах на 20–30% вищий throughput), schema-first валідація через JSON Schema, TypeScript-підтримка з коробки. Для нового проекту вибираємо Fastify.
// Fastify + TypeScript + Zod валідація
import Fastify from 'fastify';
import { z } from 'zod';
const app = Fastify({ logger: true });
const CreatePostSchema = z.object({
title: z.string().min(1).max(200),
content: z.string().min(1),
authorId: z.string().uuid(),
});
app.post('/posts', async (request, reply) => {
const body = CreatePostSchema.parse(request.body);
const post = await postService.create(body);
return reply.status(201).send(post);
});
PostgreSQL + Prisma ORM. Prisma дає типобезпечні запити з TypeScript-схеми:
model User {
id String @id @default(uuid())
email String @unique
posts Post[]
createdAt DateTime @default(now())
}
const user = await prisma.user.findUnique({
where: { id: userId },
include: { posts: { take: 10, orderBy: { createdAt: 'desc' } } },
});
Prisma Studio — вбудований GUI для перегляду даних у розробці. Prisma Migrate — версіонування схеми БД через migration-файли.
Автентифікація мобільних клієнтів
Для мобільних додатків — JWT з коротким access token (15 хв) та довгим refresh token (30 днів) у secure storage на пристрої. Ротація refresh token при кожному використанні.
import jwt from 'jsonwebtoken';
export const generateTokens = (userId: string) => ({
accessToken: jwt.sign({ sub: userId, type: 'access' }, process.env.JWT_SECRET!, {
expiresIn: '15m',
}),
refreshToken: jwt.sign({ sub: userId, type: 'refresh' }, process.env.JWT_REFRESH_SECRET!, {
expiresIn: '30d',
}),
});
// Middleware верифікації
export const authMiddleware = async (request: FastifyRequest, reply: FastifyReply) => {
const token = request.headers.authorization?.replace('Bearer ', '');
if (!token) return reply.status(401).send({ error: 'Unauthorized' });
try {
const payload = jwt.verify(token, process.env.JWT_SECRET!) as JwtPayload;
request.userId = payload.sub!;
} catch {
return reply.status(401).send({ error: 'Invalid token' });
}
};
Refresh token зберігається в БД (таблиця refresh_tokens) — це дозволяє інвалідувати всі сеанси користувача при зміні пароля або logout з усіх пристроїв.
Push-сповіщення через Firebase Admin SDK
import * as admin from 'firebase-admin';
admin.initializeApp({ credential: admin.credential.cert(serviceAccount) });
export const sendPushNotification = async (
fcmToken: string,
title: string,
body: string,
data?: Record<string, string>
) => {
const message: admin.messaging.Message = {
token: fcmToken,
notification: { title, body },
data,
apns: {
payload: { aps: { sound: 'default', badge: 1 } },
},
android: {
priority: 'high',
notification: { sound: 'default' },
},
};
return admin.messaging().send(message);
};
Для масових розсилок — sendEachForMulticast з батчами по 500 токенів. Невалідні токени (messaging/registration-token-not-registered) видаляємо з БД.
Realtime: WebSocket або Server-Sent Events
Чат, лайки в реальному часі, статус доставки — вимагають постійного з'єднання. WebSocket через ws або socket.io:
import { WebSocketServer } from 'ws';
const wss = new WebSocketServer({ server: httpServer });
const connections = new Map<string, WebSocket>();
wss.on('connection', (ws, request) => {
const userId = getUserIdFromRequest(request);
connections.set(userId, ws);
ws.on('close', () => connections.delete(userId));
});
export const notifyUser = (userId: string, event: object) => {
const ws = connections.get(userId);
if (ws?.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify(event));
}
};
Для горизонтального масштабування (кілька інстансів) WebSocket-з'єднання прив'язане до конкретного сервера — потрібен Redis Pub/Sub для розсилки між інстансами.
Інфраструктура
Docker + docker-compose для локальної розробки. PM2 або Docker для production. PostgreSQL основна БД, Redis для кешу та черг (BullMQ). S3 для файлів.
API-структура:
src/
modules/
users/ # controller, service, repository, dto
posts/
notifications/
shared/
middleware/
guards/
utils/
app.ts
server.ts
Шаруватість: controller → service → repository. Service не знає про HTTP-контекст — тестується чисто через Jest.
Типові помилки
Блокуючі операції в event loop. JSON.parse великого файлу, синхронний fs.readFileSync на кожен запит — блокують усі інші запити. Важкі операції — у worker threads або offload в чергу.
N+1 у Prisma. Запит списку постів без include → окремий запит для автора кожного поста. Рішення: завжди include або Prisma $queryRaw з JOIN для складних випадків.
Відсутність rate limiting. Мобільний клієнт відправляє 100 запитів в секунду при поганому сітьовому коді — сервер падає. Fastify Rate Limit (@fastify/rate-limit) + Redis для розподіленого обмеження.
Що входить у розробку
Проектування API контракту (OpenAPI/Swagger). Налаштування інфраструктури (БД, Redis, Docker). Реалізація Auth (JWT + refresh). CRUD модулі під вимоги додатка. Push-сповіщення. CI/CD конфігурація. Документація API.
Терміни
MVP бекенд (Auth + 3–5 ресурсів + push): 2–3 тижні. Повноцінний бекенд з realtime, платежами, файлами: 1–3 місяці. Вартість розраховується після проробки функціональних вимог.







