1 | # request.js
|
2 |
|
3 | > Send parameterized requests to GitHub’s APIs with sensible defaults in browsers and Node
|
4 |
|
5 | [![@latest](https://img.shields.io/npm/v/@octokit/request.svg)](https://www.npmjs.com/package/@octokit/request)
|
6 | [![Build Status](https://github.com/octokit/request.js/workflows/Test/badge.svg)](https://github.com/octokit/request.js/actions?query=workflow%3ATest+branch%3Amaster)
|
7 |
|
8 | `@octokit/request` is a request library for browsers & node that makes it easier
|
9 | to interact with [GitHub’s REST API](https://developer.github.com/v3/) and
|
10 | [GitHub’s GraphQL API](https://developer.github.com/v4/guides/forming-calls/#the-graphql-endpoint).
|
11 |
|
12 | It uses [`@octokit/endpoint`](https://github.com/octokit/endpoint.js) to parse
|
13 | the passed options and sends the request using [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)
|
14 | ([node-fetch](https://github.com/bitinn/node-fetch) in Node).
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 | - [Features](#features)
|
21 | - [Usage](#usage)
|
22 | - [REST API example](#rest-api-example)
|
23 | - [GraphQL example](#graphql-example)
|
24 | - [Alternative: pass `method` & `url` as part of options](#alternative-pass-method--url-as-part-of-options)
|
25 | - [Authentication](#authentication)
|
26 | - [request()](#request)
|
27 | - [`request.defaults()`](#requestdefaults)
|
28 | - [`request.endpoint`](#requestendpoint)
|
29 | - [Special cases](#special-cases)
|
30 | - [The `data` parameter – set request body directly](#the-data-parameter-%E2%80%93-set-request-body-directly)
|
31 | - [Set parameters for both the URL/query and the request body](#set-parameters-for-both-the-urlquery-and-the-request-body)
|
32 | - [LICENSE](#license)
|
33 |
|
34 |
|
35 |
|
36 | ## Features
|
37 |
|
38 | 🤩 1:1 mapping of REST API endpoint documentation, e.g. [Add labels to an issue](https://developer.github.com/v3/issues/labels/#add-labels-to-an-issue) becomes
|
39 |
|
40 | ```js
|
41 | request("POST /repos/{owner}/{repo}/issues/{number}/labels", {
|
42 | mediaType: {
|
43 | previews: ["symmetra"],
|
44 | },
|
45 | owner: "octokit",
|
46 | repo: "request.js",
|
47 | number: 1,
|
48 | labels: ["🐛 bug"],
|
49 | });
|
50 | ```
|
51 |
|
52 | 👶 [Small bundle size](https://bundlephobia.com/result?p=@octokit/request@5.0.3) (\<4kb minified + gzipped)
|
53 |
|
54 | 😎 [Authenticate](#authentication) with any of [GitHubs Authentication Strategies](https://github.com/octokit/auth.js).
|
55 |
|
56 | 👍 Sensible defaults
|
57 |
|
58 | - `baseUrl`: `https://api.github.com`
|
59 | - `headers.accept`: `application/vnd.github.v3+json`
|
60 | - `headers.agent`: `octokit-request.js/<current version> <OS information>`, e.g. `octokit-request.js/1.2.3 Node.js/10.15.0 (macOS Mojave; x64)`
|
61 |
|
62 | 👌 Simple to test: mock requests by passing a custom fetch method.
|
63 |
|
64 | 🧐 Simple to debug: Sets `error.request` to request options causing the error (with redacted credentials).
|
65 |
|
66 | ## Usage
|
67 |
|
68 | <table>
|
69 | <tbody valign=top align=left>
|
70 | <tr><th>
|
71 | Browsers
|
72 | </th><td width=100%>
|
73 | Load <code>@octokit/request</code> directly from <a href="https://cdn.skypack.dev">cdn.skypack.dev</a>
|
74 |
|
75 | ```html
|
76 | <script type="module">
|
77 | import { request } from "https://cdn.skypack.dev/@octokit/request";
|
78 | </script>
|
79 | ```
|
80 |
|
81 | </td></tr>
|
82 | <tr><th>
|
83 | Node
|
84 | </th><td>
|
85 |
|
86 | Install with <code>npm install @octokit/request</code>
|
87 |
|
88 | ```js
|
89 | const { request } = require("@octokit/request");
|
90 | // or: import { request } from "@octokit/request";
|
91 | ```
|
92 |
|
93 | </td></tr>
|
94 | </tbody>
|
95 | </table>
|
96 |
|
97 | ### REST API example
|
98 |
|
99 | ```js
|
100 | // Following GitHub docs formatting:
|
101 | // https://developer.github.com/v3/repos/#list-organization-repositories
|
102 | const result = await request("GET /orgs/{org}/repos", {
|
103 | headers: {
|
104 | authorization: "token 0000000000000000000000000000000000000001",
|
105 | },
|
106 | org: "octokit",
|
107 | type: "private",
|
108 | });
|
109 |
|
110 | console.log(`${result.data.length} repos found.`);
|
111 | ```
|
112 |
|
113 | ### GraphQL example
|
114 |
|
115 | For GraphQL request we recommend using [`@octokit/graphql`](https://github.com/octokit/graphql.js#readme)
|
116 |
|
117 | ```js
|
118 | const result = await request("POST /graphql", {
|
119 | headers: {
|
120 | authorization: "token 0000000000000000000000000000000000000001",
|
121 | },
|
122 | query: `query ($login: String!) {
|
123 | organization(login: $login) {
|
124 | repositories(privacy: PRIVATE) {
|
125 | totalCount
|
126 | }
|
127 | }
|
128 | }`,
|
129 | variables: {
|
130 | login: "octokit",
|
131 | },
|
132 | });
|
133 | ```
|
134 |
|
135 | ### Alternative: pass `method` & `url` as part of options
|
136 |
|
137 | Alternatively, pass in a method and a url
|
138 |
|
139 | ```js
|
140 | const result = await request({
|
141 | method: "GET",
|
142 | url: "/orgs/{org}/repos",
|
143 | headers: {
|
144 | authorization: "token 0000000000000000000000000000000000000001",
|
145 | },
|
146 | org: "octokit",
|
147 | type: "private",
|
148 | });
|
149 | ```
|
150 |
|
151 | ## Authentication
|
152 |
|
153 | The simplest way to authenticate a request is to set the `Authorization` header directly, e.g. to a [personal access token](https://github.com/settings/tokens/).
|
154 |
|
155 | ```js
|
156 | const requestWithAuth = request.defaults({
|
157 | headers: {
|
158 | authorization: "token 0000000000000000000000000000000000000001",
|
159 | },
|
160 | });
|
161 | const result = await requestWithAuth("GET /user");
|
162 | ```
|
163 |
|
164 | For more complex authentication strategies such as GitHub Apps or Basic, we recommend the according authentication library exported by [`@octokit/auth`](https://github.com/octokit/auth.js).
|
165 |
|
166 | ```js
|
167 | const { createAppAuth } = require("@octokit/auth-app");
|
168 | const auth = createAppAuth({
|
169 | appId: process.env.APP_ID,
|
170 | privateKey: process.env.PRIVATE_KEY,
|
171 | installationId: 123,
|
172 | });
|
173 | const requestWithAuth = request.defaults({
|
174 | request: {
|
175 | hook: auth.hook,
|
176 | },
|
177 | mediaType: {
|
178 | previews: ["machine-man"],
|
179 | },
|
180 | });
|
181 |
|
182 | const { data: app } = await requestWithAuth("GET /app");
|
183 | const { data: app } = await requestWithAuth(
|
184 | "POST /repos/{owner}/{repo}/issues",
|
185 | {
|
186 | owner: "octocat",
|
187 | repo: "hello-world",
|
188 | title: "Hello from the engine room",
|
189 | }
|
190 | );
|
191 | ```
|
192 |
|
193 | ## request()
|
194 |
|
195 | `request(route, options)` or `request(options)`.
|
196 |
|
197 | **Options**
|
198 |
|
199 | <table>
|
200 | <thead>
|
201 | <tr>
|
202 | <th align=left>
|
203 | name
|
204 | </th>
|
205 | <th align=left>
|
206 | type
|
207 | </th>
|
208 | <th align=left>
|
209 | description
|
210 | </th>
|
211 | </tr>
|
212 | </thead>
|
213 | <tr>
|
214 | <th align=left>
|
215 | <code>route</code>
|
216 | </th>
|
217 | <td>
|
218 | String
|
219 | </td>
|
220 | <td>
|
221 | **Required**. If <code>route</code> is set it has to be a string consisting of the request method and URL, e.g. <code>GET /orgs/{org}</code>
|
222 | </td>
|
223 | </tr>
|
224 | <tr>
|
225 | <th align=left>
|
226 | <code>options.baseUrl</code>
|
227 | </th>
|
228 | <td>
|
229 | String
|
230 | </td>
|
231 | <td>
|
232 | The base URL that <code>route</code> or <code>url</code> will be prefixed with, if they use relative paths. <em>Defaults to <code>https://api.github.com</code></em>.
|
233 | </td>
|
234 | </tr>
|
235 | <th align=left>
|
236 | <code>options.headers</code>
|
237 | </th>
|
238 | <td>
|
239 | Object
|
240 | </td>
|
241 | <td>
|
242 | Custom headers. Passed headers are merged with defaults:<br>
|
243 | <em><code>headers['user-agent']</code> defaults to <code>octokit-rest.js/1.2.3</code> (where <code>1.2.3</code> is the released version)</em>.<br>
|
244 | <em><code>headers['accept']</code> defaults to <code>application/vnd.github.v3+json</code>.<br> Use <code>options.mediaType.{format,previews}</code> to request API previews and custom media types.
|
245 | </td>
|
246 | </tr>
|
247 | <tr>
|
248 | <th align=left>
|
249 | <code>options.mediaType.format</code>
|
250 | </th>
|
251 | <td>
|
252 | String
|
253 | </td>
|
254 | <td>
|
255 | Media type param, such as `raw`, `html`, or `full`. See <a href="https://developer.github.com/v3/media/">Media Types</a>.
|
256 | </td>
|
257 | </tr>
|
258 | <tr>
|
259 | <th align=left>
|
260 | <code>options.mediaType.previews</code>
|
261 | </th>
|
262 | <td>
|
263 | Array of strings
|
264 | </td>
|
265 | <td>
|
266 | Name of previews, such as `mercy`, `symmetra`, or `scarlet-witch`. See <a href="https://developer.github.com/v3/previews/">API Previews</a>.
|
267 | </td>
|
268 | </tr>
|
269 | <tr>
|
270 | <th align=left>
|
271 | <code>options.method</code>
|
272 | </th>
|
273 | <td>
|
274 | String
|
275 | </td>
|
276 | <td>
|
277 | Any supported <a href="https://developer.github.com/v3/#http-verbs">http verb</a>, case insensitive. <em>Defaults to <code>Get</code></em>.
|
278 | </td>
|
279 | </tr>
|
280 | <tr>
|
281 | <th align=left>
|
282 | <code>options.url</code>
|
283 | </th>
|
284 | <td>
|
285 | String
|
286 | </td>
|
287 | <td>
|
288 | **Required**. A path or full URL which may contain <code>:variable</code> or <code>{variable}</code> placeholders,
|
289 | e.g. <code>/orgs/{org}/repos</code>. The <code>url</code> is parsed using <a href="https://github.com/bramstein/url-template">url-template</a>.
|
290 | </td>
|
291 | </tr>
|
292 | <tr>
|
293 | <th align=left>
|
294 | <code>options.data</code>
|
295 | </th>
|
296 | <td>
|
297 | Any
|
298 | </td>
|
299 | <td>
|
300 | Set request body directly instead of setting it to JSON based on additional parameters. See <a href="#data-parameter">"The `data` parameter"</a> below.
|
301 | </td>
|
302 | </tr>
|
303 | <tr>
|
304 | <th align=left>
|
305 | <code>options.request.agent</code>
|
306 | </th>
|
307 | <td>
|
308 | <a href="https://nodejs.org/api/http.html#http_class_http_agent">http(s).Agent</a> instance
|
309 | </td>
|
310 | <td>
|
311 | Node only. Useful for custom proxy, certificate, or dns lookup.
|
312 | </td>
|
313 | </tr>
|
314 | <tr>
|
315 | <th align=left>
|
316 | <code>options.request.fetch</code>
|
317 | </th>
|
318 | <td>
|
319 | Function
|
320 | </td>
|
321 | <td>
|
322 | Custom replacement for <a href="https://github.com/bitinn/node-fetch">built-in fetch method</a>. Useful for testing or request hooks.
|
323 | </td>
|
324 | </tr>
|
325 | <tr>
|
326 | <th align=left>
|
327 | <code>options.request.hook</code>
|
328 | </th>
|
329 | <td>
|
330 | Function
|
331 | </td>
|
332 | <td>
|
333 | Function with the signature <code>hook(request, endpointOptions)</code>, where <code>endpointOptions</code> are the parsed options as returned by <a href="https://github.com/octokit/endpoint.js#endpointmergeroute-options-or-endpointmergeoptions"><code>endpoint.merge()</code></a>, and <code>request</code> is <a href="https://github.com/octokit/request.js#request"><code>request()</code></a>. This option works great in conjuction with <a href="https://github.com/gr2m/before-after-hook">before-after-hook</a>.
|
334 | </td>
|
335 | </tr>
|
336 | <tr>
|
337 | <th align=left>
|
338 | <a name="options-request-signal"></a><code>options.request.signal</code>
|
339 | </th>
|
340 | <td>
|
341 | <a href="https://github.com/bitinn/node-fetch/tree/e996bdab73baf996cf2dbf25643c8fe2698c3249#request-cancellation-with-abortsignal">new AbortController().signal</a>
|
342 | </td>
|
343 | <td>
|
344 | Use an <code>AbortController</code> instance to cancel a request. In node you can only cancel streamed requests.
|
345 | </td>
|
346 | </tr>
|
347 | <th align=left>
|
348 | <code>options.request.log</code>
|
349 | </th>
|
350 | <td>
|
351 | <code>object</code>
|
352 | </td>
|
353 | <td>
|
354 | Used for internal logging. Defaults to <a href="https://developer.mozilla.org/en-US/docs/Web/API/console"><code>console</code></a>.
|
355 | </td>
|
356 | </tr>
|
357 | <tr>
|
358 | <th align=left>
|
359 | <code>options.request.timeout</code>
|
360 | </th>
|
361 | <td>
|
362 | Number
|
363 | </td>
|
364 | <td>
|
365 | Node only. Request/response timeout in ms, it resets on redirect. 0 to disable (OS limit applies). <a href="#options-request-signal">options.request.signal</a> is recommended instead.
|
366 | </td>
|
367 | </tr>
|
368 | </table>
|
369 |
|
370 | All other options except `options.request.*` will be passed depending on the `method` and `url` options.
|
371 |
|
372 | 1. If the option key is a placeholder in the `url`, it will be used as replacement. For example, if the passed options are `{url: '/orgs/{org}/repos', org: 'foo'}` the returned `options.url` is `https://api.github.com/orgs/foo/repos`
|
373 | 2. If the `method` is `GET` or `HEAD`, the option is passed as query parameter
|
374 | 3. Otherwise the parameter is passed in the request body as JSON key.
|
375 |
|
376 | **Result**
|
377 |
|
378 | `request` returns a promise and resolves with 4 keys
|
379 |
|
380 | <table>
|
381 | <thead>
|
382 | <tr>
|
383 | <th align=left>
|
384 | key
|
385 | </th>
|
386 | <th align=left>
|
387 | type
|
388 | </th>
|
389 | <th align=left>
|
390 | description
|
391 | </th>
|
392 | </tr>
|
393 | </thead>
|
394 | <tr>
|
395 | <th align=left><code>status</code></th>
|
396 | <td>Integer</td>
|
397 | <td>Response status status</td>
|
398 | </tr>
|
399 | <tr>
|
400 | <th align=left><code>url</code></th>
|
401 | <td>String</td>
|
402 | <td>URL of response. If a request results in redirects, this is the final URL. You can send a <code>HEAD</code> request to retrieve it without loading the full response body.</td>
|
403 | </tr>
|
404 | <tr>
|
405 | <th align=left><code>headers</code></th>
|
406 | <td>Object</td>
|
407 | <td>All response headers</td>
|
408 | </tr>
|
409 | <tr>
|
410 | <th align=left><code>data</code></th>
|
411 | <td>Any</td>
|
412 | <td>The response body as returned from server. If the response is JSON then it will be parsed into an object</td>
|
413 | </tr>
|
414 | </table>
|
415 |
|
416 | If an error occurs, the `error` instance has additional properties to help with debugging
|
417 |
|
418 | - `error.status` The http response status code
|
419 | - `error.request` The request options such as `method`, `url` and `data`
|
420 | - `error.response` The http response object with `url`, `headers`, and `data`
|
421 |
|
422 | ## `request.defaults()`
|
423 |
|
424 | Override or set default options. Example:
|
425 |
|
426 | ```js
|
427 | const myrequest = require("@octokit/request").defaults({
|
428 | baseUrl: "https://github-enterprise.acme-inc.com/api/v3",
|
429 | headers: {
|
430 | "user-agent": "myApp/1.2.3",
|
431 | authorization: `token 0000000000000000000000000000000000000001`,
|
432 | },
|
433 | org: "my-project",
|
434 | per_page: 100,
|
435 | });
|
436 |
|
437 | myrequest(`GET /orgs/{org}/repos`);
|
438 | ```
|
439 |
|
440 | You can call `.defaults()` again on the returned method, the defaults will cascade.
|
441 |
|
442 | ```js
|
443 | const myProjectRequest = request.defaults({
|
444 | baseUrl: "https://github-enterprise.acme-inc.com/api/v3",
|
445 | headers: {
|
446 | "user-agent": "myApp/1.2.3",
|
447 | },
|
448 | org: "my-project",
|
449 | });
|
450 | const myProjectRequestWithAuth = myProjectRequest.defaults({
|
451 | headers: {
|
452 | authorization: `token 0000000000000000000000000000000000000001`,
|
453 | },
|
454 | });
|
455 | ```
|
456 |
|
457 | `myProjectRequest` now defaults the `baseUrl`, `headers['user-agent']`,
|
458 | `org` and `headers['authorization']` on top of `headers['accept']` that is set
|
459 | by the global default.
|
460 |
|
461 | ## `request.endpoint`
|
462 |
|
463 | See https://github.com/octokit/endpoint.js. Example
|
464 |
|
465 | ```js
|
466 | const options = request.endpoint("GET /orgs/{org}/repos", {
|
467 | org: "my-project",
|
468 | type: "private",
|
469 | });
|
470 |
|
471 | // {
|
472 | // method: 'GET',
|
473 | // url: 'https://api.github.com/orgs/my-project/repos?type=private',
|
474 | // headers: {
|
475 | // accept: 'application/vnd.github.v3+json',
|
476 | // authorization: 'token 0000000000000000000000000000000000000001',
|
477 | // 'user-agent': 'octokit/endpoint.js v1.2.3'
|
478 | // }
|
479 | // }
|
480 | ```
|
481 |
|
482 | All of the [`@octokit/endpoint`](https://github.com/octokit/endpoint.js) API can be used:
|
483 |
|
484 | - [`octokitRequest.endpoint()`](#endpoint)
|
485 | - [`octokitRequest.endpoint.defaults()`](#endpointdefaults)
|
486 | - [`octokitRequest.endpoint.merge()`](#endpointdefaults)
|
487 | - [`octokitRequest.endpoint.parse()`](#endpointmerge)
|
488 |
|
489 | ## Special cases
|
490 |
|
491 | <a name="data-parameter"></a>
|
492 |
|
493 | ### The `data` parameter – set request body directly
|
494 |
|
495 | Some endpoints such as [Render a Markdown document in raw mode](https://developer.github.com/v3/markdown/#render-a-markdown-document-in-raw-mode) don’t have parameters that are sent as request body keys, instead the request body needs to be set directly. In these cases, set the `data` parameter.
|
496 |
|
497 | ```js
|
498 | const response = await request("POST /markdown/raw", {
|
499 | data: "Hello world github/linguist#1 **cool**, and #1!",
|
500 | headers: {
|
501 | accept: "text/html;charset=utf-8",
|
502 | "content-type": "text/plain",
|
503 | },
|
504 | });
|
505 |
|
506 | // Request is sent as
|
507 | //
|
508 | // {
|
509 | // method: 'post',
|
510 | // url: 'https://api.github.com/markdown/raw',
|
511 | // headers: {
|
512 | // accept: 'text/html;charset=utf-8',
|
513 | // 'content-type': 'text/plain',
|
514 | // 'user-agent': userAgent
|
515 | // },
|
516 | // body: 'Hello world github/linguist#1 **cool**, and #1!'
|
517 | // }
|
518 | //
|
519 | // not as
|
520 | //
|
521 | // {
|
522 | // ...
|
523 | // body: '{"data": "Hello world github/linguist#1 **cool**, and #1!"}'
|
524 | // }
|
525 | ```
|
526 |
|
527 | ### Set parameters for both the URL/query and the request body
|
528 |
|
529 | There are API endpoints that accept both query parameters as well as a body. In that case you need to add the query parameters as templates to `options.url`, as defined in the [RFC 6570 URI Template specification](https://tools.ietf.org/html/rfc6570).
|
530 |
|
531 | Example
|
532 |
|
533 | ```js
|
534 | request(
|
535 | "POST https://uploads.github.com/repos/octocat/Hello-World/releases/1/assets{?name,label}",
|
536 | {
|
537 | name: "example.zip",
|
538 | label: "short description",
|
539 | headers: {
|
540 | "content-type": "text/plain",
|
541 | "content-length": 14,
|
542 | authorization: `token 0000000000000000000000000000000000000001`,
|
543 | },
|
544 | data: "Hello, world!",
|
545 | }
|
546 | );
|
547 | ```
|
548 |
|
549 | ## LICENSE
|
550 |
|
551 | [MIT](LICENSE)
|