REST API: методы, коды ответов и дизайн ресурсов
REST - общий язык, на котором договариваются фронт и бэкенд, и собес проверяет, чувствуешь ли ты его стиль: моделируешь ли данные ресурсами или лепишь RPC-эндпоинты с глаголами. По одному-двум путям в твоём API опытный ревьюер сразу понимает уровень.
Типовые формулировки: «спроектируй API для заказов», «почему /getUsers - плохо?», «что вернуть при создании ресурса».
Путь - существительное, действие - метод
REST моделирует данные как ресурсы: путь - существительное (/users, /users/1), а действие задаёт HTTP-метод. Глагол в пути (/getUsers, /deleteUser) - антипаттерн: он дублирует семантику метода, которую HTTP уже несёт. GET /users читает, DELETE /users/1 удаляет - путь остаётся именем ресурса.
Коллекция и элемент - разные ресурсы: GET /users отдаёт список, GET /users/42 - конкретного пользователя, id в пути адресует элемент. Это разделение и даёт предсказуемый, самоописательный API.
// Отсюда же вложенность: /users/42/orders - заказы конкретного пользователя, тоже существительные по цепочке.
- ресурс
- сущность, адресуемая URL-существительным
- коллекция/элемент
- /users против /users/42 - разные ресурсы
Stateless и коды создания
Stateless: сервер не хранит клиентскую сессию между запросами - каждый запрос несёт всё нужное, обычно токен. Раз состояния на сервере нет, запрос обслужит любой инстанс - вот откуда берётся горизонтальное масштабирование. Хранить сессию клиента на сервере эту возможность ломает.
Создание ресурса это 201 Created с заголовком Location, указывающим URL нового ресурса. 200 менее точен, 204 - успех без тела, 3xx - редиректы. Ответить 200 на создание - потерять семантику: клиент не узнает ни что создано, ни где это лежит.
// Точность кодов - не педантизм: по ним клиенты и прокси принимают решения о кэше, ретрае и навигации.
- stateless
- сервер не держит сессию клиента между запросами
- 201 Created
- код успешного создания ресурса, обычно с Location
Как отвечать: «Почему /getUsers - плохой дизайн?»
Потому что действие в REST выражает HTTP-метод, а не путь. Путь это имя ресурса, существительное: коллекция /users и элемент /users/42. Глагол getUsers дублирует семантику GET, которую протокол уже несёт, и толкает к RPC-стилю, где на каждое действие свой эндпоинт вместо предсказуемого набора методов над ресурсом. Правильно - GET /users для списка, POST /users для создания, GET /users/42 для одного. Так API самоописателен: по методу и пути сразу ясно, что происходит, и это же даёт единообразие для кэша и клиентов.
Названа суть (метод несёт действие, путь - ресурс), показан правильный набор и объяснён системный выигрыш - предсказуемость и кэшируемость, а не просто «так принято».
На чём валят
- −Глаголы в пути (/getUsers, /deleteUser) дублируют семантику метода - не REST-стиль.
- −Хранить сессию клиента на сервере ломает stateless и мешает горизонтальному масштабированию.
- −Отвечать 200 на создание вместо 201 с Location - теряется точность семантики.
- −Мешать коллекцию и элемент в одном пути, не адресуя конкретный ресурс через id.
Проверьте себя
Пять вопросов из банка по этой подтеме. Всего их 11, остальные разбираются в тренажёре.
- Что означает «REST — stateless»?A)Клиент не может передавать никакого состояния на серверB)Между клиентом и сервером запрещено держать TCP-соединениеC)Сервер не хранит клиентскую сессию между запросамиD)Сервер вообще не имеет базы данных и ничего не сохраняет
показать ответ и разбор
+C)Сервер не хранит клиентскую сессию между запросами// разбор: Stateless: сервер не держит сессионного состояния клиента между запросами — каждый запрос несёт всё нужное (токен, параметры), и любой инстанс может его обслужить. Это даёт горизонтальное масштабирование без липких сессий. Данные ресурсов, разумеется, хранятся в БД.
- POST /users успешно создал пользователя. Какой ответ по REST-семантике?A)201 Created с заголовком Location на новый ресурсB)302 Found с редиректом браузера на страницу нового профиляC)204 No Content, ведь клиенту тело ответа больше не нужноD)200 OK с телом созданного объекта и без каких-либо заголовков
показать ответ и разбор
+A)201 Created с заголовком Location на новый ресурс// разбор: Создание ресурса — 201 Created, обычно с заголовком Location, указывающим URL нового ресурса (и часто телом с самим объектом). 200 сгодится, но менее точен; 204 не несёт тела; 3xx — про редиректы. Точные коды делают API предсказуемым для клиентов.
- Как в REST различают коллекцию и конкретный элемент?A)Элемент передают query-параметром вида ?id=42B)/users — коллекция, /users/42 — элемент коллекцииC)Коллекцию берут через GET, а элемент — только через POSTD)Разницы нет: и коллекция, и элемент живут по одному URL
показать ответ и разбор
+B)/users — коллекция, /users/42 — элемент коллекции// разбор: Коллекция и элемент — разные ресурсы с разными URL: GET /users отдаёт список, GET /users/42 — конкретного, DELETE /users/42 удаляет его. Идентификатор в пути адресует элемент. Это единообразие позволяет применять методы предсказуемо к обоим уровням.
- Как в REST принято именовать коллекцию пользователей в пути?A)Глаголом действия, который клиент собирается выполнить: /getAllUsersB)Слово выбирают произвольно — строгих соглашений по именованию в REST нетC)Существительное во множественном числе: /usersD)Именем метода и сущности вместе через подчёркивание: /user_list_read
показать ответ и разбор
+C)Существительное во множественном числе: /users// разбор: В REST путь адресует ресурс, поэтому это существительное: коллекция — во множественном числе (/users), элемент — /users/{id}. Действие выражает HTTP-метод, а не путь. Единообразие имён (мн. число для коллекций, вложенность для связей) делает API предсказуемым.
- Что означает требование statelessness (отсутствие состояния) в REST?A)Все запросы обязаны быть строго последовательными и идти строго по одномуB)Клиент не должен сохранять никакого состояния между обращениями к серверуC)Сервер вообще не имеет права хранить какие-либо данные, включая базу данныхD)Каждый запрос самодостаточен — сервер не хранит контекст между запросами клиента
показать ответ и разбор
+D)Каждый запрос самодостаточен — сервер не хранит контекст между запросами клиента// разбор: Statelessness: сервер не держит клиентский контекст между запросами — каждый запрос несёт всё для его обработки (например, токен аутентификации вместо серверной сессии). Это даёт горизонтальное масштабирование (любой инстанс обслужит любой запрос) и устойчивость. Прикладные данные при этом спокойно живут в БД.
дальше
Теорию прочитали. Навык ставится повторением
В Сеньорчике эта подтема идёт в ежедневных сессиях: движок возвращает её, пока ответы не станут уверенными, и ведёт прогресс отдельно по каждой подтеме. Теория внутри тоже бесплатна, лимит только на количество вопросов в день.