Пошук уроків, статей та іншого контенту
Порівняєте NestJS, Express та Fastify за архітектурою, продуктивністю, можливостями й підходами до розробки.
NestJS, Express і Fastify — це інструменти для створення серверних застосунків на Node.js, але вони розв’язують різні задачі.
Express — мінімалістичний вебфреймворк із великою екосистемою.
Fastify — вебфреймворк, орієнтований на високу продуктивність і схеми валідації.
NestJS — архітектурний фреймворк для побудови структурованих застосунків. За замовчуванням він працює поверх Express, але може використовувати Fastify.
Тому NestJS не є прямою альтернативою лише Express або Fastify. Він додає архітектуру, правила й готові механізми поверх HTTP-платформи.
Express надає базові інструменти для створення HTTP-сервера:
маршрутизацію;
middleware;
обробку запитів і відповідей;
роботу з параметрами URL;
підтримку великої кількості сторонніх пакетів.
Мінімальний Express-застосунок може виглядати так:
const express = require('express');
const app = express();
const port = 3000;
app.use(express.json());
app.get('/users/:id', (req, res) => {
res.json({
id: req.params.id,
name: 'Олена',
});
});
app.post('/users', (req, res) => {
res.status(201).json({
message: 'Користувача створено',
user: req.body,
});
});
app.listen(port, () => {
console.log(`Сервер запущено на http://localhost:${port}`);
});Щоб запустити приклад:
npm init -y
npm install express
node app.jsПростий початок для новачків.
Дуже велика кількість пакетів і прикладів.
Гнучка структура проєкту.
Легко додавати власні middleware.
Підходить для невеликих сервісів і простих API.
Express майже не нав’язує структуру. У великому проєкті розробники самостійно вирішують:
де зберігати контролери;
як організувати бізнес-логіку;
як виконувати валідацію;
як налаштувати залежності;
як розділити модулі.
Це дає свободу, але може призвести до різних підходів у різних частинах одного проєкту.
Fastify також є HTTP-фреймворком для Node.js, але його дизайн зосереджений на продуктивності, низьких накладних витратах і схемах даних.
Приклад простого Fastify-сервера:
const fastify = require('fastify')({
logger: true,
});
fastify.get('/users/:id', async (request) => {
return {
id: request.params.id,
name: 'Олена',
};
});
fastify.post(
'/users',
{
schema: {
body: {
type: 'object',
required: ['name'],
properties: {
name: { type: 'string' },
},
},
},
},
async (request, reply) => {
reply.code(201);
return {
message: 'Користувача створено',
user: request.body,
};
},
);
const start = async () => {
try {
await fastify.listen({ port: 3000 });
} catch (error) {
fastify.log.error(error);
process.exit(1);
}
};
start();Для запуску:
npm init -y
npm install fastify
node app.jsУ цьому прикладі schema описує формат тіла запиту. Fastify може використовувати такі схеми для перевірки даних і формування відповідей.
Висока продуктивність у багатьох сценаріях.
Низькі накладні витрати фреймворку.
Вбудована підтримка схем запитів і відповідей.
Зручне логування.
Плагінна архітектура.
Екосистема менша, ніж у Express.
Не всі middleware для Express сумісні з Fastify.
Для команди, знайомої лише з Express, деякі підходи можуть бути незвичними.
Fastify, як і Express, не нав’язує повну структуру великого застосунку.
NestJS — це фреймворк для створення масштабованих серверних застосунків на TypeScript.
Він використовує такі основні поняття:
модулі — групують пов’язані частини застосунку;
контролери — обробляють HTTP-запити;
сервіси — містять бізнес-логіку;
декоратори — описують маршрути та залежності;
dependency injection — автоматично передає потрібні залежності класам.
Приклад контролера NestJS:
import { Body, Controller, Get, Param, Post } from '@nestjs/common';
@Controller('users')
export class UsersController {
@Get(':id')
getUser(@Param('id') id: string) {
return {
id,
name: 'Олена',
};
}
@Post()
createUser(@Body() body: { name: string }) {
return {
message: 'Користувача створено',
user: body,
};
}
}У NestJS маршрут визначається декораторами:
@Controller('users') створює базовий шлях /users;
@Get(':id') відповідає на GET /users/:id;
@Post() відповідає на POST /users;
@Param() отримує параметр URL;
@Body() отримує тіло запиту.
Зазвичай контролер не повинен містити всю бізнес-логіку. Для цього створюють сервіс:
import { Injectable } from '@nestjs/common';
@Injectable()
export class UsersService {
findById(id: string) {
return {
id,
name: 'Олена',
};
}
}Після цього сервіс можна передати в контролер через dependency injection:
import { Controller, Get, Param } from '@nestjs/common';
import { UsersService } from './users.service';
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get(':id')
getUser(@Param('id') id: string) {
return this.usersService.findById(id);
}
}NestJS сам створить екземпляр UsersService, якщо сервіс зареєстрований у відповідному модулі.
Express і Fastify переважно відповідають на питання:
Як отримати HTTP-запит і повернути HTTP-відповідь?
Вони надають основу, а структуру застосунку команда визначає сама.
Типова структура Express або Fastify-проєкту може бути такою:
src/
routes/
controllers/
services/
models/
middlewares/Але ця структура не є обов’язковою. Інша команда може організувати файли зовсім інакше.
NestJS відповідає не лише за HTTP, а й за організацію коду.
Типовий NestJS-проєкт поділяється на функціональні модулі:
src/
users/
users.controller.ts
users.service.ts
users.module.ts
app.module.ts
main.tsТаке розділення допомагає:
знаходити код конкретної функціональності;
ізолювати залежності;
повторно використовувати сервіси;
підтримувати однаковий стиль у команді;
легше тестувати частини застосунку.
У спрощеному порівнянні:
Fastify часто показує вищу пропускну здатність у простих HTTP-бенчмарках.
Express має більше накладних витрат, але зазвичай їх достатньо для типових API.
NestJS поверх Express додає власний рівень абстракції.
NestJS із Fastify може зменшити HTTP-накладні витрати, але все одно зберігає архітектурні можливості NestJS.
Реальна швидкодія залежить не лише від фреймворку. На неї також впливають:
база даних;
зовнішні API;
складність бізнес-логіки;
серіалізація даних;
валідація;
логування;
кешування;
конфігурація сервера.
Наприклад, запит до повільної бази даних може тривати сотні мілісекунд. Різниця між HTTP-фреймворками в такому випадку може бути набагато меншою за час очікування бази даних.
Тому не варто обирати фреймворк лише за результатом синтетичного бенчмарку.
Express добре підходить, якщо потрібні:
невеликий API;
простий сервер;
швидкий прототип;
повний контроль над структурою;
використання специфічних Express middleware.
Розробник сам вирішує, як організувати контролери, сервіси й перевірку даних.
Fastify зручно використовувати, якщо важливі:
висока продуктивність HTTP-рівня;
структуровані схеми даних;
вбудоване логування;
плагінний підхід;
компактний і швидкий сервер.
Fastify також залишає багато архітектурних рішень на розсуд команди.
NestJS доцільний, якщо потрібні:
чітка структура великого проєкту;
TypeScript;
dependency injection;
модульність;
єдиний стиль для команди;
вбудована інтеграція з типовими серверними механізмами;
зручне масштабування кількох функціональних частин.
За це доводиться платити складнішим стартом і більшою кількістю абстракцій.
За замовчуванням NestJS використовує Express. Це означає, що багато Express-підходів і middleware можна використовувати в NestJS.
NestJS також можна налаштувати на Fastify через адаптер. Тоді контролери, модулі та сервіси залишаються NestJS-кодом, а HTTP-платформою стає Fastify.
Приклад запуску NestJS із Fastify:
import { NestFactory } from '@nestjs/core';
import {
FastifyAdapter,
NestFastifyApplication,
} from '@nestjs/platform-fastify';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create<NestFastifyApplication>(
AppModule,
new FastifyAdapter(),
);
await app.listen(3000, '0.0.0.0');
}
bootstrap();Для цього проєкт має використовувати пакет адаптера Fastify. Вибір адаптера не змінює основні контролери й модулі, але може впливати на сумісність middleware та деякі особливості конфігурації.
Express має найнижчий поріг входу:
app.get('/status', (req, res) => {
res.json({ status: 'ok' });
});У NestJS той самий маршрут потребує контролера:
import { Controller, Get } from '@nestjs/common';
@Controller()
export class AppController {
@Get('status')
getStatus() {
return { status: 'ok' };
}
}NestJS-код виглядає багатослівніше, але така структура стає корисною в більших застосунках. Контролер відповідає за HTTP, сервіс — за бізнес-логіку, а модуль — за зв’язування частин.
Отже:
Express швидше дозволяє написати перший маршрут.
NestJS допомагає підтримувати порядок у великому коді.
Fastify поєднує низькорівневий стиль HTTP-фреймворку з фокусом на продуктивність і схеми.
Орієнтуйтеся на розмір проєкту та потреби команди.
ви вивчаєте основи Node.js і HTTP;
потрібен невеликий сервер;
важлива максимальна кількість готових прикладів;
команда вже добре знає Express;
вам потрібна гнучка структура без обов’язкової архітектури.
потрібна висока продуктивність HTTP-рівня;
ви хочете використовувати схеми запитів і відповідей;
потрібні вбудовані можливості логування;
команда готова працювати з Fastify-екосистемою.
проєкт має багато функціональних модулів;
над ним працює кілька розробників;
важливі TypeScript і dependency injection;
потрібна стандартна архітектура;
застосунок має розвиватися протягом тривалого часу.
NestJS використовує HTTP-платформу під капотом. За замовчуванням це Express, але можна вибрати Fastify.
Синтетичний тест показує лише конкретний сценарій. У реальному застосунку значний час можуть займати база даних, зовнішні сервіси та бізнес-логіка.
Express не забороняє модулі, сервіси чи контролери. Він просто не створює їх автоматично і не змушує команду використовувати конкретний стиль.
Express і Fastify мають різні API та механізми розширення. Middleware для Express не обов’язково працюватиме з Fastify.
Контролер має приймати запит і повертати відповідь. Основну бізнес-логіку краще розміщувати в сервісах, щоб код було простіше тестувати та повторно використовувати.
Express — простий і гнучкий фреймворк із великою екосистемою.
Fastify — швидкий HTTP-фреймворк зі схемами, плагінами та низькими накладними витратами.
NestJS — структурований TypeScript-фреймворк із модулями, контролерами, сервісами та dependency injection.
NestJS за замовчуванням працює поверх Express.
NestJS можна налаштувати на використання Fastify.
Express і Fastify дають більше свободи на рівні архітектури.
NestJS потребує більше початкових знань, але допомагає підтримувати великі проєкти.
Найкращий вибір залежить від розміру застосунку, вимог до продуктивності та досвіду команди.