Skip to content

Commit 29d8e50

Browse files
joshfreeCopilot
andauthored
REST API best practices: guidance for efficient polling and caching (#62431)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4959e1f9-f8e6-4e97-a487-f395a0123c79
1 parent f3b6a19 commit 29d8e50

1 file changed

Lines changed: 52 additions & 7 deletions

File tree

content/rest/using-the-rest-api/best-practices-for-using-the-rest-api.md

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ category:
2626

2727
You should subscribe to webhook events instead of polling the API for data. This will help your integration stay within the API rate limit. For more information, see [AUTOTITLE](/webhooks).
2828

29+
If you cannot use webhooks and you must poll the API, poll as efficiently as possible to avoid exceeding the rate limit:
30+
31+
* Poll only as often as you need to, on a fixed schedule. If a response includes an `x-poll-interval` header, wait at least that many seconds before you poll the same endpoint again.
32+
* Make authenticated conditional requests, so that unchanged data does not count against your primary rate limit. For more information, see [Use conditional requests](#use-conditional-requests).
33+
* Request only the data that you need, and keep responses stable, so that more of your polls return `304 Not Modified`. For more information, see [Make requests that can be cached](#make-requests-that-can-be-cached).
34+
2935
## Make authenticated requests
3036

3137
Authenticated requests have a higher primary rate limit than unauthenticated requests. To avoid exceeding the rate limit, you should make authenticated requests. For more information, see [AUTOTITLE](/rest/using-the-rest-api/rate-limits-for-the-rest-api).
@@ -67,28 +73,67 @@ Many API endpoints return URL values for fields in the response body. You should
6773

6874
Similarly, you should not try to manually construct pagination queries. Instead, you should use the link headers to determine what pages of results you can request. For more information, see [AUTOTITLE](/rest/using-the-rest-api/using-pagination-in-the-rest-api).
6975

70-
## Use conditional requests if appropriate
76+
## Use conditional requests
77+
78+
Most endpoints return an `etag` header, and many endpoints return a `last-modified` header. You can use the values of these headers to make conditional `GET` requests. If the response has not changed, you will receive a `304 Not Modified` response. Making a conditional request does not count against your primary rate limit if a `304` response is returned and the request was made while correctly authorized with an `Authorization` header. This makes conditional requests especially useful when you poll an endpoint, because each `304 Not Modified` response is fast and does not use your rate limit.
79+
80+
In the following examples, replace `YOUR-TOKEN` with your access token.{% ifversion ghes %} Replace `REPO-OWNER` with the account that owns the repository, and replace `REPO-NAME` with the name of the repository.{% endif %}
81+
82+
To make a conditional request with an `etag`:
83+
84+
1. Make a request and save the value of the `etag` header from the response.
85+
86+
```shell
87+
curl --include --header "Authorization: Bearer YOUR-TOKEN" {% data variables.product.rest_url %}/repos/{% ifversion ghes %}REPO-OWNER/REPO-NAME{% else %}octocat/Spoon-Knife{% endif %}/pulls
88+
```
89+
90+
The response includes an `etag` header:
91+
92+
```text
93+
HTTP/2 200
94+
etag: "644b5b0155e6404a9cc4bd9d8b1ae730"
95+
```
96+
97+
1. On your next request to the same URL, send the saved value in the `if-none-match` header.
7198

72-
Most endpoints return an `etag` header, and many endpoints return a `last-modified` header. You can use the values of these headers to make conditional `GET` requests. If the response has not changed, you will receive a `304 Not Modified` response. Making a conditional request does not count against your primary rate limit if a `304` response is returned and the request was made while correctly authorized with an `Authorization` header.
99+
```shell
100+
curl --include --header "Authorization: Bearer YOUR-TOKEN" --header 'if-none-match: "644b5b0155e6404a9cc4bd9d8b1ae730"' {% data variables.product.rest_url %}/repos/{% ifversion ghes %}REPO-OWNER/REPO-NAME{% else %}octocat/Spoon-Knife{% endif %}/pulls
101+
```
73102

74-
For example, if a previous request returned an `etag` header value of `644b5b0155e6404a9cc4bd9d8b1ae730`, you can use the `if-none-match` header in a future request:
103+
If the data has not changed, you will receive a `304 Not Modified` response, which does not count against your primary rate limit:
104+
105+
```text
106+
HTTP/2 304
107+
```
108+
109+
You can also use the `last-modified` header. For example, if a previous request returned a `last-modified` header value of `Wed, 25 Oct 2023 19:17:59 GMT`, you can use the `if-modified-since` header in a future request:
75110

76111
```shell
77-
curl -H "Authorization: Bearer YOUR-TOKEN" {% data variables.product.rest_url %}/meta --include --header 'if-none-match: "644b5b0155e6404a9cc4bd9d8b1ae730"'
112+
curl --include --header "Authorization: Bearer YOUR-TOKEN" --header 'if-modified-since: Wed, 25 Oct 2023 19:17:59 GMT' {% data variables.product.rest_url %}/repos/{% ifversion ghes %}REPO-OWNER/REPO-NAME{% else %}octocat/Spoon-Knife{% endif %}
78113
```
79114

80-
For example, if a previous request returned a `last-modified` header value of `Wed, 25 Oct 2023 19:17:59 GMT`, you can use the `if-modified-since` header in a future request:
115+
Conditional requests for unsafe methods, such as `POST`, `PUT`, `PATCH`, and `DELETE` are not supported unless otherwise noted in the documentation for a specific endpoint.
116+
117+
## Make requests that can be cached
118+
119+
A conditional request only saves you time and rate limit if the endpoint returns `304 Not Modified`. The endpoint returns `304` when the representation that you requested has not changed since you saved its `etag` or `last-modified` value; unrelated response headers, such as the date, can still differ. To make `304` responses more likely when you poll, keep your requests stable and specific.
120+
121+
Request only the data that you need. A smaller, more specific response changes less often, so it returns `304 Not Modified` more often. For example, to check the pull requests for one branch, filter the list by that branch instead of listing every pull request and searching the results yourself. Replace `HEAD-OWNER` with the account that owns the head branch; for a pull request from a fork, this is the account that owns the fork. Replace `BRANCH-NAME` with the name of the branch, and URL-encode it if it contains special characters such as `#` or `&`:
81122

82123
```shell
83-
curl -H "Authorization: Bearer YOUR-TOKEN" {% data variables.product.rest_url %}/repos/github/docs --include --header 'if-modified-since: Wed, 25 Oct 2023 19:17:59 GMT'
124+
curl --include --header "Authorization: Bearer YOUR-TOKEN" "{% data variables.product.rest_url %}/repos/{% ifversion ghes %}REPO-OWNER/REPO-NAME{% else %}octocat/Spoon-Knife{% endif %}/pulls?head=HEAD-OWNER:BRANCH-NAME"
84125
```
85126

86-
Conditional requests for unsafe methods, such as `POST`, `PUT`, `PATCH`, and `DELETE` are not supported unless otherwise noted in the documentation for a specific endpoint.
127+
If you page through a list, use a stable sort order. Some parameters, such as `sort=updated`, reorder the list whenever an item changes. When an item moves to a new position, the items between its old and new positions shift onto different pages, so pages that you already fetched can return new data instead of `304 Not Modified`. A stable order, such as the default, stops updates to existing items from reordering the list, although adding or removing items can still shift entries onto other pages.
128+
129+
Use the same parameters every time you poll the same data. A different page size, page number, or filter produces a different response with a different `etag`.
87130

88131
## Do not ignore errors
89132

90133
You should not ignore repeated `4xx` and `5xx` error codes. Instead, you should ensure that you are correctly interacting with the API. For example, if an endpoint requests a string and you are passing it a numeric value, you will receive a validation error. Similarly, attempting to access an unauthorized or nonexistent endpoint will result in a `4xx` error.
91134

135+
If you are polling and a resource repeatedly returns a `404 Not Found` response, do not keep requesting it on every poll. First, make sure that the `404` is not caused by authentication or authorization. {% data variables.product.company_short %} returns a `404 Not Found` response instead of a `403 Forbidden` response for some private resources when your credentials do not grant access, so a `404` does not always mean that the resource is absent. For more information, see [AUTOTITLE](/rest/using-the-rest-api/troubleshooting-the-rest-api#404-not-found-for-an-existing-resource). Once you have confirmed that your credentials are correct, wait much longer before you check again, or check again only when you have a reason to believe that the resource now exists. Repeatedly requesting a missing resource wastes your rate limit and can trigger a secondary rate limit.
136+
92137
Intentionally ignoring repeated validation errors may result in the suspension of your app for abuse.
93138

94139
## Further reading

0 commit comments

Comments
 (0)