Пошук уроків, статей та іншого контенту
Налаштуєте маршрути контролера для GET, POST, PUT, PATCH і DELETE-запитів.
Маршрут визначає, як застосунок реагує на HTTP-запит. Він складається з:
HTTP-методу: GET, POST, PUT, PATCH або DELETE;
шляху, наприклад /tasks;
обробника, який виконується після отримання запиту.
У NestJS маршрути описують у контролерах за допомогою декораторів:
@Get()
@Post()
@Put()
@Patch()
@Delete()Контролер із префіксом tasks може обробляти такі запити:
GET /tasks — отримати всі завдання;
GET /tasks/1 — отримати завдання з ідентифікатором 1;
POST /tasks — створити завдання;
PUT /tasks/1 — повністю замінити завдання;
PATCH /tasks/1 — частково оновити завдання;
DELETE /tasks/1 — видалити завдання.
Декоратор @Controller() задає спільний префікс для всіх маршрутів контролера:
@Controller('tasks')
export class TasksController {
// Маршрут буде доступний за адресою GET /tasks
@Get()
findAll() {
return [];
}
}Метод findAll() виконається лише для GET-запиту до /tasks.
Нижче наведено простий контролер для роботи із завданнями. Дані зберігаються в масиві в пам’яті, тому після перезапуску застосунку вони зникнуть.
app.controller.tsimport {
Body,
Controller,
Delete,
Get,
NotFoundException,
Param,
Patch,
Post,
Put,
} from '@nestjs/common';
interface Task {
id: number;
title: string;
completed: boolean;
}
interface CreateTaskDto {
title: string;
completed?: boolean;
}
interface UpdateTaskDto {
title?: string;
completed?: boolean;
}
// Тимчасове сховище для прикладу
const tasks: Task[] = [
{
id: 1,
title: 'Вивчити маршрути NestJS',
completed: false,
},
];
@Controller('tasks')
export class AppController {
@Get()
findAll(): Task[] {
return tasks;
}
@Get(':id')
findOne(@Param('id') id: string): Task {
const task = tasks.find((item) => item.id === Number(id));
if (!task) {
throw new NotFoundException('Завдання не знайдено');
}
return task;
}
@Post()
create(@Body() body: CreateTaskDto): Task {
const task: Task = {
id: tasks.length > 0 ? tasks[tasks.length - 1].id + 1 : 1,
title: body.title,
completed: body.completed ?? false,
};
tasks.push(task);
return task;
}
@Put(':id')
replace(@Param('id') id: string, @Body() body: CreateTaskDto): Task {
const taskIndex = tasks.findIndex((item) => item.id === Number(id));
if (taskIndex === -1) {
throw new NotFoundException('Завдання не знайдено');
}
const replacedTask: Task = {
id: Number(id),
title: body.title,
completed: body.completed ?? false,
};
tasks[taskIndex] = replacedTask;
return replacedTask;
}
@Patch(':id')
update(
@Param('id') id: string,
@Body() body: UpdateTaskDto,
): Task {
const task = tasks.find((item) => item.id === Number(id));
if (!task) {
throw new NotFoundException('Завдання не знайдено');
}
if (body.title !== undefined) {
task.title = body.title;
}
if (body.completed !== undefined) {
task.completed = body.completed;
}
return task;
}
@Delete(':id')
remove(@Param('id') id: string): { message: string } {
const taskIndex = tasks.findIndex((item) => item.id === Number(id));
if (taskIndex === -1) {
throw new NotFoundException('Завдання не знайдено');
}
tasks.splice(taskIndex, 1);
return {
message: 'Завдання видалено',
};
}
}Якщо контролер називається AppController, його потрібно додати до модуля.
app.module.tsimport { Module } from '@nestjs/common';
import { AppController } from './app.controller';
@Module({
controllers: [AppController],
})
export class AppModule {}Стандартний файл main.ts може виглядати так:
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
}
bootstrap();Після запуску застосунку маршрути будуть доступні на http://localhost:3000.
Метод GET використовують для отримання даних. Він не повинен змінювати стан сервера.
@Get()
findAll() {
return tasks;
}Цей маршрут обробляє:
GET /tasksДля отримання одного ресурсу параметр додають до шляху:
@Get(':id')
findOne(@Param('id') id: string) {
// ...
}Маршрут:
GET /tasks/1@Param('id') отримує значення динамічної частини шляху:
@Get(':id')
findOne(@Param('id') id: string) {
return {
receivedId: id,
};
}HTTP-параметри надходять у застосунок як рядки. Тому значення id перетворюють на число за допомогою Number(id):
const numericId = Number(id);Метод POST використовують для створення нового ресурсу.
@Post()
create(@Body() body: CreateTaskDto) {
// ...
}@Body() отримує дані з тіла запиту. Наприклад, клієнт може надіслати:
{
"title": "Прочитати документацію",
"completed": false
}Запит до маршруту створення:
POST /tasksЗа замовчуванням NestJS повертає для POST статус 201 Created, якщо обробник успішно завершився.
Метод PUT використовують для повної заміни ресурсу.
@Put(':id')
replace(@Param('id') id: string, @Body() body: CreateTaskDto) {
// ...
}Приклад запиту:
{
"title": "Оновлена назва",
"completed": true
}Якщо ресурс мав додаткові поля, повна заміна може їх видалити. Тому для PUT зазвичай передають повний опис ресурсу.
Маршрут:
PUT /tasks/1Метод PATCH використовують для часткового оновлення ресурсу.
@Patch(':id')
update(@Param('id') id: string, @Body() body: UpdateTaskDto) {
// ...
}Можна передати лише поле, яке потрібно змінити:
{
"completed": true
}У цьому випадку значення title залишиться без змін.
Маршрут:
PATCH /tasks/1Різниця між PUT і PATCH:
PUT замінює весь ресурс;
PATCH змінює лише передані поля.
Метод DELETE використовують для видалення ресурсу.
@Delete(':id')
remove(@Param('id') id: string) {
// ...
}Маршрут:
DELETE /tasks/1Якщо завдання не існує, контролер кидає NotFoundException:
throw new NotFoundException('Завдання не знайдено');NestJS перетворить це на HTTP-відповідь зі статусом 404 Not Found.
Для перевірки можна використовувати curl.
curl http://localhost:3000/taskscurl http://localhost:3000/tasks/1curl -X POST http://localhost:3000/tasks \
-H "Content-Type: application/json" \
-d '{"title":"Вивчити POST","completed":false}'curl -X PUT http://localhost:3000/tasks/1 \
-H "Content-Type: application/json" \
-d '{"title":"Оновлене завдання","completed":true}'curl -X PATCH http://localhost:3000/tasks/1 \
-H "Content-Type: application/json" \
-d '{"completed":false}'curl -X DELETE http://localhost:3000/tasks/1Маршрути з параметрами потрібно використовувати уважно. Наприклад:
@Get('statistics')
getStatistics() {
return { total: tasks.length };
}
@Get(':id')
findOne(@Param('id') id: string) {
// ...
}Запит GET /tasks/statistics має потрапити до маршруту statistics, а не сприйматися як пошук завдання з ідентифікатором statistics.
Статичні маршрути варто оголошувати перед параметризованими:
@Get('statistics')
getStatistics() {
// ...
}
@Get(':id')
findOne(@Param('id') id: string) {
// ...
}Маршрути GET /tasks і POST /tasks мають однаковий шлях, але це різні маршрути, оскільки HTTP-методи різні.
@Get()
findAll() {
// Отримання даних
}
@Post()
create() {
// Створення даних
}Запит GET не виконає метод, позначений @Post(), і навпаки.
Якщо метод використовує @Param('id'), у маршруті має бути :id:
@Get(':id')
findOne(@Param('id') id: string) {
// ...
}Без :id параметр не буде переданий.
Значення з @Param() є рядком:
@Delete(':id')
remove(@Param('id') id: string) {
// id має тип string
}Під час порівняння з числовим ідентифікатором використовуйте Number(id):
const taskId = Number(id);Якщо клієнт надсилає лише одне поле, для часткового оновлення потрібно використовувати PATCH. PUT призначений для повної заміни ресурсу.
Для JSON-тіла запиту потрібно вказати:
Content-Type: application/jsonБез цього сервер або клієнт може неправильно обробити тіло запиту.
Контролер об’єднує маршрути зі спільним префіксом.
@Get() обробляє запити для отримання даних.
@Post() створює новий ресурс.
@Put() повністю замінює ресурс.
@Patch() частково оновлює ресурс.
@Delete() видаляє ресурс.
@Param() отримує параметри з URL.
@Body() отримує дані з тіла запиту.
Значення параметрів URL надходять як рядки.
Для неіснуючого ресурсу можна використати NotFoundException.