сеньорчикОткрыть в Telegram
← вся теориятеория к собесу · Интеграции

REST и HTTP

REST и HTTP

Сердце собеса системного аналитика. Гонять будут по методам и кодам ответа, но настоящий вопрос за всем этим один: понимаешь ли ты, что код ответа - машинный контракт, а не украшение для разработчика.

Стержень: метод задаёт смысл операции, код ответа говорит клиенту, как реагировать. Всё остальное вытекает отсюда - и кэширование, и повторы, и метрики, и то, какой экран увидит пользователь.

// Формулировки: «чем PUT отличается от PATCH?», «какой код вернёшь?», «как отдать список из миллиона записей?»

Методы и их смысл

GET объявлен безопасным: он не меняет состояние системы. Из этого обещания растут вполне материальные последствия - браузер имеет право закэшировать ответ, прокси может повторить запрос, поисковый робот способен пройти по ссылке сам. Меняющий состояние GET - ошибка проектирования, и обнаруживается она обычно так: робот прошёл по всем ссылкам «удалить» и вычистил половину каталога.

PUT передаёт полное представление ресурса и замещает им прежнее. Ключевое слово - полное: непереданные поля не остаются как были, они обнуляются. Отсюда классическая авария, которую видел почти каждый: клиент шлёт PUT с тремя полями из десяти, чтобы «поправить телефон», и молча стирает семь остальных - адрес, комментарий, реквизиты.

PATCH меняет частично и именно для такой правки и предназначен. Разница между этими двумя методами - не вкусовщина, а два разных договора о том, что происходит с непереданными полями.

// Идемпотентность важнее, чем кажется на бумаге. Сеть ненадёжна, ответ может потеряться уже на обратном пути, и у клиента должно быть право повторить запрос, не рискуя списать деньги дважды. Именно поэтому семантика метода - это в первую очередь ответ на вопрос «безопасно ли повторить».

Коды ответа как контракт

Каждый код - это инструкция клиенту, что делать дальше. 400 означает «запрос сформирован неверно, повторять бессмысленно, чини у себя». 401 - «я не знаю, кто ты», и клиент идёт получать токен заново. 403 - «знаю, кто ты, но тебе нельзя», и переавторизация тут не поможет ни на грамм. 404 - ресурса нет. 409 - конфликт состояния, кто-то успел раньше. Всё, что начинается с пятёрки, - сбой на нашей стороне, и повторить имеет смысл.

Различие 401 и 403 - не педантизм, а два разных экрана в интерфейсе и две разные ветки в клиентском коде. Перепутав их, ты отправишь человека переавторизовываться по кругу там, где ему просто не выдали доступ.

Отдельный грех - отдавать ошибку с кодом 200 и признаком провала внутри тела. Мониторинг в этот момент показывает нулевую долю ошибок при полностью сломанной интеграции. Клиентские библиотеки считают вызов успешным и идут дальше с пустыми данными. Политики повторов не срабатывают, потому что повторять вроде бы нечего.

// И клиенту нельзя разбирать текст сообщения об ошибке: формулировку однажды поправят ради красоты, и интеграция сломается без единого изменения в контракте. Правильный набор - код по ситуации, стабильный машиночитаемый признак ошибки в теле и человеческий текст рядом, отдельным полем, для показа пользователю.

Большие списки и долгие операции

Список отдают постранично, с фильтрами и стабильной сортировкой. Способов пагинации два, и они не равнозначны.

Нумерация страниц через смещение ломается на живых данных. Клиент прочитал первые двадцать записей и просит следующие двадцать. Пока он читал, наверх добавились три новые - и теперь записи, которые были на позициях 18, 19 и 20, съехали на 21, 22 и 23. Клиент увидит их второй раз, а три записи из старой выдачи не увидит вовсе. Пагинация по курсору - «отдай следующие двадцать после вот этой записи» - от такого свободна.

Операцию, которая идёт минуты, не держат в синхронном запросе. Соединение оборвётся на прокси или балансировщике по их собственному таймауту, а клиент в момент обрыва не будет знать главного - выполнилась операция или нет.

// Стандартный приём: сервер отвечает кодом 202, что означает «задачу принял, результата пока нет», и отдаёт идентификатор задачи. Клиент дальше опрашивает статус или получает уведомление. И обязательно нужен метод проверки статуса по ключу клиента, иначе после обрыва он снова окажется в неведении.

202 Accepted
код «задача принята в обработку, результата пока нет». Обязательно сопровождается идентификатором, по которому потом спрашивают статус

Как отвечать: «Сервис отдаёт 200 с телом error: not found. Что скажешь?»

Верну на доработку: здесь должен быть 404. Код ответа - это машинный контракт, по нему работают метрики, алерты, политики повторов и промежуточные прокси, и ни один из них в тело не заглядывает. Если ошибка приходит с кодом 200, доля ошибок в мониторинге остаётся нулевой при полностью сломанной интеграции, а клиентские библиотеки не включают обработку сбоя и идут дальше с пустыми данными. Разбирать текст тела клиенту тоже нельзя - формулировку однажды поправят, и интеграция сломается без изменения контракта. Правильно так: код по ситуации, стабильный машиночитаемый признак ошибки в теле и отдельным полем человеческий текст для показа пользователю.

Кандидат объясняет через последствия для мониторинга и повторов, а не ссылкой на «так принято». Именно это отличает человека, который разбирал инцидент, от человека, читавшего гайд по REST.

На чём валятся

  • − Отдают ошибку с кодом 200 и ослепляют мониторинг: интеграция лежит, графики зелёные.
  • − Шлют PUT с частью полей, молча затирая остальные.
  • − Передают чувствительные данные в параметрах адреса - они оседают в логах, истории браузера и заголовке перехода.
  • − Меняют состояние в GET-запросе и однажды получают массовое удаление от робота.
  • − Держат минутную операцию в синхронном вызове и упираются в таймаут прокси.

Проверьте себя

Пять вопросов из банка по этой подтеме. Всего их 12, остальные разбираются в тренажёре.

  1. #ana_int_rest1 / 5
    Чем 401 отличается от 403?
    A)401 — не опознан, 403 — не допущен
    B)401 возвращает сервер, 403 — прокси
    C)401 временный, 403 постоянный
    D)Разницы нет, коды взаимозаменяемы
    показать ответ и разбор
    +A)401 — не опознан, 403 — не допущен

    // разбор: 401 означает «я не знаю, кто ты»: токен отсутствует, протух или неверен, и клиенту нужно пройти аутентификацию заново. 403 — «я знаю, кто ты, но тебе сюда нельзя»: повторная авторизация не поможет, нужны другие права. Для интерфейса это два разных сценария поведения.

  2. #ana_int_rest2 / 5
    Нужно вернуть список заказов, которых сотни тысяч. Что предусмотреть в контракте?
    A)Сжатие ответа на стороне сервера
    B)Пагинацию и параметры фильтрации
    C)Увеличенный таймаут для клиента
    D)Асинхронную выгрузку в файл
    показать ответ и разбор
    +B)Пагинацию и параметры фильтрации

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

  3. #ana_int_rest3 / 5
    Клиент шлёт PUT с тремя полями из десяти. Что станет с остальными семью?
    A)Сохранят прежние значения
    B)Будут затёрты умолчаниями
    C)Вызовут ошибку валидации запроса
    D)Останутся, но будут помечены устаревшими
    показать ответ и разбор
    +B)Будут затёрты умолчаниями

    // разбор: PUT передаёт полное представление ресурса и замещает им прежнее, поэтому непереданные поля теряют свои значения. Это классическая авария интеграции: клиент думает, что обновляет три поля, а на деле обнуляет семь. Для частичного изменения существует PATCH — и в контракте это различие надо проговаривать явно.

  4. #ana_int_rest4 / 5
    Партнёр предлагает передавать номер счёта в query-параметрах GET-запроса. Что возразить?
    A)Query-параметры имеют жёсткий лимит длины
    B)Такие данные осядут в логах и истории
    C)GET не поддерживает передачу параметров
    D)Параметры придётся кодировать вручную
    показать ответ и разбор
    +B)Такие данные осядут в логах и истории

    // разбор: Строка запроса попадает в логи веб-сервера, прокси и системы мониторинга, сохраняется в истории браузера и в заголовке referer. Для чувствительных данных это утечка по умолчанию, даже при HTTPS. Такие значения передают в теле запроса, а лучше — заменяют на непрямой идентификатор.

  5. #ana_int_rest5 / 5
    Сервис отдаёт 200 с телом, где написано «ошибка: клиент не найден». Чем это плохо?
    A)Тело ответа станет слишком большим
    B)Нарушается формат JSON
    C)Мониторинг сочтёт вызов успешным
    D)Клиент не сможет разобрать ответ
    показать ответ и разбор
    +C)Мониторинг сочтёт вызов успешным

    // разбор: Код ответа — это машинный контракт: по нему работают метрики, алерты, политики повторов и прокси. Если ошибка приходит с кодом 200, доля ошибок в мониторинге остаётся нулевой при сломанной интеграции, а клиентские библиотеки не включают обработку сбоя. Разбирать текст тела приходится вручную.

дальше

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

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