Пошук уроків, статей та іншого контенту
Навчитеся обирати коректні HTTP-статуси для успішних відповідей, помилок і асинхронних операцій.
HTTP-статус — це числовий код у відповіді сервера, який повідомляє клієнту, чим завершився запит.
Наприклад:
200 OK — запит успішно виконано;
201 Created — ресурс створено;
400 Bad Request — запит має некоректні дані;
404 Not Found — ресурс не знайдено;
500 Internal Server Error — на сервері сталася неочікувана помилка.
Статус важливий не лише для людини, яка читає відповідь. Frontend, мобільний застосунок або інший API-клієнт використовує його, щоб зрозуміти, чи була операція успішною і що робити далі.
Перша цифра коду визначає його групу:
1xx — інформаційні відповіді;
2xx — успішне виконання;
3xx — перенаправлення;
4xx — помилка на стороні клієнта;
5xx — помилка на стороні сервера.
У звичайних REST API найчастіше використовують статуси з груп 2xx, 4xx і 5xx.
Найпоширеніші статуси:
200 OK — операцію успішно виконано, відповідь зазвичай містить дані;
201 Created — новий ресурс успішно створено;
202 Accepted — запит прийнято, але операція ще виконується асинхронно;
204 No Content — операцію успішно виконано, але тіло відповіді відсутнє.
Ці статуси означають, що проблема пов’язана із запитом клієнта:
400 Bad Request — некоректний формат або значення даних;
401 Unauthorized — користувач не автентифікований;
403 Forbidden — користувач автентифікований, але не має потрібних прав;
404 Not Found — запитаний ресурс не існує;
409 Conflict — запит конфліктує з поточним станом ресурсу;
422 Unprocessable Entity — дані мають правильний формат, але не проходять перевірку бізнес-правил.
Ці статуси вказують на проблему під час обробки запиту на сервері:
500 Internal Server Error — неочікувана помилка;
502 Bad Gateway — сервер отримав некоректну відповідь від іншого сервера;
503 Service Unavailable — сервіс тимчасово недоступний.
У власному коді найчастіше потрібно явно використовувати 500 або відповідні винятки NestJS. Інші 5xx зазвичай стосуються інфраструктури або взаємодії між сервісами.
NestJS автоматично встановлює статус для стандартних HTTP-методів:
GET — 200 OK;
POST — 201 Created;
PATCH — 200 OK;
PUT — 200 OK;
DELETE — 200 OK.
Якщо потрібно змінити статус, використовуйте декоратор @HttpCode().
import {
Body,
Controller,
Delete,
Get,
HttpCode,
HttpStatus,
NotFoundException,
Param,
Post,
} from '@nestjs/common';
type Task = {
id: number;
title: string;
};
@Controller('tasks')
export class TasksController {
private readonly tasks: Task[] = [
{ id: 1, title: 'Вивчити HTTP-статуси' },
];
@Get()
findAll(): Task[] {
return this.tasks;
}
@Post()
create(@Body() body: { title: string }): Task {
const task: Task = {
id: this.tasks.length + 1,
title: body.title,
};
this.tasks.push(task);
// Для створення ресурсу NestJS за замовчуванням повертає 201.
return task;
}
@Delete(':id')
@HttpCode(HttpStatus.NO_CONTENT)
remove(@Param('id') id: string): void {
const taskIndex = this.tasks.findIndex((task) => task.id === Number(id));
if (taskIndex === -1) {
throw new NotFoundException('Завдання не знайдено');
}
this.tasks.splice(taskIndex, 1);
// Для 204 тіло відповіді має бути порожнім.
}
}У цьому прикладі:
GET /tasks повертає 200;
POST /tasks повертає 201;
DELETE /tasks/:id повертає 204;
якщо завдання не знайдено, NestJS повертає 404.
Для помилок клієнта NestJS має готові класи винятків:
BadRequestException — 400;
UnauthorizedException — 401;
ForbiddenException — 403;
NotFoundException — 404;
ConflictException — 409;
UnprocessableEntityException — 422;
InternalServerErrorException — 500.
Приклад:
import {
ConflictException,
Controller,
Post,
} from '@nestjs/common';
@Controller('users')
export class UsersController {
private readonly emails = new Set(['user@example.com']);
@Post()
createUser(): { message: string } {
const email = 'user@example.com';
if (this.emails.has(email)) {
throw new ConflictException('Користувач із таким email уже існує');
}
this.emails.add(email);
return {
message: 'Користувача створено',
};
}
}Якщо виконати POST /users, контролер поверне статус 409, оскільки користувач із таким email уже існує.
NestJS також сформує JSON-відповідь приблизно такого вигляду:
{
"statusCode": 409,
"message": "Користувач із таким email уже існує",
"error": "Conflict"
}Точний формат може змінюватися залежно від налаштувань застосунку та глобальних фільтрів винятків.
Ці статуси часто плутають, але вони описують різні ситуації.
400 Bad RequestВикористовуйте, коли сам запит некоректний:
відсутнє обов’язкове поле;
значення має неправильний тип;
JSON має некоректний формат;
параметр не відповідає очікуваному формату.
import {
BadRequestException,
Body,
Controller,
Post,
} from '@nestjs/common';
@Controller('products')
export class ProductsController {
@Post()
create(@Body() body: { name?: string }) {
if (!body.name || body.name.trim() === '') {
throw new BadRequestException('Поле name є обов’язковим');
}
return {
name: body.name,
};
}
}404 Not FoundВикористовуйте, коли запит має правильний формат, але ресурс із вказаним ідентифікатором не знайдено.
Наприклад, клієнт надсилає GET /tasks/999, але завдання з таким ідентифікатором не існує.
409 ConflictВикористовуйте, коли запит сам по собі правильний, але його неможливо виконати через поточний стан даних.
Приклади:
реєстрація email, який уже використовується;
створення ресурсу з ідентифікатором, що вже існує;
зміна ресурсу, який одночасно змінив інший користувач.
201Для POST, який створює новий ресурс, коректним статусом є 201 Created.
import {
Body,
Controller,
HttpCode,
HttpStatus,
Post,
} from '@nestjs/common';
@Controller('articles')
export class ArticlesController {
@Post()
@HttpCode(HttpStatus.CREATED)
create(@Body() body: { title: string }) {
return {
id: 1,
title: body.title,
};
}
}Для POST декоратор @HttpCode(HttpStatus.CREATED) у цьому прикладі не є обов’язковим, оскільки NestJS і так використовує 201. Явне зазначення статусу може зробити намір коду зрозумілішим.
201 слід використовувати саме тоді, коли внаслідок запиту створено ресурс. Якщо POST лише запускає дію без створення ресурсу, може бути доречнішим 200 або 202.
204Якщо ресурс успішно видалено і клієнту не потрібно повертати дані, використовуйте 204 No Content.
import {
Controller,
Delete,
HttpCode,
HttpStatus,
Param,
} from '@nestjs/common';
@Controller('files')
export class FilesController {
@Delete(':id')
@HttpCode(HttpStatus.NO_CONTENT)
deleteFile(@Param('id') id: string): void {
console.log(`Файл ${id} видалено`);
// Не повертаємо об'єкт або повідомлення.
}
}Відповідь із кодом 204 не повинна містити тіло. Якщо потрібно повернути клієнту повідомлення або результат операції, використовуйте 200.
202Деякі операції не завершуються під час обробки одного HTTP-запиту. Наприклад:
формування великого звіту;
імпорт великого файлу;
надсилання масових повідомлень;
обробка завдання у фоновому процесі.
У такому випадку сервер може повернути 202 Accepted. Це означає:
Сервер прийняв запит, але результат ще не готовий.
202 не означає, що операція вже успішно завершилася. Він лише підтверджує прийняття запиту.
import {
Body,
Controller,
HttpCode,
HttpStatus,
Post,
} from '@nestjs/common';
@Controller('reports')
export class ReportsController {
@Post()
@HttpCode(HttpStatus.ACCEPTED)
createReport(@Body() body: { month: string }) {
const jobId = 'report-job-123';
// У реальному застосунку тут запускається фонова обробка.
console.log(`Формування звіту за ${body.month}: ${jobId}`);
return {
jobId,
status: 'pending',
};
}
}Клієнт отримує ідентифікатор завдання та може пізніше перевірити його стан окремим запитом.
Не використовуйте 202, якщо операція вже завершилася до моменту формування відповіді. Для завершеної операції використовуйте відповідний статус 200, 201 або 204.
Статус та тіло відповіді доповнюють одне одного:
статус повідомляє про результат на рівні протоколу;
тіло містить додаткові дані або опис помилки.
Наприклад, успішна відповідь:
{
"id": 10,
"title": "Нова стаття"
}зі статусом 201 означає, що статтю створено.
Помилкова відповідь:
{
"statusCode": 404,
"message": "Статтю не знайдено",
"error": "Not Found"
}зі статусом 404 означає, що клієнт правильно звернувся до API, але потрібного ресурсу немає.
Не варто повертати статус 200 для всіх ситуацій і записувати помилку лише в поле success:
{
"success": false,
"message": "Статтю не знайдено"
}Такий підхід змушує кожного клієнта аналізувати тіло відповіді замість використання стандартного HTTP-статусу.
Перед поверненням відповіді поставте собі такі запитання:
Операція успішно завершилася?
Так — використовуйте статус із групи 2xx.
Ресурс було створено?
Так — 201 Created.
Операція прийнята, але ще виконується?
Так — 202 Accepted.
Операція завершилася без даних для повернення?
Так — 204 No Content.
Клієнт надіслав некоректні дані?
Використовуйте 400 або 422.
Потрібний ресурс не існує?
Використовуйте 404.
Запит суперечить поточному стану даних?
Використовуйте 409.
Помилка виникла через проблему самого сервера?
Використовуйте 500 або інший відповідний 5xx.
200 для помилкиЯкщо ресурс не знайдено, не повертайте 200 із повідомленням про помилку. Використовуйте NotFoundException і статус 404.
500 для некоректних данихПомилка в даних клієнта не є помилкою сервера. Для неї використовуйте 400, 409 або 422 залежно від ситуації.
201 без створення ресурсу201 призначений для створення ресурсу. Для звичайного читання даних використовуйте 200.
204Статус 204 означає відсутність тіла відповіді. Якщо потрібно повернути JSON, використовуйте 200.
401 і 403401 — сервер не знає, хто виконує запит;
403 — сервер знає користувача, але забороняє йому виконувати операцію.
Повідомлення помилки має допомагати клієнту зрозуміти проблему, але не повинно розкривати внутрішні деталі сервера. Наприклад, клієнту не потрібно бачити stack trace або текст SQL-помилки.
HTTP-статус описує результат обробки запиту.
200 використовують для успішного отримання або зміни даних.
201 означає створення ресурсу.
202 означає прийняття асинхронної операції, яка ще не завершилася.
204 означає успішну операцію без тіла відповіді.
400 призначений для некоректного запиту.
404 — ресурс не знайдено.
409 — конфлікт із поточним станом даних.
5xx використовують для помилок сервера.
У NestJS готові класи винятків автоматично формують відповідний статус.
Декоратор @HttpCode() дає змогу змінити статус успішної відповіді.