Салют! Хочу тоже затронуть тему,
проектировать REST API и рассказать на своем примере
Знаете, что меня до сих пор выбивает из равновесия? Когда на ревью спрашиваешь разработчика: “почему эндпоинт называется именно так?” — и в ответ: “ну, так исторически сложилось” 🤯 За 10 лет я слышала это столько раз, что уже завела внутренний счётчик.
🚨
Давайте разберём REST API нормально — один раз, по-человечески, с примером.Сначала главное: REST — это не технология, это договорённостьREST — архитектурный стиль. Просто набор правил о том, как клиент и сервер общаются через HTTP. И первое правило, которое нарушают чаще всего — ресурсы именуются существительными, не глаголами.
❌
Так не надо:POST /getUser
POST /createOrder
GET /deleteProduct?id=5
✅
Так правильно:GET /users/{id}
POST /orders
DELETE /products/{id}
HTTP-методы сами несут смысл действия — GET получить, POST создать, PUT/PATCH обновить, DELETE удалить. Глагол в URL — это дублирование, которое потом запутает всех, включая вас саму через полгода.
💡
Живой пример: API интернет-магазинаЕсть товары, заказы, пользователи. Поехали.
Базовые операции:
GET /products — список товаров
GET /products/{id} — конкретный товар
POST /products — создать товар
PATCH /products/{id} — обновить часть данных
DELETE /products/{id} — удалить товар
Здесь сразу вопрос, который почти никогда не задают вслух:
PUT или PATCH?PUT — заменяет ресурс целиком и обязан быть идемпотентным — то есть хоть десять раз вызови с одними данными, результат одинаковый
PATCH — обновляет только то, что передали
На практике PATCH выигрывает почти всегда — никто не хочет слать весь объект ради изменения одного поля статуса.
Вложенные ресурсы — и вот тут начинается самое интересноеЗаказ принадлежит пользователю. Отражаем это в структуре:
GET /users/{userId}/orders — все заказы пользователя
GET /users/{userId}/orders/{orderId} — конкретный заказ
POST /users/{userId}/orders — создать заказНо если заказы нужны и сами по себе — например, в админке — добавляем отдельно:
GET /orders/{id}И вот моё личное правило, выстраданное на проектах:
Вложенность глубже двух уровней — тревожный сигнал. Если у вас
/users/{id}/orders/{orderId}/items/{itemId}/reviews — это не REST, это маршрут до боли.
Коды ответов — то, на что аналитики машут рукой зря“Разработчик разберётся” — нет. Или разберётся по-своему, и тогда фронт получает 200 с телом {"error": true} и тихо плачет.
Минимальный джентльменский набор:200 - Успешный GET, PATCH, PUT
201 - Успешный POST — ресурс создан
204 - Успешный DELETE — тело пустое
400 - Синтаксически сломанный запрос (битый JSON и т.п.)
401 - Не авторизован 403 - Авторизован, но нет прав 404 - Ресурс не найден 409 - Конфликт (дубль email, например)
422 - Запрос понят, но данные не прошли валидацию
500 - Ошибка сервера
Отдельно про 400 vs 422 — это путают постоянно. 400 — когда запрос синтаксически сломан, сервер вообще не смог его прочитать. 422 — запрос понятен, но внутри что-то не то: поле обязательное, формат не тот, логика не сходится. Для ошибок валидации форм почти всегда нужен именно 422.
И 401 vs 403 — классика жанра: 401 = “кто ты вообще?”, 403 = “знаю кто ты, но нет”.
Формат ошибки — договоритесь до начала разработкиЛучший момент для этого — старт проекта. Худший — когда фронт уже написал сорок обработчиков.
✅ Хорошо:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Поле email обязательно",
"field": "email"
}
}❌ Плохо:
Второй вариант — это не API, это квест.
{
"status": false,
"msg": "err"
}Версионирование — заложите сразуAPI когда-нибудь изменится. Поменяется логика, добавятся поля, что-то удалится.
Если не заложить версионирование с самого начала — первое же обновление превратится в боль для всех.
Самый простой и понятный способ:/api/v1/products
/api/v2/products
___________
Источник:
@ba_and_sa💙
BA|SA | 💬
BA|SA