Перейти к основному содержимому

OData — протокол открытых данных

Всем

OData

Что такое OData?

OData (Open Data Protocol, «протокол открытых данных») — это открытый стандарт для создания и использования RESTful API, ориентированных на работу со структурированными данными как с единой моделью сущностей. Клиент обращается к ресурсам по HTTP, а сервер может на лету отфильтровать, отсортировать, развернуть связи и вернуть только нужные поля — без того, чтобы для каждой комбинации параметров проектировать отдельный эндпоинт.

OData не заменяет HTTP и не конкурирует с JSON как форматом: он надстраивается над REST, добавляя согласованные правила адресации ресурсов, описания модели данных (метаданные) и системных опций запроса$filter, $select, $expand и других.

Официальная документация и экосистема Microsoft: OData на Microsoft Learn. Спецификация поддерживается консорциумом OASIS; актуальные версии протокола — OData 4.0 и 4.01.

Простая аналогия: обычный REST API — это меню с фиксированными блюдами («список пользователей», «пользователь по id», «активные пользователи за месяц» — три разных URL). OData ближе к SQL поверх HTTP: один ресурс Users, а «нарезка» данных задаётся в строке запроса.


OData - стандарт запросов к REST-данным

В середине 2000-х корпоративным системам нужен был способ отдавать данные множеству клиентов (веб, десктоп, отчёты, интеграции) без взрыва числа методов API. Microsoft предложила протокол в 2007 году; с 2012 года OData развивается как открытый стандарт OASIS, а не как закрытая технология одного вендора.

Идея: описать модель данных (сущности, свойства, связи, операции) один раз, опубликовать сервисный корень (service root) и позволить клиентам комбинировать стандартные опции запроса. Так снижается дублирование контрактов и упрощается интеграция между продуктами разных команд.


Где OData используется

ОбластьПримеры
Корпоративные ERP/CRMMicrosoft Dynamics 365, SAP (OData-сервисы), интеграции с учётными системами
Платформа MicrosoftSharePoint REST/OData, Azure API Management, отчётность Power BI к OData-источникам
Разработка на .NETASP.NET Core OData, Microsoft.OData.Client, Web API с пакетом Microsoft.AspNetCore.OData
Отечественные продуктыПубликация данных из через OData для витрин и внешних систем
Универсальные клиентыExcel Power Query, Postman, браузерные REST-клиенты, генераторы кода по $metadata

OData особенно уместен, когда потребителей много, набор полей и фильтров непредсказуем, а данные уже лежат в реляционной или объектной модели (таблицы, сущности EF, справочники конфигурации).


Как устроен OData-сервис

Сервисный корень и наборы сущностей

OData-сервис публикуется с корневого URL (service root), например:

https://services.example.com/odata/v1/

По этому адресу клиент получает описание наборов сущностей (entity sets) — коллекций, с которыми можно работать, по смыслу близких к таблицам или ресурсам REST:

GET https://services.example.com/odata/v1/

Типичные пути к данным:

GET .../odata/v1/Products — коллекция
GET .../odata/v1/Products(42) — одна сущность по ключу
GET .../odata/v1/Categories(3)/Products — связанная коллекция

Идентификация сущности в URL может быть в скобках Products(42) или в сегменте пути — в зависимости от версии и настроек сервиса; смысл один: стабильный адрес ресурса в терминах модели, а не произвольное имя метода.

Метаданные модели ($metadata)

Ключевое отличие от «голого» REST — документ метаданных (Conceptual Schema Definition Language, CSDL), обычно доступный по:

GET .../odata/v1/$metadata

В нём описаны:

  • типы сущностей и сложных типов;
  • свойства, ключи, обязательность;
  • навигационные свойства (связи «один-ко-многим», «многие-ко-многим»);
  • действия (actions) и функции (functions).

Клиенты и инструменты (Power Query, генераторы прокси) читают $metadata и понимают модель без отдельного PDF-контракта. Для человека это XML; для машины — основа типобезопасных клиентов.

HTTP и форматы представления

OData опирается на HTTP:

ОперацияHTTPПример смысла
Чтение коллекции или сущностиGETСписок заказов, заказ по id
СозданиеPOSTНовая запись в наборе
Полная заменаPUTОбновление всех полей
Частичное обновлениеPATCHИзменение отдельных полей
УдалениеDELETEУдаление сущности

Тело запросов и ответов чаще всего в JSON (application/json); в спецификации также предусмотрен Atom/XML. Заголовок Accept и опция $format уточняют представление.

Поток обработки запроса:


Системные опции запроса (query options)

Системные опции — параметры строки запроса, которые управляют объёмом, составом и порядком возвращаемых данных. В OData 4.x имена опций могут начинаться с $ (в 4.01 поддерживается и без префикса, регистронезависимо для совместимости).

ОпцияНазначение
$filterФильтрация коллекции (предикат по полям и связям)
$selectВыбор только указанных свойств
$expand«Подгрузка» связанных сущностей в одном ответе
$orderbyСортировка
$top / $skipПостраничная выборка (лимит и смещение)
$countВключить или запросить только количество элементов
$searchПолнотекстовый поиск (семантика зависит от реализации сервиса)
$computeВычисляемые поля в проекции (OData 4.01)

Подробные правила и примеры: Обзор опций запроса, Использование опций.

$filter — фильтрация на сервере

Вместо эндпоинта GET /users?status=active&minAge=18 клиент пишет единый ресурс и выражение:

GET .../People?$filter=FirstName eq 'Иван' and Age ge 18

Поддерживаются сравнения (eq, ne, gt, ge, …), логика (and, or, not), функции (contains, startswith, year, …), обход связей (Department/Name eq 'IT'). Сервер обязан интерпретировать фильтр по модели; необоснованные поля отклоняются или игнорируются согласно политике безопасности.

$select и $expand — экономия трафика

Только нужные поля:

GET .../Products?$select=Name,Price

Связанные сущности «в одном заходе»:

GET .../Orders(1001)?$expand=Customer,Lines

Комбинация: развернуть заказчика, но у него взять только имя и город:

GET .../Orders?$expand=Customer($select=Name,City)

Это прямой аналог JOIN + проекции в SQL, но выраженный в URL — удобно для UI, которому на списке нужны разные «срезы» данных.

Пагинация

GET .../Products?$orderby=Name&$top=20&$skip=40

Сервис может вернуть @odata.nextLink — URL следующей страницы, чтобы клиент не собирал смещения вручную при больших объёмах.

$count

GET .../Products/$count
GET .../Products?$count=true&$filter=Price gt 1000

Позволяет получить число элементов без полной выгрузки коллекции.


Действия и функции

Помимо CRUD над сущностями, OData описывает:

  • Functions — операции без побочных эффектов (как чистые функции), вызываются через GET, могут участвовать в $filter / $orderby.
  • Actions — операции с побочными эффектами (списание, утверждение документа, массовая операция), обычно через POST.

Пример вызова функции (схематично):

GET .../Products/Model.GetFeaturedProducts()

Action может принимать параметры в теле POST. Так протокол совмещает ресурсную модель и бизнес-операции, не ломая REST-транспорт.


Версии протокола

ВерсияЗаметки
OData 2.0 / 3.0Широко в legacy (SharePoint, старые .NET-сервисы); опции вроде $inlinecount
OData 4.0 / 4.01Текущая основа; улучшенная типизация, $compute, уточнённые правила URL
OData 4.02Развитие стандарта OASIS; при внедрении сверяйтесь с документом протокола

При интеграции всегда уточняйте версию сервиса и набор поддерживаемых опций: сервер может не реализовать $search или $expand на глубину больше N.


OData и «обычный» REST

КритерийREST (типичный)OData
КонтрактOpenAPI/Swagger, описание вручную$metadata + соглашения протокола
ФильтрацияОтдельные query-параметры на каждый сценарийЕдиный язык $filter
СвязиНесколько запросов или специальные DTO$expand по навигационным свойствам
Сложность сервераНиже, полный контроль эндпоинтовВыше: парсер запросов, безопасность, производительность
КэшированиеПроще для простых GETСложнее из-за комбинаций опций
КлиентыУниверсальныВыигрывают типизированные OData-клиенты

OData не обязателен для каждого API. Его выбирают, когда много ад hoc запросов к одной модели данных (отчёты, интеграции, админки). Для узкого мобильного API с фиксированными экранами чаще достаточно простого REST или GraphQL.


Безопасность и эксплуатация

Свободный $filter и $orderby — это по сути пользовательский запрос к данным. Риски:

  • Производительность — тяжёлые фильтры без индексов нагружают СУБД;
  • Утечка полей$select не должен обходить права на свойства;
  • Инъекции — реализация должна параметризовать запросы к БД, а не склеивать SQL из строки URL.

На практике ограничивают глубину $expand, белый список полей в $filter, лимиты $top, аутентификацию (OAuth 2.0, API keys) и авторизацию на уровне строк. Подробнее про развёртывание и hardening: раздел Security на Microsoft Learn.


Пример на C# (клиент)

Для .NET существует клиентская библиотека, работающая с IQueryable-подобным API:

var context = new Container(new Uri("https://services.example.com/odata/v1/"));
var query = context.Products
.Where(p => p.Price < 100)
.OrderBy(p => p.Name)
.Take(10);

foreach (var product in query)
{
Console.WriteLine($"{product.Name}: {product.Price}");
}

На сервере ASP.NET Core OData подключает те же опции к контроллерам или minimal API, транслируя $filter в LINQ и далее в SQL через EF Core.

Связанные материалы энциклопедии: API, HTTP, Веб-сервисы, SOAP, 1С: интеграция.


Полезные ссылки


См. также

Другие статьи этого же раздела в боковом меню (как на странице «О разделе»).