Общее описание

API v01

Публичное API. Версия v01. Все запросы выполняются по HTTPS.


https://<host>/api/v01/<Service>/...


Этот раздел — общие правила работы с API: транспорт, формат запросов и ответов, OData-параметры чтения, типы данных. Описание конкретных сервисов вынесено в отдельные разделы документации.


Сервисы и операции

СервисЧтение (OData)Изменение (REST)
Task / Tasksодна задача · список задач · справочникиCreate, Update, Delete
Project / Projectsсписок проектов · справочникиCreate, Update, Deactivate, Restore
User / Usersсписок пользователей · профили · настройки · справочникиCreate, UpdateProfile, UpdateSettings, Activate, Deactivate
WorkLog / WorkLogsсписок списаний времени · справочникиCreate, Update, Delete


Соглашение по именам сервисов

Каждая сущность представлена парой endpoint-ов:

  • Сервис в единственном числе (/api/v01/Task, /api/v01/Project, /api/v01/User, /api/v01/WorkLog) — операции над одной записью: REST-операции записи (Create, Update, Delete и пр.) и, где применимо, OData-чтение одной записи по ключу.
  • Сервис во множественном числе (/api/v01/Tasks, /api/v01/Projects, /api/v01/Users, /api/v01/WorkLogs) — выборка коллекции и связанные объекты-справочники (Statuses, Types, Priorities, и т. п.).


Транспорт

Используется два транспорта:

  • OData v2 — для чтения данных. Поддерживаются стандартные операторы $select, $filter, $orderby, $skip, $top и формат ответа $format=json. По умолчанию OData возвращает XML — на практике почти всегда требуется явно запросить JSON.
  • REST — для операций записи. Метод POST, тело — JSON, ответ — JSON.


Конверт ответа REST

Все REST-операции отвечают унифицированным JSON-документом.

Успех:

{
  "status": "Success",
  "statusCode": 200,
  "details": { /* ключи созданной/изменённой сущности */ }
}


Ошибка:

{
  "status": "Error",
  "statusCode": 500,
  "statusText": "Wrong parameters"
}


Особый случай — бизнес-ошибка из логики БД: statusCode = 399, в statusText приходит MessageCode (строковый код, который клиент локализует самостоятельно). Во всех остальных случаях statusText содержит готовый локализованный текст.


HTTP / statusCodestatusTextКогда возникает
200—Успех
399MessageCode (например, JBTASKS.TASK_PROJECT_NOT_FOUND)Бизнес-ошибка; клиент должен локализовать код
500"Wrong parameters"Не передан обязательный конверт XxxData или ключи
прочие 4xx/5xxготовый текст (MessageText)Прочие ошибки слоя БД


Конверт запроса REST

Все REST-операции принимают JSON-тело со следующей общей формой:

{
  "<Entity>Data": { /* поля сущности */ },
  "<Entity>KeyField": "TaskID",
  "Parent<Entity>KeyField": "TaskKey"
}


Поле <Entity>Data — основной контейнер. Поля <Entity>KeyField и Parent<Entity>KeyField (если применимо) задают, какой именно ключ из переданных является ведущим: TaskID, TaskKey, IntegrationID, Email, EmployeeID и т. п. Если <Entity>KeyField опущен, сервис сам определит ведущий ключ по тому, какие поля заполнены — приоритет <Entity>ID → бизнес-код → IntegrationID.


OData: чтение данных

Чтение всегда выполняется через сервисы во множественном числе или через единичный сервис с параметрами.

Базовый запрос коллекции

GET /api/v01/Tasks/odata/Tasks?$format=json
GET /api/v01/Projects/odata/Projects?$format=json
GET /api/v01/Users/odata/Users?$format=json
GET /api/v01/WorkLogs/odata/WorkLogs?$format=json


Поддерживаемые параметры запроса

ПараметрНазначениеПример
$selectСписок возвращаемых полей через запятую. Сильно сокращает payload и ускоряет ответ.$select=TaskID,TaskKey,TaskText,StatusID
$filterУсловие фильтрации. Операторы: eq, ne, gt, ge, lt, le, логические and, or, not. Строки — в одинарных кавычках.$filter=ProjectCode eq 'PROJ' and StatusCategoryID ne '3'
$orderbyСортировка. Направления asc / desc. Поддерживается сортировка по нескольким полям через запятую.$orderby=PriorityID asc, DueDateTime desc
$topСколько записей вернуть (страница).$top=50
$skipСколько записей пропустить (offset). Используется в паре с $top для постраничной выборки.$skip=100&$top=50
$formatФормат ответа. Для JSON указывать json.$format=json
$inlinecountЗапросить общее число записей в коллекции (без учёта $top / $skip).$inlinecount=allpages


Сводный пример

Получить вторую страницу из 50 открытых задач проекта PROJ, отсортированных по приоритету, только нужные поля, с общим счётчиком:

GET /api/v01/Tasks/odata/Tasks
  ?$select=TaskID,TaskKey,TaskText,StatusID,PriorityID,AssigneeFullName,DueDateTime
  &$filter=ProjectCode eq 'PROJ' and StatusCategoryID ne '3'
  &$orderby=PriorityID asc, DueDateTime asc
  &$skip=50&$top=50
  &$inlinecount=allpages
  &$format=json


Ответ (сокращённо):

{
  "d": {
    "__count": "327",
    "results": [
      {
        "TaskID": "0000004242",
        "TaskKey": "PROJ-42",
        "TaskText": "Починить логин",
        "StatusID": "10",
        "PriorityID": "HIGH",
        "AssigneeFullName": "Иван Петров",
        "DueDateTime": "/Date(1735603200000)/"
      }
    ]
  }
}


Чтение одной записи

Если у сервиса есть OData-точка одиночника, она принимает значения ключа через параметры пути:

GET /api/v01/Task/odata/Task(ID='PROJ-42',TaskKeyField='TaskKey')/Results?$format=json


Разрешённые значения …KeyField:

СущностьИмя поляДопустимые значения
TaskTaskKeyFieldTaskID, TaskKey, IntegrationID
ProjectProjectKeyFieldProjectID, ProjectCode, IntegrationID
UserUserKeyFieldUserID, EmployeeID, Email, IntegrationID
WorkLogWorkLogKeyFieldWorkLogID, IntegrationID


Кодировки и типы данных

Тип данныхJSON-представлениеКомментарий
строковый (NVARCHAR(n))stringUTF-8
целочисленный (INTEGER, INT, SMALLINT)numberцелое
длинный целочисленный (BIGINT)number / stringбольшие значения могут приходить как строка
дробный (DECIMAL(p,s))stringOData сериализует дробные значения как строку
дата/время (SECONDDATE, TIMESTAMP)stringформат OData: "/Date(epochMs)/"; на вход в REST допускается ISO YYYY-MM-DDTHH:MM:SS


В REST-операциях даты-времена в формате YYYY-MM-DDTHH:MM:SS нормализуются сервером в YYYYMMDDHHMMSS (14 символов).


Подсказки клиенту

  • Всегда указывайте $format=json — иначе OData возвращает XML.
  • Не запрашивайте «все поля» — используйте $select, payload крупный.
  • Для постраничной выборки используйте $top + $skip + $inlinecount=allpages.
  • В $filter строки заключаются в одинарные кавычки.
  • При записи передавайте только те поля, которые меняете — пустые/отсутствующие поля интерпретируются как null и могут затереть значения. Поведение зависит от конкретной операции — см. описание соответствующей операции.