НейроАгент

Исправление пагинации Jira API v3: отсутствуют startAt, maxResults, total

Исправление отсутствующей метаданных пагинации Jira API v3 (startAt, maxResults, total). Узнайте разницу между конечными точками /search и /search/jql и реализуйте правильную пагинацию в вашем приложении C#.

Вопрос

Почему API Jira версии 3 не возвращает информацию о постраничной навигации (startAt, maxResults, total) в ответе при запросе задач?

Я разрабатываю приложение на C#, которое взаимодействует с API Jira. При попытке получения недавно созданных задач Jira за последний месяц с использованием API версии 3, ответ в формате JSON не содержит ожидаемых полей информации о постраничной навигации (startAt, maxResults, total). Ответ начинается непосредственно с массива задач.

Без этой информации о постраничной навигации я не могу реализовать постраничный просмотр данных. Я пытался включить параметры startAt и maxResults в URL запроса, чтобы заставить API вернуть эти поля, но они все равно отсутствуют в ответе. URL запроса, кажется, правильно сформирован.

Стоит отметить, что мы недавно перешли с устаревшей версии API на версию 3. Вот URL, который я использую:

https://bec-sv.atlassian.net/rest/api/3/search/jql?jql=created >%3D -35d&fields=id,key,issuetype,created,customfield_12106,status,reporter,summary,updated,customfield_12111,customfield_11700,customfield_12107,assignee,customfield_12113,customfield_12108,customfield_12134,customfield_12226,customfield_12207,customfield_11902,fixVersions,customfield_10008,customfield_12283,customfield_12326,customfield_12325,customfield_12327,customfield_12321,customfield_12320,customfield_12329,customfield_12330,customfield_12331,customfield_12328,customfield_10007&startAt=0&maxResults=1000

Кто-нибудь может подсказать, почему информация о постраничной навигации может отсутствовать в ответе и как ее получить?

НейроАгент

Проблема, с которой вы сталкиваетесь с отсутствием метаданных постраничной навигации в ответе Jira API v3, вероятно, связана с использованием неправильного конечного точки. При использовании /rest/api/3/search/jql Jira не возвращает стандартные поля постраничной навигации (startAt, maxResults, total), которые доступны в конечной точке /rest/api/3/search. Более новая конечная точка /search/jql использует другой подход к постраничной навигации с использованием nextPageToken вместо традиционных параметров постраничной навигации.

Содержание

Понимание различий между конечными точками

Ключевая проблема заключается в используемой вами конечной точке. В API Jira v3 существуют две разные конечные точки поиска с различным поведением:

  • /rest/api/3/search: Это традиционная конечная точка, которая возвращает полные метаданные постраничной навигации, включая поля startAt, maxResults и total в ответе.

  • /rest/api/3/search/jql: Эта более новая конечная точка использует другой механизм постраничной навигации и не возвращает традиционные метаданные постраничной навигации. Вместо этого она полагается на nextPageToken для постраничной навигации.

Согласно обсуждению на Stack Overflow по этой теме: “В API Jira v3 правильной конечной точкой для поиска JQL является /rest/api/3/search, а не /rest/api/3/search/jql. При использовании /search/jql Jira не возвращает метаданные постраничной навигации (startAt, maxResults, total).” [источник]


Правильная реализация с использованием /rest/api/3/search

Чтобы получить необходимые метаданные постраничной навигации, следует использовать конечную точку /rest/api/3/search вместо этого. Вот как правильно структурировать ваш запрос:

csharp
// Правильный URL конечной точки
string baseUrl = "https://bec-sv.atlassian.net/rest/api/3/search";
string jqlQuery = "created >= -35d";
string fields = "id,key,issuetype,created,customfield_12106,status,reporter,summary,updated,customfield_12111,customfield_11700,customfield_12107,assignee,customfield_12113,customfield_12108,customfield_12134,customfield_12226,customfield_12207,customfield_11902,fixVersions,customfield_10008,customfield_12283,customfield_12326,customfield_12325,customfield_12327,customfield_12321,customfield_12320,customfield_12329,customfield_12330,customfield_12331,customfield_12328,customfield_10007";

var queryParams = new Dictionary<string, string>
{
    { "jql", jqlQuery },
    { "fields", fields },
    { "startAt", "0" },
    { "maxResults", "1000" }
};

var response = await httpClient.GetAsync($"{baseUrl}?{new FormUrlEncodedContent(queryParams).ReadAsStringAsync()}");

С этим подходом вы получите ответ, включающий метаданные постраничной навигации:

json
{
  "expand": "schema,names",
  "startAt": 0,
  "maxResults": 1000,
  "total": 2500,
  "issues": [
    // ... массив задач
  ]
}

Сообщество подтверждает, что этот подход работает: “Вы можете использовать параметр постраничной навигации ‘startAt’, чтобы указать начальную задачу, возвращаемую в результатах JQL, поэтому вы сможете запускать несколько вызовов, последовательно возвращающих 1000 задач.” [источник]


Альтернатива: использование более новой конечной точки /search/jql

Если вам необходимо использовать более новую конечную точку /search/jql (которая в конечном итоге может заменить традиционные конечные точки поиска), вам потребуется адаптировать подход к постраничной навигации. Эта конечная точка использует nextPageToken вместо традиционных параметров постраничной навигации.

Ключевые различия включают:

  • Отсутствие полей startAt, maxResults или total в ответе
  • Ответ включает nextPageToken для постраничной навигации
  • Совершенно другая структура ответа

Как отмечено в обсуждении сообщества Atlassian: “С новой конечной точкой ‘/rest/api/3/search/jql’ структура ответа изменилась” и постраничная навигация должна обрабатываться с использованием nextPageToken вместо startAt. [источник]

Ответ от конечной точки /search/jql выглядит следующим образом:

json
{
  "issues": [
    // ... массив задач
  ],
  "nextPageToken": "токен-следующей-страницы-здесь"
}

Для реализации постраничной навигации с этой конечной точкой:

csharp
string baseUrl = "https://bec-sv.atlassian.net/rest/api/3/search/jql";
string jqlQuery = "created >= -35d";
string fields = "id,key,issuetype,created,customfield_12106,status,reporter,summary,updated,customfield_12111,customfield_11700,customfield_12107,assignee,customfield_12113,customfield_12108,customfield_12134,customfield_12226,customfield_12207,customfield_11902,fixVersions,customfield_10008,customfield_12283,customfield_12326,customfield_12325,customfield_12327,customfield_12321,customfield_12320,customfield_12329,customfield_12330,customfield_12331,customfield_12328,customfield_10007";

var queryParams = new Dictionary<string, string>
{
    { "jql", jqlQuery },
    { "fields", fields }
};

// Первый запрос
var response = await httpClient.GetAsync($"{baseUrl}?{new FormUrlEncodedContent(queryParams).ReadAsStringAsync()}");
var data = await response.Content.ReadFromJsonAsync<JiraSearchJqlResponse>();

// Последующие запросы с использованием nextPageToken
if (!string.IsNullOrEmpty(data.NextPageToken))
{
    queryParams.Add("nextPageToken", data.NextPageToken);
    response = await httpClient.GetAsync($"{baseUrl}?{new FormUrlEncodedContent(queryParams).ReadAsStringAsync()}");
}

Лучшие практики постраничной навигации

При реализации постраничной навигации с API Jira v3 учтите эти лучшие практики:

Для традиционной конечной точки /rest/api/3/search:

  • Используйте разумные значения maxValues: Максимальное значение для maxResults обычно составляет 1000. Как указано в документации Atlassian, “Вы можете извлекать ‘страницы’ максимум по 1000 задач с использованием параметров запроса постраничной навигации startAt и maxResults.” [источник]
  • Рассчитайте общее количество итераций: Используйте поле total, чтобы определить, сколько страниц вам нужно извлечь: Math.Ceil(total / maxResults)
  • Последовательная постраничная навигация: Добавляйте значение maxResults к startAt для каждого последующего запроса для перемещения по результатам [источник]

Для более новой конечной точки /search/jql:

  • Используйте nextPageToken: Этот токен используется для постраничной навигации вместо постраничной навигации на основе смещения
  • Токен истекает: nextPageToken имеет время истечения, поэтому вы должны обрабатывать результаты своевременно
  • Нет общего количества: В отличие от традиционной конечной точки, вы заранее не будете знать общее количество результатов

Документация Atlassian рекомендует: “Клиенты REST API систематически подтверждают значение maxResults при выполнении запросов, чтобы предотвратить сбои всякий раз, когда эти пределы изменяются.” [источник]


Рекомендации по миграции

Важно отметить, что Atlassian объявил сроки устаревания традиционных конечных точек поиска. Согласно обсуждению в сообществе, “конечные точки /rest/api/2/search и /rest/api/3/search будут удалены 1 мая 2025 года.” [источник]

Это означает, что у вас есть несколько вариантов:

  1. Мгновенная миграция: Переключитесь на /search/jql сейчас и адаптируйте логику постраничной навигации
  2. Постепенная миграция: Продолжайте использовать /rest/api/3/search до даты устаревания
  3. Гибридный подход: Используйте обе конечные точки в зависимости от ваших конкретных потребностей

Документация Atlassian отмечает: “Большинство существующих обработок ответов остаются прежними, но структура запроса должна быть скорректирована для соответствия новому API. Кроме того, постраничная навигация должна обрабатываться с использованием nextPageToken вместо startAt.” [источник]


Шаги по устранению неполадок

Если после переключения на правильную конечную точку вы все еще не получаете метаданные постраничной навигации, попробуйте следующие шаги по устранению неполадок:

  1. Проверьте URL конечной точки: Убедитесь, что вы используете /rest/api/3/search, а не /rest/api/3/search/jql
  2. Проверьте формат ответа: Ищите наличие полей startAt, maxResults и total
  3. Протестируйте с минимальными параметрами: Сначала попробуйте простой запрос, чтобы изолировать проблему
  4. Проверьте разрешения API: Убедитесь, что ваше приложение имеет необходимые разрешения для просмотра всех задач
  5. Проверьте ограничение скорости: Jira может ограничивать ответы для больших наборов результатов

Один из участников сообщества отметил: “В этом случае, даже если вы устанавливаете maxResults равным 1000, сам API имеет жесткий лимит в 100 результатов на запрос. Чтобы решить эту проблему, вам потребуется реализовать постраничную навигацию в ваших API-запросах.” [источник]

Если вы работаете с более чем 50 записями, будьте готовы отправлять несколько запросов: “Если у вас более 50 записей, вам потребуется отправлять запрос несколько раз. В первом ответе вы получите значение total, которое представляет общее количество записей из JQL.” [источник]


Заключение

Отсутствие метаданных постраничной навигации в ответе вашего API Jira v3, скорее всего, связано с использованием конечной точки /search/jql вместо традиционной /rest/api/3/search. Вот основные выводы:

  1. Используйте правильную конечную точку: Переключитесь с /rest/api/3/search/jql на /rest/api/3/search, чтобы получить поля startAt, maxResults и total в ответе
  2. Планируйте миграцию: Имейте в виду, что традиционные конечные точки поиска будут устареть 1 мая 2025 года, и начните планировать миграцию на новый подход к постраничной навигации
  3. Реализуйте правильную постраничную навигацию: Рассчитайте количество необходимых страниц с использованием поля total и перебирайте результаты, увеличивая startAt на maxResults
  4. Протестируйте оба подхода: Рассмотрите возможность использования обеих конечных точек в период перехода для обеспечения совместимости

Используя правильную конечную точку и реализуя правильную логику постраничной навигации, вы сможете эффективно извлекать все задачи Jira, сохраняя совместимость как с текущими, так и с будущими версиями API.

Источники

  1. Problem Getting Paging Info from Jira API - Stack Overflow
  2. JIRA Cloud REST API pagination - Same issues returned on different pages - Atlassian Community
  3. How to use the maxResults API parameter for Jira Issue Search REST API - Atlassian
  4. Jira Atlassian API Pagination - Stack Overflow
  5. Why can’t I query more than 1000 results for JIRA? - Stack Overflow
  6. Solved: Rest API maxResults Problem - Atlassian Community
  7. Solved: JIRA API code to resolve pagination for issue search - Atlassian Community
  8. JIRA Cloud REST API v3 /search/jql: Slower Fetching with nextPageToken & No totalIssues – Any Workarounds? - Atlassian Developer Community
  9. When are JQL search endpoints /rest/api/2/search and /rest/api/3/search really being removed? - Atlassian Community
  10. Atlassian REST API Search Endpoints Deprecation - Adaptavist