Раздел 2A. API-ручки (эндпоинты)
Что такое ручка-эндпоинт; как вывести API из требований; HTTP против WebSocket по направлению.
Это короткий, но важный практический раздел между «требованиями» (Раздел 2) и «соединением» (Раздел 3). Сняли требования — полезно набросать API-поверхность: список ручек, по которым клиент будет дёргать сервер. Это показывает интервьюеру, что ты умеешь переводить требования в конкретный контракт.
Что такое API-ручка
Ручка (endpoint) — это адрес, по которому клиент общается с сервером, и одно конкретное действие за ним. POST /messages — отправить сообщение, GET /messages/{chat_id} — загрузить историю.
Аналогия: меню в ресторане. Клиент (телефон) говорит серверу «хочу вот это» и называет конкретное блюдо — ручку. Меню — это список доступных действий.
Как понять, какие ручки нужны
Идёшь по функциональным требованиям и для каждого спрашиваешь — как клиент это запросит? Одно действие пользователя → одна ручка.
Нужны ли ручки, если есть WebSocket? Да — это разные оси
Главная ошибка — делить «фича → HTTP или WS». Делить надо по направлению:
- Входящий запрос (клиент → сервер) — разовое действие. Обычно HTTP-ручка: загрузить историю, создать чат, добавить участника, выложить файл. Саму отправку сообщения тоже можно слать ручкой
POST /messages(вернётmessage_id/seq и закроет идемпотентность) — или кадром по уже открытому WebSocket. Оба варианта валидны; на интервью проговори, что выбор есть. - Исходящая доставка (сервер → клиент) — всегда push по WebSocket. Ручкой нельзя дотолкнуть данные тому, кто прямо сейчас ничего не спрашивает. Сюда: новое сообщение получателю, «печатает…», онлайн-статус, галочки доставки/прочтения, входящий звонок.
Простое правило: запросил один раз → HTTP; прилетает само и постоянно → WebSocket. Открыл приложение → по HTTP подтянул список чатов и историю → поднял WebSocket → дальше всё новое идёт по нему.
Ручка почти всегда тянет за собой событие
Действие и оповещение — разные вещи:
PUT /messages/{id}(редактировать),DELETE /messages/{id}(удалить),POST /chats/{id}/members(добавить) — HTTP-ручка сохраняет изменение в БД…- …а потом сервер по WebSocket рассылает остальным участникам событие: «сообщение изменилось», «участник добавлен» — их клиенты обновляют экран.
То же и с отправкой: POST /messages (или WS-кадр) сохраняет и присваивает seq → сервер пушит сообщение получателям по их WebSocket. Ручки не работают в одиночку — почти каждая тянет за собой realtime-событие.
Контракт реального времени (события WebSocket)
У постоянного канала свой «список действий» — это события, а не URL:
message.new, message.edited, message.deleted, receipt (доставлено/прочитано), typing, presence, call.invite/answer/ice. Это тоже часть API — назови её отдельно от REST-ручек.
Базовый набор HTTP-ручек
GET /messages/{chat_id}?after={seq}&limit=50 история, пагинация по курсору
PUT /messages/{msg_id} редактировать (+ WS-событие всем)
DELETE /messages/{msg_id} удалить (+ WS-событие всем)
POST /messages отправить (можно и по WS; вернёт
message_id, идемпотентность client_msg_id)
POST /chats создать чат
GET /chats список моих чатов
POST /chats/{id}/members добавить участника
DELETE /chats/{id}/members/{user_id} удалить участника
GET /users/{id}/presence снимок статуса (живое — по WS)
POST /media pre-signed URL для загрузки
GET /media/{file_id} скачать (обычно прямой CDN-URL)
POST /auth/login · /auth/refresh · POST /devices · GET /users/me
POST /keys · GET /users/{id}/prekeys ключи для E2EE (Раздел 15)
Что часто забывают (а спрашивают)
- Аутентификация и устройства.
POST /auth/login,/auth/refresh,POST /devices(регистрация устройства и его push-токена APNs/FCM, Раздел 5),GET /users/me. Без этого нет ни сессии, ни мультидевайса (Раздел 10). - Ключи для E2EE.
POST /keys(выложить prekeys),GET /users/{id}/prekeys(забрать чужие) — асинхронная установка ключа из X3DH (Раздел 15). - История — это пагинация по курсору, а не «отдай всё»:
?after={seq}&limit=50. Тот же курсор лежит в основе догона после офлайна (Разделы 6, 10). - Идемпотентность отправки.
POST /messagesнесётclient_msg_id, чтобы ретраи по плохой сети не задвоили сообщение (Раздел 6). - Медиа грузится не через API.
POST /mediaвозвращает pre-signed URL, клиент льёт файл напрямую в объектное хранилище/CDN, минуя API-гейтвей; в сообщении едет только ссылка (Раздел 9). - REST-гигиена. Версия в пути (
/v1/...), статус-коды (200/201/4xx), авторизация заголовком (Authorization: Bearer …), rate-limit, единый формат ошибок.