← все темы
Проектирование API
Вопросов с разбором: 23. В боте эти же карточки приходят по расписанию повторений.
1 Блок 1 из 5: REST — Что такое REST и какие у него принципы? 🔥
REST (Representational State Transfer) — архитектурный стиль Роя Филдинга для распределённых систем. На практике «REST API» — это HTTP API, построенный вокруг ресурсов.
Принципы (ограничения):
- Клиент — сервер: интерфейс и хранение данных разделены.
- Stateless: каждый запрос содержит всё нужное, сервер не хранит контекст клиента между запросами.
- Кэшируемость: ответы явно помечаются кэшируемыми или нет.
- Единый интерфейс: ресурсы по URL, действия — HTTP-методами, представления (JSON), самоописываемые сообщения, гипермедиа (HATEOAS).
- Многоуровневость: между клиентом и сервером могут быть прокси, кэши, балансировщики.
- Код по требованию (необязательно).
Суть на практике: существительные в URL, глаголы — это HTTP-методы, правильные статус-коды, отсутствие серверных сессий.
Принципы (ограничения):
- Клиент — сервер: интерфейс и хранение данных разделены.
- Stateless: каждый запрос содержит всё нужное, сервер не хранит контекст клиента между запросами.
- Кэшируемость: ответы явно помечаются кэшируемыми или нет.
- Единый интерфейс: ресурсы по URL, действия — HTTP-методами, представления (JSON), самоописываемые сообщения, гипермедиа (HATEOAS).
- Многоуровневость: между клиентом и сервером могут быть прокси, кэши, балансировщики.
- Код по требованию (необязательно).
Суть на практике: существительные в URL, глаголы — это HTTP-методы, правильные статус-коды, отсутствие серверных сессий.
2 Блок 1 из 5: REST — Как правильно именовать ресурсы и строить URL?
- Существительные во множественном числе, а не глаголы:
- Коллекция и элемент:
- Вложенность для принадлежности, не глубже 1–2 уровней:
- Нижний регистр и дефисы:
- Фильтры, сортировка, пагинация — в query-параметрах:
- Версия — в начале пути:
Действия, которые плохо ложатся на CRUD, оформляют как подресурс или «ресурс-действие»:
Второй вариант чище: у возврата появляется свой id, статус и история.
/orders, а не /getOrders.- Коллекция и элемент:
/orders и /orders/42.- Вложенность для принадлежности, не глубже 1–2 уровней:
/users/7/orders.- Нижний регистр и дефисы:
/payment-methods.- Фильтры, сортировка, пагинация — в query-параметрах:
/orders?status=paid&sort=-created_at&limit=20.- Версия — в начале пути:
/v1/orders.Действия, которые плохо ложатся на CRUD, оформляют как подресурс или «ресурс-действие»:
POST /orders/42/cancel # действие над заказом
POST /orders/42/refunds # создать возврат — новый ресурс
Второй вариант чище: у возврата появляется свой id, статус и история.
3 Блок 1 из 5: REST — Как CRUD ложится на HTTP-методы и чем PUT отличается от PATCH? 🔥
GET /orders список 200
POST /orders создать 201 + Location: /orders/42
GET /orders/42 получить 200 / 404
PUT /orders/42 заменить целиком 200 / 204
PATCH /orders/42 изменить частично 200 / 204
DELETE /orders/42 удалить 204 / 404
PUT — клиент присылает полное представление ресурса. Отсутствующее поле означает «очистить». Идемпотентен.
PATCH — клиент присылает только изменения. В общем случае не идемпотентен.
PUT /users/7 {"name": "Аня", "email": "a@x.ru", "phone": null}
PATCH /users/7 {"phone": "+79990001122"}Форматы PATCH: JSON Merge Patch (RFC 7396: прислали поле — заменили, прислали
null — удалили) и JSON Patch (RFC 6902: список операций add/remove/replace).
4 Блок 1 из 5: REST — Какие статус-коды возвращать из API в типичных ситуациях? 🔥
-
-
-
-
-
-
-
-
-
-
-
-
Антипаттерн: всегда
200 OK — успешный GET, PUT, PATCH с телом.-
201 Created — ресурс создан, плюс заголовок Location.-
202 Accepted — задача принята в фоновую обработку, результат будет позже.-
204 No Content — успех без тела (DELETE).-
400 Bad Request — невалидный JSON, не тот тип параметра.-
401 Unauthorized — нет или неверный токен.-
403 Forbidden — токен валиден, но прав нет.-
404 Not Found — ресурса нет (или скрываем его существование от чужих).-
409 Conflict — конфликт состояния: дубликат, устаревшая версия, недопустимый переход статуса.-
422 Unprocessable Entity — синтаксис верный, но данные не прошли валидацию (FastAPI использует его по умолчанию).-
429 Too Many Requests — превышен лимит, плюс Retry-After.-
500 — непредвиденная ошибка; 503 — временно недоступен.Антипаттерн: всегда
200 и {"success": false} в теле — ломает кэши, ретраи, мониторинг и клиентские библиотеки.
5 Блок 1 из 5: REST — Как оформлять ошибки в API?
Ошибки должны быть единообразными, машиночитаемыми и понятными человеку. Стандарт — Problem Details (RFC 9457, ранее RFC 7807),
Правила:
- стабильный машинный код ошибки — клиент ветвится по нему, а не по тексту;
- ошибки валидации — по полям;
- никаких стек-трейсов, SQL и внутренних деталей в ответе;
-
Content-Type: application/problem+json:HTTP/1.1 422 Unprocessable Entity
Content-Type: application/problem+json
{
"type": "https://api.example.com/errors/validation",
"title": "Данные не прошли проверку",
"status": 422,
"detail": "Количество должно быть больше нуля",
"instance": "/orders",
"errors": [{"field": "qty", "code": "min_value"}]
}
Правила:
- стабильный машинный код ошибки — клиент ветвится по нему, а не по тексту;
- ошибки валидации — по полям;
- никаких стек-трейсов, SQL и внутренних деталей в ответе;
-
request_id в ответе или заголовке, чтобы найти запрос в логах.
6 Блок 2 из 5: Проектирование — Чем отличается пагинация offset и cursor? 🔥
Offset/limit:
- ✅ просто, можно перейти на любую страницу, легко показать общее количество;
- ❌ на больших offset медленно: БД читает и отбрасывает все предыдущие строки;
- ❌ при вставке и удалении записи «съезжают»: дубли или пропуски между страницами.
Cursor (keyset):
- ✅ стабильная скорость на любой глубине (работает по индексу);
- ✅ нет дублей и пропусков при изменении данных;
- ❌ нельзя перейти сразу на страницу N; курсор непрозрачен.
Когда что: админки и небольшие таблицы — offset; ленты, бесконечный скролл, большие таблицы и публичные API — cursor. Сортировка обязательно с уникальным ключом (
GET /orders?limit=20&offset=40 → LIMIT 20 OFFSET 40.- ✅ просто, можно перейти на любую страницу, легко показать общее количество;
- ❌ на больших offset медленно: БД читает и отбрасывает все предыдущие строки;
- ❌ при вставке и удалении записи «съезжают»: дубли или пропуски между страницами.
Cursor (keyset):
GET /orders?limit=20&after=eyJpZCI6MTAwfQSELECT * FROM orders
WHERE (created_at, id) < (:last_created_at, :last_id)
ORDER BY created_at DESC, id DESC
LIMIT 20;
- ✅ стабильная скорость на любой глубине (работает по индексу);
- ✅ нет дублей и пропусков при изменении данных;
- ❌ нельзя перейти сразу на страницу N; курсор непрозрачен.
Когда что: админки и небольшие таблицы — offset; ленты, бесконечный скролл, большие таблицы и публичные API — cursor. Сортировка обязательно с уникальным ключом (
id) на конце, иначе порядок недетерминирован.
7 Блок 2 из 5: Проектирование — Как версионировать API? 🔥
Способы:
- В пути:
- В заголовке:
- В query:
- По дате (как у Stripe):
Главное — не способ, а политика:
- новая мажорная версия только для ломающих изменений;
- совместимые изменения (новое необязательное поле, новый эндпоинт) — без новой версии;
- старую версию объявляют устаревшей (заголовки
- В пути:
/v1/orders — самый распространённый: видно, легко маршрутизировать и кэшировать.- В заголовке:
Accept: application/vnd.example.v2+json или API-Version: 2 — чистые URL, но сложнее отлаживать.- В query:
?version=2 — просто, но засоряет параметры.- По дате (как у Stripe):
Stripe-Version: 2024-06-20, версия закрепляется за клиентом.Главное — не способ, а политика:
- новая мажорная версия только для ломающих изменений;
- совместимые изменения (новое необязательное поле, новый эндпоинт) — без новой версии;
- старую версию объявляют устаревшей (заголовки
Deprecation/Sunset), дают срок и следят, кто ещё ей пользуется.
8 Блок 2 из 5: Проектирование — Какие изменения API ломают обратную совместимость?
Ломающие:
- удалить или переименовать поле, эндпоинт, параметр;
- изменить тип поля (
- сделать необязательное поле обязательным во входных данных;
- ужесточить валидацию;
- изменить смысл статус-кода или значения enum;
- изменить семантику поведения (ресурс перестал создаваться синхронно).
Безопасные:
- добавить новый эндпоинт;
- добавить необязательный параметр или поле во входных данных;
- добавить поле в ответ.
Нюанс: добавление значения в enum или поля в ответ безопасно только для «терпимых» клиентов (принцип Постеля). Документируйте, что клиент должен игнорировать неизвестные поля и значения.
- удалить или переименовать поле, эндпоинт, параметр;
- изменить тип поля (
"42" → 42) или формат (дата, деньги);- сделать необязательное поле обязательным во входных данных;
- ужесточить валидацию;
- изменить смысл статус-кода или значения enum;
- изменить семантику поведения (ресурс перестал создаваться синхронно).
Безопасные:
- добавить новый эндпоинт;
- добавить необязательный параметр или поле во входных данных;
- добавить поле в ответ.
Нюанс: добавление значения в enum или поля в ответ безопасно только для «терпимых» клиентов (принцип Постеля). Документируйте, что клиент должен игнорировать неизвестные поля и значения.
9 Блок 2 из 5: Проектирование — Что такое идемпотентность API и как работает Idempotency-Key? 🔥
Проблема: клиент отправил
Решение: клиент генерирует уникальный ключ на операцию и передаёт его в заголовке:
Что делает сервер:
1. Ищет ключ в хранилище (таблица с уникальным индексом или Redis).
2. Нет ключа — атомарно резервирует его, выполняет операцию, сохраняет ответ.
3. Ключ есть и операция завершена — возвращает сохранённый ответ, не выполняя операцию заново.
4. Ключ есть, но операция ещё идёт —
5. Тот же ключ с другим телом — ошибка (
Детали: ключ хранят ограниченное время (например, 24 часа), привязывают к пользователю, резервирование делают атомарно (
POST /payments, ответ потерялся по таймауту. Платёж прошёл или нет? Повторить — рискуем списать дважды.Решение: клиент генерирует уникальный ключ на операцию и передаёт его в заголовке:
POST /payments
Idempotency-Key: 6f1c2b8e-7e9a-4a0f-9a55-1d2b3c4d5e6f
Что делает сервер:
1. Ищет ключ в хранилище (таблица с уникальным индексом или Redis).
2. Нет ключа — атомарно резервирует его, выполняет операцию, сохраняет ответ.
3. Ключ есть и операция завершена — возвращает сохранённый ответ, не выполняя операцию заново.
4. Ключ есть, но операция ещё идёт —
409 Conflict.5. Тот же ключ с другим телом — ошибка (
422).Детали: ключ хранят ограниченное время (например, 24 часа), привязывают к пользователю, резервирование делают атомарно (
INSERT ... ON CONFLICT DO NOTHING). Так устроены API Stripe и многих платёжных систем.
10 Блок 2 из 5: Проектирование — Как в API обрабатывать долгие операции?
Если операция идёт дольше пары секунд (отчёт, импорт, генерация видео), держать HTTP-запрос открытым плохо: таймауты прокси, занятые воркеры, обрывы связи.
Паттерн асинхронной операции:
- работа уходит в фоновую очередь (Celery, Kafka);
- клиент опрашивает статус или получает уведомление: webhook, SSE, WebSocket;
- у задачи явные статусы:
- создание задачи делают идемпотентным, чтобы повтор не запустил вторую.
Паттерн асинхронной операции:
POST /reports → 202 Accepted
Location: /reports/jobs/77
GET /reports/jobs/77 → 200 {"status": "running", "progress": 40}
GET /reports/jobs/77 → 200 {"status": "done", "result_url": "/reports/77.csv"}
- работа уходит в фоновую очередь (Celery, Kafka);
- клиент опрашивает статус или получает уведомление: webhook, SSE, WebSocket;
- у задачи явные статусы:
pending, running, done, failed (с причиной);- создание задачи делают идемпотентным, чтобы повтор не запустил вторую.
11 Блок 2 из 5: Проектирование — Как проектировать фильтрацию, сортировку и выбор полей?
GET /orders?status=paid&created_after=2026-01-01&sort=-created_at,id&fields=id,total&limit=50
- Фильтры — простые параметры по полям (
status=paid), диапазоны через суффиксы (created_after, price_min) или операторы (price[gte]=100).- Сортировка —
sort=-created_at: минус означает «по убыванию».- Выбор полей —
fields=id,total, чтобы не гонять лишние данные.- Связанные данные —
expand=customer или include=items вместо N запросов.Важно на бэкенде:
- разрешать сортировку и фильтры только по белому списку полей — иначе SQL-инъекции и тяжёлые запросы без индексов;
- ограничивать
limit сверху;- под частые фильтры заводить индексы.
12 Блок 3 из 5: Аутентификация и защита — Чем аутентификация отличается от авторизации? 🔥
- Аутентификация (authentication, AuthN) — кто вы? Проверка личности: пароль, токен, сертификат, OTP. Ошибка —
- Авторизация (authorization, AuthZ) — что вам можно? Проверка прав на действие или ресурс. Ошибка —
Сначала аутентификация, потом авторизация.
Модели авторизации:
- RBAC — по ролям (admin, manager, user);
- ABAC — по атрибутам (владелец ресурса, отдел, время);
- проверки на уровне объекта: «пользователь видит только свои заказы».
Частая уязвимость — IDOR / BOLA:
401 Unauthorized.- Авторизация (authorization, AuthZ) — что вам можно? Проверка прав на действие или ресурс. Ошибка —
403 Forbidden.Сначала аутентификация, потом авторизация.
Модели авторизации:
- RBAC — по ролям (admin, manager, user);
- ABAC — по атрибутам (владелец ресурса, отдел, время);
- проверки на уровне объекта: «пользователь видит только свои заказы».
Частая уязвимость — IDOR / BOLA:
GET /orders/42 отдаёт чужой заказ, потому что проверили только, что пользователь залогинен. Правильно — фильтровать по владельцу: Order.objects.get(id=42, user=request.user).
13 Блок 3 из 5: Аутентификация и защита — Чем отличаются сессии и токены?
Сессии (stateful): после логина сервер создаёт запись сессии (в БД или Redis), а клиенту отдаёт её id в cookie.
- ✅ сессию легко отозвать — удалить запись;
- ✅ в cookie только случайный id;
- ❌ хранилище сессий нужно на каждом запросе, его нужно масштабировать;
- ❌ cookie неудобны для мобильных клиентов и других доменов; нужна защита от CSRF.
Токены (часто stateless, JWT): сервер выдаёт подписанный токен с данными пользователя, клиент шлёт его в
- ✅ проверяется без обращения к хранилищу — удобно для микросервисов;
- ✅ подходит для мобильных приложений и межсервисных вызовов;
- ❌ отозвать до истечения срока сложно → короткий срок жизни плюс refresh-токены или чёрный список.
Практика: веб-приложение на одном домене — сессии; публичный API, мобильные клиенты, микросервисы — токены.
- ✅ сессию легко отозвать — удалить запись;
- ✅ в cookie только случайный id;
- ❌ хранилище сессий нужно на каждом запросе, его нужно масштабировать;
- ❌ cookie неудобны для мобильных клиентов и других доменов; нужна защита от CSRF.
Токены (часто stateless, JWT): сервер выдаёт подписанный токен с данными пользователя, клиент шлёт его в
Authorization: Bearer.- ✅ проверяется без обращения к хранилищу — удобно для микросервисов;
- ✅ подходит для мобильных приложений и межсервисных вызовов;
- ❌ отозвать до истечения срока сложно → короткий срок жизни плюс refresh-токены или чёрный список.
Практика: веб-приложение на одном домене — сессии; публичный API, мобильные клиенты, микросервисы — токены.
14 Блок 3 из 5: Аутентификация и защита — Как устроен JWT и какие у него подводные камни? 🔥
JWT (JSON Web Token) — три части в base64url через точку:
- Payload не зашифрован, а только подписан: прочитать может любой, подделать без ключа нельзя. Секреты в JWT не кладут.
- HS256 — общий секрет (подписывает и проверяет один сервис); RS256/ES256 — подписывает приватный ключ, проверяют все по публичному (удобно в микросервисах).
Access и refresh: короткий access-токен (5–15 минут) на каждый запрос и долгий refresh-токен, которым получают новый access. Refresh хранится на сервере и его можно отозвать.
Подводные камни:
- обязательно проверять подпись,
- нельзя мгновенно отозвать access-токен;
- в
- большой payload раздувает каждый запрос.
header.payload.signature.header: {"alg": "RS256", "typ": "JWT"}
payload: {"sub": "42", "role": "user", "exp": 1767225600}
signature: подпись header и payload ключом сервера- Payload не зашифрован, а только подписан: прочитать может любой, подделать без ключа нельзя. Секреты в JWT не кладут.
- HS256 — общий секрет (подписывает и проверяет один сервис); RS256/ES256 — подписывает приватный ключ, проверяют все по публичному (удобно в микросервисах).
Access и refresh: короткий access-токен (5–15 минут) на каждый запрос и долгий refresh-токен, которым получают новый access. Refresh хранится на сервере и его можно отозвать.
Подводные камни:
- обязательно проверять подпись,
exp, aud, iss и жёстко задавать алгоритм — атака alg: none;- нельзя мгновенно отозвать access-токен;
- в
localStorage токен доступен для XSS; безопаснее HttpOnly-cookie;- большой payload раздувает каждый запрос.
15 Блок 3 из 5: Аутентификация и защита — Что такое OAuth 2.0 и OpenID Connect? 🔥
OAuth 2.0 — протокол делегирования доступа: пользователь разрешает приложению действовать от его имени в другом сервисе, не отдавая пароль. Результат — access token.
Роли: resource owner (пользователь), client (наше приложение), authorization server (выдаёт токены), resource server (API с данными).
Основные flow:
- Authorization Code + PKCE — для веба и мобильных: пользователя перенаправляют на сервер авторизации, он логинится, приложение получает код и обменивает его на токен. Стандарт по умолчанию.
- Client Credentials — сервис ходит в сервис от своего имени, без пользователя.
- Implicit и Password — устарели, не используются.
OpenID Connect (OIDC) — надстройка над OAuth 2.0 для аутентификации: дополнительно выдаётся ID token (JWT с данными пользователя). Это «Войти через Google».
Коротко: OAuth 2.0 — про доступ («что можно»), OIDC — про личность («кто это»).
Роли: resource owner (пользователь), client (наше приложение), authorization server (выдаёт токены), resource server (API с данными).
Основные flow:
- Authorization Code + PKCE — для веба и мобильных: пользователя перенаправляют на сервер авторизации, он логинится, приложение получает код и обменивает его на токен. Стандарт по умолчанию.
- Client Credentials — сервис ходит в сервис от своего имени, без пользователя.
- Implicit и Password — устарели, не используются.
OpenID Connect (OIDC) — надстройка над OAuth 2.0 для аутентификации: дополнительно выдаётся ID token (JWT с данными пользователя). Это «Войти через Google».
Коротко: OAuth 2.0 — про доступ («что можно»), OIDC — про личность («кто это»).
16 Блок 3 из 5: Аутентификация и защита — Что такое rate limiting и какие есть алгоритмы? 🔥
Rate limiting — ограничение числа запросов от клиента за период. Защищает от перегрузки, перебора паролей, злоупотреблений и помогает честно делить ресурсы.
Алгоритмы:
- Fixed window — счётчик на окно («100 в минуту»). Просто, но на границе окон можно сделать 200 запросов за секунду.
- Sliding window — окно скользит (лог запросов или взвешенная сумма двух окон). Точнее.
- Token bucket — ведро пополняется с постоянной скоростью, запрос тратит токен. Разрешает короткие всплески. Самый популярный.
- Leaky bucket — запросы вытекают с постоянной скоростью, сглаживает поток.
Реализация: счётчики в Redis (
Ответ клиенту:
Алгоритмы:
- Fixed window — счётчик на окно («100 в минуту»). Просто, но на границе окон можно сделать 200 запросов за секунду.
- Sliding window — окно скользит (лог запросов или взвешенная сумма двух окон). Точнее.
- Token bucket — ведро пополняется с постоянной скоростью, запрос тратит токен. Разрешает короткие всплески. Самый популярный.
- Leaky bucket — запросы вытекают с постоянной скоростью, сглаживает поток.
Реализация: счётчики в Redis (
INCR + EXPIRE или Lua-скрипт для атомарности), лимиты на nginx или API-шлюзе.Ответ клиенту:
429 Too Many Requests, Retry-After и заголовки с остатком лимита (RateLimit-Remaining). Лимиты задают по пользователю или API-ключу, а не только по IP.
17 Блок 4 из 5: Альтернативы REST — Что такое gRPC и когда его использовать? 🔥
gRPC — RPC-фреймворк от Google: клиент вызывает метод удалённого сервиса как локальную функцию.
- Контракт описывается в Protobuf (
- Бинарная сериализация — компактнее и быстрее JSON.
- Работает поверх HTTP/2: мультиплексирование и стриминг (серверный, клиентский, двунаправленный).
- Строгая типизация, дедлайны и отмена вызовов встроены в протокол.
Когда: межсервисное взаимодействие внутри компании, высокая нагрузка и низкая задержка, стриминг, polyglot-среда с общим контрактом.
Минусы: браузер не умеет gRPC напрямую (нужен gRPC-Web или шлюз), бинарный трафик сложнее отлаживать, нужна генерация кода.
- Контракт описывается в Protobuf (
.proto), из него генерируется код клиента и сервера.- Бинарная сериализация — компактнее и быстрее JSON.
- Работает поверх HTTP/2: мультиплексирование и стриминг (серверный, клиентский, двунаправленный).
- Строгая типизация, дедлайны и отмена вызовов встроены в протокол.
service OrderService {
rpc GetOrder (GetOrderRequest) returns (Order);
rpc WatchOrders (WatchRequest) returns (stream OrderEvent);
}Когда: межсервисное взаимодействие внутри компании, высокая нагрузка и низкая задержка, стриминг, polyglot-среда с общим контрактом.
Минусы: браузер не умеет gRPC напрямую (нужен gRPC-Web или шлюз), бинарный трафик сложнее отлаживать, нужна генерация кода.
18 Блок 4 из 5: Альтернативы REST — Что такое GraphQL и какие у него плюсы и минусы?
GraphQL — язык запросов к API: один эндпоинт, клиент сам описывает, какие данные и в какой форме ему нужны.
Плюсы:
- нет over-fetching и under-fetching: ровно нужные поля за один запрос;
- строгая схема и типы, интроспекция и автодокументация;
- удобно для фронтенда с разными экранами и мобильных клиентов.
Минусы:
- проблема N+1 на бэкенде → нужен DataLoader (батчинг);
- сложно ограничить тяжёлые запросы: глубина, стоимость, лимиты;
- HTTP-кэширование почти не работает (всё через
- ошибки возвращаются со статусом 200 внутри ответа.
Когда: много разных клиентов с разными потребностями, богатая связанная модель данных, BFF для фронтенда.
query {
order(id: 42) {
total
customer { name }
items { product { title } qty }
}
}Плюсы:
- нет over-fetching и under-fetching: ровно нужные поля за один запрос;
- строгая схема и типы, интроспекция и автодокументация;
- удобно для фронтенда с разными экранами и мобильных клиентов.
Минусы:
- проблема N+1 на бэкенде → нужен DataLoader (батчинг);
- сложно ограничить тяжёлые запросы: глубина, стоимость, лимиты;
- HTTP-кэширование почти не работает (всё через
POST на один URL);- ошибки возвращаются со статусом 200 внутри ответа.
Когда: много разных клиентов с разными потребностями, богатая связанная модель данных, BFF для фронтенда.
19 Блок 4 из 5: Альтернативы REST — Как выбрать между REST, gRPC и GraphQL? 🔥
- REST — публичные API, интеграции с партнёрами, простые CRUD-сервисы, когда важны HTTP-кэширование и понятность. Выбор по умолчанию.
- gRPC — внутренние вызовы между микросервисами, высокая нагрузка, стриминг, строгий контракт между командами.
- GraphQL — API для собственных фронтендов и мобильных приложений со сложными и меняющимися требованиями к данным.
Частая комбинация: gRPC между сервисами внутри, REST или GraphQL наружу (через API-шлюз или BFF).
Что сказать на интервью: выбор зависит от потребителей API, требований к производительности, кэшированию и зрелости команды. «Серебряной пули» нет.
- gRPC — внутренние вызовы между микросервисами, высокая нагрузка, стриминг, строгий контракт между командами.
- GraphQL — API для собственных фронтендов и мобильных приложений со сложными и меняющимися требованиями к данным.
Частая комбинация: gRPC между сервисами внутри, REST или GraphQL наружу (через API-шлюз или BFF).
Что сказать на интервью: выбор зависит от потребителей API, требований к производительности, кэшированию и зрелости команды. «Серебряной пули» нет.
20 Блок 4 из 5: Альтернативы REST — Что такое webhook и как сделать его надёжным?
Webhook — обратный вызов: при событии сервис сам отправляет HTTP-запрос на URL, который заранее зарегистрировал клиент. Вместо того чтобы клиент постоянно спрашивал «оплата прошла?», платёжная система сама сообщает об этом.
Отправителю:
- ретраи с экспоненциальной задержкой, если получатель не ответил 2xx;
- подпись запроса (HMAC в заголовке), чтобы получатель мог проверить источник;
- id события и время, журнал доставок, возможность переотправить.
Получателю:
- проверять подпись и время (защита от подделки и повтора);
- быстро отвечать 2xx, а обработку отправлять в очередь;
- быть идемпотентным: одно событие может прийти несколько раз;
- не полагаться на порядок событий — при сомнениях перезапрашивать актуальное состояние через API.
Отправителю:
- ретраи с экспоненциальной задержкой, если получатель не ответил 2xx;
- подпись запроса (HMAC в заголовке), чтобы получатель мог проверить источник;
- id события и время, журнал доставок, возможность переотправить.
Получателю:
- проверять подпись и время (защита от подделки и повтора);
- быстро отвечать 2xx, а обработку отправлять в очередь;
- быть идемпотентным: одно событие может прийти несколько раз;
- не полагаться на порядок событий — при сомнениях перезапрашивать актуальное состояние через API.
21 Блок 5 из 5: Документация и практика — Что такое OpenAPI и зачем он нужен?
OpenAPI (бывший Swagger) — стандарт машиночитаемого описания HTTP API в YAML или JSON: эндпоинты, параметры, схемы запросов и ответов, ошибки, аутентификация.
Что даёт:
- интерактивная документация (Swagger UI, Redoc);
- генерация клиентов и SDK на разных языках;
- валидация запросов, контрактные тесты, моки;
- единый контракт между бэкендом и фронтендом.
Подходы:
- Code-first — схема генерируется из кода: FastAPI из Pydantic-моделей и аннотаций, в DRF —
- Design-first — сначала пишут и согласуют спецификацию, потом код. Удобно, когда API делают несколько команд параллельно.
Что даёт:
- интерактивная документация (Swagger UI, Redoc);
- генерация клиентов и SDK на разных языках;
- валидация запросов, контрактные тесты, моки;
- единый контракт между бэкендом и фронтендом.
Подходы:
- Code-first — схема генерируется из кода: FastAPI из Pydantic-моделей и аннотаций, в DRF —
drf-spectacular.- Design-first — сначала пишут и согласуют спецификацию, потом код. Удобно, когда API делают несколько команд параллельно.
22 Блок 5 из 5: Документация и практика — Что такое HATEOAS и модель зрелости Ричардсона?
Модель зрелости Ричардсона — уровни «RESTовости» API:
- Уровень 0 — один URL, всё через
- Уровень 1 — ресурсы: разные URL для разных сущностей.
- Уровень 2 — HTTP-методы и статус-коды по назначению. Здесь находится большинство «REST API».
- Уровень 3 — HATEOAS: ответы содержат ссылки на возможные действия.
Идея HATEOAS: клиент не зашивает URL и бизнес-правила, а следует ссылкам от сервера. На практике применяется редко: клиенты всё равно пишутся под конкретный API.
- Уровень 0 — один URL, всё через
POST (RPC поверх HTTP, SOAP).- Уровень 1 — ресурсы: разные URL для разных сущностей.
- Уровень 2 — HTTP-методы и статус-коды по назначению. Здесь находится большинство «REST API».
- Уровень 3 — HATEOAS: ответы содержат ссылки на возможные действия.
{
"id": 42,
"status": "new",
"_links": {
"self": {"href": "/orders/42"},
"pay": {"href": "/orders/42/payments", "method": "POST"},
"cancel": {"href": "/orders/42/cancel", "method": "POST"}
}
}Идея HATEOAS: клиент не зашивает URL и бизнес-правила, а следует ссылкам от сервера. На практике применяется редко: клиенты всё равно пишутся под конкретный API.
23 Блок 5 из 5: Документация и практика — Как спроектировать API для бронирования столиков в ресторане? 🔥
1. Ресурсы: рестораны, столики, слоты (свободное время), бронирования.
2. Эндпоинты:
3. Создание брони:
4. Ошибки:
5. На что обратить внимание:
- двойное бронирование — уникальное ограничение или блокировка в БД, а не проверка в коде;
-
- время в ISO 8601 с часовым поясом;
- отмена как действие (
- уведомление ресторана — асинхронно через очередь или webhook.
2. Эндпоинты:
GET /v1/restaurants?city=perm&cursor=...
GET /v1/restaurants/12/availability?date=2026-10-20&guests=4
POST /v1/bookings Idempotency-Key: ...
GET /v1/bookings/{id}
GET /v1/users/me/bookings?status=upcoming
POST /v1/bookings/{id}/cancel
3. Создание брони:
POST /v1/bookings
{"restaurant_id": 12, "starts_at": "2026-10-20T19:00:00+05:00", "guests": 4}
201 Created
Location: /v1/bookings/981
{"id": 981, "status": "confirmed", "table_id": 7, ...}
4. Ошибки:
409 — слот уже занят; 422 — время в прошлом или гостей больше вместимости; 403 — отмена чужой брони; 429 — слишком много попыток.5. На что обратить внимание:
- двойное бронирование — уникальное ограничение или блокировка в БД, а не проверка в коде;
-
Idempotency-Key на создание — защита от повторной отправки;- время в ISO 8601 с часовым поясом;
- отмена как действие (
/cancel), а не DELETE — бронь остаётся в истории;- уведомление ресторана — асинхронно через очередь или webhook.
Ничего не нашлось — попробуйте другой запрос.
Хотите не просто прочитать, а запомнить?
Бот вернёт вам эти вопросы ровно тогда, когда вы начнёте их забывать.