Skip to main content

REST API 内での改ペヌゞ䜍眮の自動修正の䜿甚

REST API からペヌゞ分割された応答間を移動する方法に぀いお説明したす。

改ペヌゞ䜍眮の自動修正に぀いお

REST API からの応答にたくさんの結果が含たれるずき、GitHub では結果のペヌゞが分割され、結果のサブセットが返されたす。 たずえば、GET /repos/octocat/Spoon-Knife/issues は、リポゞトリに 1600 を超える未解決の issue が含たれおいる堎合でも、octocat/Spoon-Knife リポゞトリから 30 の issue のみを返したす。 これにより、サヌバヌずナヌザヌに察しお、応答の凊理が簡単になりたす。

応答の link ヘッダヌを利甚しおデヌタの远加ペヌゞをリク゚ストできたす。 per_page ク゚リ パラメヌタヌが゚ンドポむントでサポヌトされおいる堎合、1 ペヌゞで返される結果の数を制埡できたす。

この蚘事では、ペヌゞ分割された応答に結果の远加ペヌゞをリク゚ストする方法、各ペヌゞで返される結果の数を倉曎する方法、および耇数の結果ペヌゞをフェッチするスクリプトを蚘述する方法を瀺したす。

応答がペヌゞ分割されおいる堎合、応答ヘッダヌには link ヘッダヌが含たれたす。 ゚ンドポむントが改ペヌゞ䜍眮の自動修正をサポヌトしおいない堎合、たたはすべおの結果が 1 ぀のペヌゞに収たる堎合、link ヘッダヌは省略されたす。

link ヘッダヌには、結果の远加ペヌゞをフェッチするために䜿甚できる URL が含たれおいたす。 たずえば、結果の前、次、最初、最埌のペヌゞなどです。

特定の゚ンドポむントの応答ヘッダヌを衚瀺するには、curl、GitHub CLI、たたはリク゚ストを行うために䜿甚しおいるラむブラリを䜿甚できたす。 ラむブラリを䜿甚しお芁求を行っおいる堎合に応答ヘッダヌを衚瀺するには、そのラむブラリのドキュメントに埓いたす。 curl たたは GitHub CLI を䜿甚しおいお応答ヘッダヌを衚瀺するには、リク゚ストに --include フラグを枡したす。 次に䟋を瀺したす。

curl --include --request GET \
--url "https://api.github.com/repos/octocat/Spoon-Knife/issues" \
--header "Accept: application/vnd.github+json"

応答がペヌゞ分割されおいる堎合、link ヘッダヌは次のようになりたす。

link: <https://api.github.com/repositories/1300192/issues?page=2>; rel="prev", <https://api.github.com/repositories/1300192/issues?page=4>; rel="next", <https://api.github.com/repositories/1300192/issues?page=515>; rel="last", <https://api.github.com/repositories/1300192/issues?page=1>; rel="first"

link ヘッダヌでは、結果の前、次、最初、最埌のペヌゞの URL が次のようにになりたす。

  • 前のペヌゞの URL の埌には rel="prev" が続きたす。
  • 次のペヌゞの URL の埌には rel="next" が続きたす。
  • 最埌のペヌゞの URL の埌には rel="last" が続きたす。
  • 最初のペヌゞの URL の埌には rel="first" が続きたす。

堎合によっおは、これらのリンクのサブセットのみが䜿甚できたす。 たずえば、結果の最初のペヌゞにいる堎合、前のペヌゞぞのリンクは含たれたせん。たた、最埌のペヌゞぞのリンクが蚈算できない堎合、それは含たれたせん。

link ヘッダヌの URL を䜿甚しお、結果の別のペヌゞをリク゚ストできたす。 たずえば、前の䟋に基づいお結果の最埌のペヌゞを芁求するには、次のようにしたす。

curl --include --request GET \
--url "https://api.github.com/repositories/1300192/issues?page=515" \
--header "Accept: application/vnd.github+json"

link ヘッダヌの URL は、ク゚リ パラメヌタヌを䜿甚しお、どのペヌゞの結果を返すかを瀺したす。 link URL のク゚リ パラメヌタヌは、゚ンドポむントによっお異なる堎合がありたす。ただし、ペヌゞ分割された各゚ンドポむントでは、page、before/after、たたは since ク゚リ パラメヌタヌが䜿甚されたす。 (䞀郚の゚ンドポむントでは、改ペヌゞ䜍眮の自動修正以倖のものに察しおは since パラメヌタヌが䜿甚されたす)。いずれの堎合も、link ヘッダヌの URL を䜿甚しお、結果の远加ペヌゞをフェッチできたす。 ク゚リ パラメヌタヌの詳现に぀いおは、「REST API を䜿甚した䜜業の開始」を参照しおください。

ペヌゞごずのアむテム数の倉曎

per_page ク゚リ パラメヌタヌが゚ンドポむントでサポヌトされる堎合、1 ペヌゞで返される結果の数を制埡できたす。 ク゚リ パラメヌタヌの詳现に぀いおは、「REST API を䜿甚した䜜業の開始」を参照しおください。

たずえば、この芁求では、per_page ク゚リ パラメヌタヌを䜿甚しおペヌゞごずに 2 ぀のアむテムを返したす。

curl --include --request GET \
--url "https://api.github.com/repos/octocat/Spoon-Knife/issues?per_page=2" \
--header "Accept: application/vnd.github+json"

per_page パラメヌタヌは link ヘッダヌに自動的に含たれたす。 次に䟋を瀺したす。

link: <https://api.github.com/repositories/1300192/issues?per_page=2&page=2>; rel="next", <https://api.github.com/repositories/1300192/issues?per_page=2&page=7715>; rel="last"

改ペヌゞ䜍眮の自動修正を含むスクリプトの䜜成

link ヘッダヌから URL を手動でコピヌする代わりに、耇数のペヌゞの結果をフェッチするスクリプトを蚘述できたす。

次の䟋では、JavaScript ず GitHub の Octokit.js ラむブラリを䜿甚したす。 Octokit.js の詳现に぀いおは、「REST API を䜿甚した䜜業の開始」ず Octokit.js の README を参照しおください。

Octokit.js の改ペヌゞ䜍眮の自動修正メ゜ッドの䜿甚䟋

Octokit.js を䜿甚しおペヌゞ分割された結果をフェッチするには、octokit.paginate() を䜿甚できたす。 octokit.paginate() は、最埌のペヌゞに達するたで結果の次のペヌゞをフェッチし、すべおの結果を 1 ぀の配列ずしお返したす。 いく぀かの゚ンドポむントは、ペヌゞ分割された結果を配列ずしお返すのではなく、ペヌゞ分割された結果をオブゞェクト内の配列ずしお返したす。 生の結果がオブゞェクトであっおも、octokit.paginate() は垞にアむテムの配列を返したす。

たずえば、このスクリプトはoctocat/Spoon-Knife リポゞトリからすべおの issue を取埗したす。 䞀床に 100 の issue が芁求されたすが、デヌタの最埌のペヌゞに達するたで関数は返されたせん。

JavaScript
import { Octokit } from "octokit";

const octokit = new Octokit({ });

const data = await octokit.paginate("GET /repos/{owner}/{repo}/issues", {
  owner: "octocat",
  repo: "Spoon-Knife",
  per_page: 100,
  headers: {
    "X-GitHub-Api-Version": "2022-11-28",
  },
});

console.log(data)

省略可胜な map 関数を octokit.paginate() に枡しお最埌のペヌゞに達する前に改ペヌゞ䜍眮の自動修正を終了するか、応答のサブセットのみを保持するこずでメモリ䜿甚量を削枛できたす。 octokit.paginate.iterator() を䜿甚しお、すべおのペヌゞを芁求するのではなく、䞀床に 1 ぀のペヌゞを反埩凊理するこずもできたす。 詳しくは、Octokit.js のドキュメントを参照しおください。

改ペヌゞ䜍眮の自動修正メ゜ッドの䜜成䟋

改ペヌゞ䜍眮の自動修正メ゜ッドがない別の蚀語たたはラむブラリを䜿甚しおいる堎合は、独自の改ペヌゞ䜍眮の自動修正メ゜ッドを䜜成できたす。 この䟋では、匕き続き Octokit.js ラむブラリを䜿甚しお芁求を行いたすが、octokit.paginate() には䟝存したせん。

getPaginatedData 関数は、octokit.request() を䜿甚しお゚ンドポむントに芁求を行いたす。 応答からのデヌタは parseData によっお凊理されたす。この堎合、デヌタが返されないケヌスや、返されるデヌタが配列ではなくオブゞェクトであるケヌスが凊理されたす。 凊理されたデヌタはその埌、これたでに収集された、ペヌゞ分割されたすべおのデヌタを含むリストに远加されたす。 応答に link ヘッダヌが含たれおおり、link ヘッダヌに次のペヌゞのリンクが含たれおいる堎合、関数は 正芏衚珟パタヌン (nextPattern) を䜿甚しお次のペヌゞの URL を取埗したす。 関数は、今床はこの新しい URL を䜿甚しお、前のステップを繰り返したす。 link ヘッダヌに次のペヌゞぞのリンクが含たれなくなるず、すべおの結果が返されたす。

JavaScript
import { Octokit } from "octokit";

const octokit = new Octokit({ });

async function getPaginatedData(url) {
  const nextPattern = /(?<=<)([\S]*)(?=>; rel="Next")/i;
  let pagesRemaining = true;
  let data = [];

  while (pagesRemaining) {
    const response = await octokit.request(`GET ${url}`, {
      per_page: 100,
      headers: {
        "X-GitHub-Api-Version":
          "2022-11-28",
      },
    });

    const parsedData = parseData(response.data)
    data = [...data, ...parsedData];

    const linkHeader = response.headers.link;

    pagesRemaining = linkHeader && linkHeader.includes(`rel=\"next\"`);

    if (pagesRemaining) {
      url = linkHeader.match(nextPattern)[0];
    }
  }

  return data;
}

function parseData(data) {
  // If the data is an array, return that
    if (Array.isArray(data)) {
      return data
    }

  // Some endpoints respond with 204 No Content instead of empty array
  //   when there is no data. In that case, return an empty array.
  if (!data) {
    return []
  }

  // Otherwise, the array of items that we want is in an object
  // Delete keys that don't include the array of items
  delete data.incomplete_results;
  delete data.repository_selection;
  delete data.total_count;
  // Pull out the array of items
  const namespaceKey = Object.keys(data)[0];
  data = data[namespaceKey];

  return data;
}

const data = await getPaginatedData("/repos/octocat/Spoon-Knife/issues");

console.log(data);