Communication & API Style (Macro-Architecture): Архитектура клиент-серверного взаимодействия веб приложений¶
- REST – ~60–80 % проектов
- GraphQL – ~20–30 % (быстрый рост)
- gRPC – ~10–20 % (корпоративные микросервисы)
- WebSocket / SSE / Webhook – по потребностям реального времени
- MQTT / AMQP – IoT и message-driven системы
- SOAP / CORBA / XML-RPC – почти не используются в новых разработках
Клиент-серверные протоколы и стили взаимодействия¶
- REST API
- GraphQL
- RPC (JSON-RPC, XML-RPC)
- gRPC
- SOAP
- tRPC
- OData
- Apache Thrift
- RSocket
Двухсторонние и push-механизмы¶
- WebSocket
- Server-Sent Events (SSE)
- Webhooks
- Long Polling / HTTP Polling
- WebTransport (over HTTP/3)
- WebRTC Data Channels
Сообщенческие и IoT-ориентированные шины¶
- MQTT
- AMQP
- STOMP
- JMS (Java Message Service)
- CoAP (Constrained Application Protocol)
- XMPP (eXtensible Messaging and Presence Protocol)
Устаревшие / нишевые¶
- CORBA
- XML-RPC (если отдельно от RPC)
- DCE/RPC
Примечание: - Некоторые технологии перекрываются по функциональности (например, JSON-RPC vs gRPC), выбор зависит от требований к типу данных, производительности, экосистеме и поддержке в языке/фреймворке. - Для streaming- или realtime-приложений часто комбинируют несколько стилей (например, REST для CRUD + WebSocket/SSE для оповещений). - Новые стандарты (HTTP/2, HTTP/3, QUIC) улучшают и оптимизируют каналы передачи, но сами по себе являются транспортом для вышеперечисленных протоколов.
REST API¶
REST API - это архитектурный стиль клиент-серверного взаимодействия, который определяет, по каким правилам приложения должны обмениваться данными между собой.
- Stateless. Сервер не хранит состояние клиента. Каждый запрос содержит всю необходимую информацию.
- Все данные представлены в виде ресурсов endpoint (/users, /products).
- Использование стандартных HTTP-методов (GET, POST, PUT, DELETE, etc).
- Ответы сервера могут быть кэшированы для повышения производительности.
- Слоистая система. Клиент не знает, взаимодействует ли он напрямую с сервером или через прокси.
- Формат данных json (xml устаревшее)
Структура REST API endpoints ресурсов¶
Основные правила:
- Использовать существительные (не глаголы)
Плохо: /getUsers, /createOrder, /deleteProduct
Хорошо: GET /users, POST /orders, DELETE /products/{id}
- Называть ресурсы во множественном числе (Единообразие и явное указание на коллекцию)
GET /users (все пользователи)
GET /users/1 (конкретный пользователь)
- Использовать нижний регистр и дефисы (kebab-case)
Плохо: /UserOrders, /productCategories
Хорошо: /user-orders, /product-categories
- Избегать пробелов и спецсимволов
Вместо пробелов использовать - или _:
GET /product-categories (лучше, чем /product%20categories)
Иерархия ресурсов:
- Вложенность для связанных сущностей. Если ресурс принадлежит другому ресурсу, использовать иерархию:
/users/{userId}/orders - Заказы пользователя
/users/{userId}/orders/{orderId} - Конкретный заказ
- Глубина вложенности ≤ 2–3 уровней
Плохо: /users/1/orders/5/products/3/reviews
Лучше: /reviews?productId=3&userId=1 (с фильтрацией)
-
Для фильтрации, сортировки, пагинации - использовать query-параметры GET
/users?role=admin&status=activeGET/products?sort=-price,created_at--= DESC GET/articles?page=2&limit=10 -
Версионирование API
/api/v1/users
/api/v2/users
Документирование¶
Swagger - документация
Тестирование¶
GraphQL¶
GraphQL — это спецификация языка запросов и система выполнения, которая может работать поверх разных транспортных протоколов (HTTP, WebSocket)
- GraphQL сам по себе stateless (как и REST), но может использоваться в stateful-сценариях:
- Stateless-часть (HTTP): Обычные запросы (Queries) и мутации (Mutations) работают через HTTP (как REST).
- Stateful-часть (WebSocket): Подписки (Subscriptions) требуют постоянного соединения (WebSocket), которое поддерживает состояние.
- Один URL (/graphql)
- Клиент каждый раз определяет что получать (получает только запрошенные поля)
Работа GraphQL под капотом¶
Клиент:
- Отправляет GraphQL-запрос (Query/Mutation) через HTTP POST:
POST /graphql HTTP/1.1
Content-Type: application/json
{
"query": "query { user(id: 1) { name email } }"
}
Сервер:
- Парсит запрос.
- Валидирует его против схемы.
- Выполняет через резолверы (функции для получения данных).
- Возвращает JSON-ответ:
Подписки (WebSocket):
- Для Subscriptions используется WebSocket (протокол graphql-ws)
- Сервер поддерживает состояние соединения и сам отправляет данные при событиях.
// Клиент подключается к WebSocket и отправляет:
{
"type": "subscribe",
"query": "subscription { newMessage { text } }"
}
Как GraphQL делает выборку данных?
Механизм резолверов (Resolvers): Каждое поле в GraphQL-запросе обрабатывается резолвером — функцией, которая знает, где взять данные.
# Схема
type Query {
user(id: ID!): User
}
type User {
id: ID!
name: String!
email: String!
posts: [Post!]!
}
// Резолверы
const resolvers = {
Query: {
user: (parent, args, context) => {
return db.users.find(user => user.id === args.id); // Данные из БД
}
},
User: {
posts: (user) => {
return db.posts.filter(post => post.authorId === user.id); // Связанные данные
}
}
};
Процесс выполнения запроса:
- Парсинг: Сервер разбирает GraphQL-запрос в AST (Abstract Syntax Tree).
- Валидация: Проверяет, что запрос соответствует схеме.
- Исполнение:
- Для каждого поля запускается соответствующий резолвер.
- Резолверы могут получать данные из:
- БД (SQL, MongoDB).
- Других API (REST, gRPC).
- Кэша (Redis).
- Сборка ответа: Данные объединяются в JSON-структуру, запрошенную клиентом.
Принцип работы запросов¶
Гибкие запросы данных (Queries)
- Клиент точно указывает, какие данные ему нужны.
- Можно запрашивать связанные данные за один запрос (например, пользователя и его посты).
- Избегает проблем over-fetching (получение лишних данных) и under-fetching (недостаточность данных).
Изменение данных (Mutations)
- Аналог POST/PUT/PATCH/DELETE в REST.
- Позволяет изменять данные на сервере и сразу получать обновленные поля в ответе.
Реал-тайм обновления (Subscriptions)
- Сервер может отправлять данные клиенту без запроса (например, уведомления, чаты).
- Работает через WebSocket (graphql-ws или subscriptions-transport-ws).
Интроспекция API
- Клиент может автоматически получать схему API (типы, поля, документацию).
- Используется для генерации документации (например, GraphiQL).
Инициация запроса с сервера¶
Сервер может инициировать запрос к клиенту, но только через подписки (Subscriptions).
- Клиент подключается к серверу через WebSocket.
- Сервер пассивно ожидает событий (например, новое сообщение в чате).
- Когда событие происходит, сервер автоматически отправляет данные всем подписанным клиентам.
Ограничения GraphQL¶
- Нет встроенного кэширования: В отличие от REST (где кэшируются URL), GraphQL требует ручной настройки кэша (например, через Apollo Client).
- Сложность запросов: Клиент может отправить слишком сложный запрос (например, с глубокой вложенностью), что нагрузит сервер.
- Проблема N+1: Если запрашиваются связанные данные, сервер может сделать много запросов к БД.
Инструменты для работы с GraphQL¶
Серверные
- Apollo Server (Node.js)
- GraphQL Yoga (упрощенный сервер)
- Hasura (GraphQL поверх PostgreSQL)
Клиентские
- Apollo Client (React/Vue)
- Relay (оптимизирован для Facebook)
- URQL (легковесная альтернатива)
RPC (Remote Procedure Call)¶
gRPC¶
SOAP (Simple Object Access Protocol)¶
SOAP - это протокол обмена структурированными сообщениями. Формат данных - Soap-XML. Может использоваться с любым протоколом прикладного уровня (SMTP, FTP, HTTP). Для описания SOAP сервисов используется WSDL (Web Services Description Language) - язык описания веб-сервисов и доступа к ним, основанный на XML.
STATEFUL
<binding type="bookPortType" name="bookBind">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="getBook">
<soap:operation soapAction="getBook"/>
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="iteral"/>
</output>
</operation>
</binding>
<service name="Hello Service">
<port binding="bookBind" name="bookPort">
<soap:address location="http://localhost/bookservice"/>
</port>
</service>