сеньорчикОткрыть в Telegram
← вся теориятеория к собесу · FastAPI, Django и API

REST API: методы, коды ответов и дизайн ресурсов

REST: ресурсы, а не действия

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, остальные разбираются в тренажёре.

  1. #rest_design1 / 5
    Что означает «REST — stateless»?
    A)Клиент не может передавать никакого состояния на сервер
    B)Между клиентом и сервером запрещено держать TCP-соединение
    C)Сервер не хранит клиентскую сессию между запросами
    D)Сервер вообще не имеет базы данных и ничего не сохраняет
    показать ответ и разбор
    +C)Сервер не хранит клиентскую сессию между запросами

    // разбор: Stateless: сервер не держит сессионного состояния клиента между запросами — каждый запрос несёт всё нужное (токен, параметры), и любой инстанс может его обслужить. Это даёт горизонтальное масштабирование без липких сессий. Данные ресурсов, разумеется, хранятся в БД.

  2. #rest_design2 / 5
    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 предсказуемым для клиентов.

  3. #rest_design3 / 5
    Как в REST различают коллекцию и конкретный элемент?
    A)Элемент передают query-параметром вида ?id=42
    B)/users — коллекция, /users/42 — элемент коллекции
    C)Коллекцию берут через GET, а элемент — только через POST
    D)Разницы нет: и коллекция, и элемент живут по одному URL
    показать ответ и разбор
    +B)/users — коллекция, /users/42 — элемент коллекции

    // разбор: Коллекция и элемент — разные ресурсы с разными URL: GET /users отдаёт список, GET /users/42 — конкретного, DELETE /users/42 удаляет его. Идентификатор в пути адресует элемент. Это единообразие позволяет применять методы предсказуемо к обоим уровням.

  4. #rest_design4 / 5
    Как в REST принято именовать коллекцию пользователей в пути?
    A)Глаголом действия, который клиент собирается выполнить: /getAllUsers
    B)Слово выбирают произвольно — строгих соглашений по именованию в REST нет
    C)Существительное во множественном числе: /users
    D)Именем метода и сущности вместе через подчёркивание: /user_list_read
    показать ответ и разбор
    +C)Существительное во множественном числе: /users

    // разбор: В REST путь адресует ресурс, поэтому это существительное: коллекция — во множественном числе (/users), элемент — /users/{id}. Действие выражает HTTP-метод, а не путь. Единообразие имён (мн. число для коллекций, вложенность для связей) делает API предсказуемым.

  5. #rest_design5 / 5
    Что означает требование statelessness (отсутствие состояния) в REST?
    A)Все запросы обязаны быть строго последовательными и идти строго по одному
    B)Клиент не должен сохранять никакого состояния между обращениями к серверу
    C)Сервер вообще не имеет права хранить какие-либо данные, включая базу данных
    D)Каждый запрос самодостаточен — сервер не хранит контекст между запросами клиента
    показать ответ и разбор
    +D)Каждый запрос самодостаточен — сервер не хранит контекст между запросами клиента

    // разбор: Statelessness: сервер не держит клиентский контекст между запросами — каждый запрос несёт всё для его обработки (например, токен аутентификации вместо серверной сессии). Это даёт горизонтальное масштабирование (любой инстанс обслужит любой запрос) и устойчивость. Прикладные данные при этом спокойно живут в БД.

дальше

Теорию прочитали. Навык ставится повторением

В Сеньорчике эта подтема идёт в ежедневных сессиях: движок возвращает её, пока ответы не станут уверенными, и ведёт прогресс отдельно по каждой подтеме. Теория внутри тоже бесплатна, лимит только на количество вопросов в день.