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, остальные разбираются в тренажёре.
- Чем 401 отличается от 403?A)401 — не опознан, 403 — не допущенB)401 возвращает сервер, 403 — проксиC)401 временный, 403 постоянныйD)Разницы нет, коды взаимозаменяемы
показать ответ и разбор
+A)401 — не опознан, 403 — не допущен// разбор: 401 означает «я не знаю, кто ты»: токен отсутствует, протух или неверен, и клиенту нужно пройти аутентификацию заново. 403 — «я знаю, кто ты, но тебе сюда нельзя»: повторная авторизация не поможет, нужны другие права. Для интерфейса это два разных сценария поведения.
- Нужно вернуть список заказов, которых сотни тысяч. Что предусмотреть в контракте?A)Сжатие ответа на стороне сервераB)Пагинацию и параметры фильтрацииC)Увеличенный таймаут для клиентаD)Асинхронную выгрузку в файл
показать ответ и разбор
+B)Пагинацию и параметры фильтрации// разбор: Отдача всего набора разом кладёт и сервер, и клиента: растёт память, растёт время ответа, повторные запросы после обрыва начинаются с нуля. Постраничная выдача с фильтрами и стабильной сортировкой — базовое требование. Для действительно больших выгрузок сверх этого делают отдельный асинхронный сценарий.
- Клиент шлёт PUT с тремя полями из десяти. Что станет с остальными семью?A)Сохранят прежние значенияB)Будут затёрты умолчаниямиC)Вызовут ошибку валидации запросаD)Останутся, но будут помечены устаревшими
показать ответ и разбор
+B)Будут затёрты умолчаниями// разбор: PUT передаёт полное представление ресурса и замещает им прежнее, поэтому непереданные поля теряют свои значения. Это классическая авария интеграции: клиент думает, что обновляет три поля, а на деле обнуляет семь. Для частичного изменения существует PATCH — и в контракте это различие надо проговаривать явно.
- Партнёр предлагает передавать номер счёта в query-параметрах GET-запроса. Что возразить?A)Query-параметры имеют жёсткий лимит длиныB)Такие данные осядут в логах и историиC)GET не поддерживает передачу параметровD)Параметры придётся кодировать вручную
показать ответ и разбор
+B)Такие данные осядут в логах и истории// разбор: Строка запроса попадает в логи веб-сервера, прокси и системы мониторинга, сохраняется в истории браузера и в заголовке referer. Для чувствительных данных это утечка по умолчанию, даже при HTTPS. Такие значения передают в теле запроса, а лучше — заменяют на непрямой идентификатор.
- Сервис отдаёт 200 с телом, где написано «ошибка: клиент не найден». Чем это плохо?A)Тело ответа станет слишком большимB)Нарушается формат JSONC)Мониторинг сочтёт вызов успешнымD)Клиент не сможет разобрать ответ
показать ответ и разбор
+C)Мониторинг сочтёт вызов успешным// разбор: Код ответа — это машинный контракт: по нему работают метрики, алерты, политики повторов и прокси. Если ошибка приходит с кодом 200, доля ошибок в мониторинге остаётся нулевой при сломанной интеграции, а клиентские библиотеки не включают обработку сбоя. Разбирать текст тела приходится вручную.
дальше
Теорию прочитали. Навык ставится повторением
В Сеньорчике эта подтема идёт в ежедневных сессиях: движок возвращает её, пока ответы не станут уверенными, и ведёт прогресс отдельно по каждой подтеме. Теория внутри тоже бесплатна, лимит только на количество вопросов в день.