cloudflare/cloudflare-typescript

Public

mirrored from https://github.com/cloudflare/cloudflare-typescriptAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v4.2.0

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

README.md

396lines · modecode

1# Cloudflare Typescript API Library
2
3[![NPM version](https://img.shields.io/npm/v/cloudflare.svg)](https://npmjs.org/package/cloudflare) ![npm bundle size](https://img.shields.io/bundlephobia/minzip/cloudflare)
4
5This library provides convenient access to the Cloudflare REST API from server-side TypeScript or JavaScript.
6
7The REST API documentation can be found on [developers.cloudflare.com](https://developers.cloudflare.com/api). The full API of this library can be found in [api.md](api.md).
8
9## Installation
10
11```sh
12npm install cloudflare
13```
14
15## Usage
16
17The full API of this library can be found in [api.md](api.md).
18
19<!-- prettier-ignore -->
20```js
21import Cloudflare from 'cloudflare';
22
23const client = new Cloudflare({
24 apiEmail: process.env['CLOUDFLARE_EMAIL'], // This is the default and can be omitted
25 apiKey: process.env['CLOUDFLARE_API_KEY'], // This is the default and can be omitted
26});
27
28async function main() {
29 const zone = await client.zones.create({
30 account: { id: '023e105f4ecef8ad9ca31a8372d0c353' },
31 name: 'example.com',
32 type: 'full',
33 });
34
35 console.log(zone.id);
36}
37
38main();
39```
40
41### Request & Response types
42
43This library includes TypeScript definitions for all request params and response fields. You may import and use them like so:
44
45<!-- prettier-ignore -->
46```ts
47import Cloudflare from 'cloudflare';
48
49const client = new Cloudflare({
50 apiEmail: process.env['CLOUDFLARE_EMAIL'], // This is the default and can be omitted
51 apiKey: process.env['CLOUDFLARE_API_KEY'], // This is the default and can be omitted
52});
53
54async function main() {
55 const params: Cloudflare.ZoneCreateParams = {
56 account: { id: '023e105f4ecef8ad9ca31a8372d0c353' },
57 name: 'example.com',
58 type: 'full',
59 };
60 const zone: Cloudflare.Zone = await client.zones.create(params);
61}
62
63main();
64```
65
66Documentation for each method, request param, and response field are available in docstrings and will appear on hover in most modern editors.
67
68## File uploads
69
70Request parameters that correspond to file uploads can be passed in many different forms:
71
72- `File` (or an object with the same structure)
73- a `fetch` `Response` (or an object with the same structure)
74- an `fs.ReadStream`
75- the return value of our `toFile` helper
76
77```ts
78import fs from 'fs';
79import fetch from 'node-fetch';
80import Cloudflare, { toFile } from 'cloudflare';
81
82const client = new Cloudflare();
83
84// If you have access to Node `fs` we recommend using `fs.createReadStream()`:
85await client.apiGateway.userSchemas.create({
86 zone_id: '023e105f4ecef8ad9ca31a8372d0c353',
87 file: fs.createReadStream('/path/to/file'),
88 kind: 'openapi_v3',
89});
90
91// Or if you have the web `File` API you can pass a `File` instance:
92await client.apiGateway.userSchemas.create({
93 zone_id: '023e105f4ecef8ad9ca31a8372d0c353',
94 file: new File(['my bytes'], 'file'),
95 kind: 'openapi_v3',
96});
97
98// You can also pass a `fetch` `Response`:
99await client.apiGateway.userSchemas.create({
100 zone_id: '023e105f4ecef8ad9ca31a8372d0c353',
101 file: await fetch('https://somesite/file'),
102 kind: 'openapi_v3',
103});
104
105// Finally, if none of the above are convenient, you can use our `toFile` helper:
106await client.apiGateway.userSchemas.create({
107 zone_id: '023e105f4ecef8ad9ca31a8372d0c353',
108 file: await toFile(Buffer.from('my bytes'), 'file'),
109 kind: 'openapi_v3',
110});
111await client.apiGateway.userSchemas.create({
112 zone_id: '023e105f4ecef8ad9ca31a8372d0c353',
113 file: await toFile(new Uint8Array([0, 1, 2]), 'file'),
114 kind: 'openapi_v3',
115});
116```
117
118## Handling errors
119
120When the library is unable to connect to the API,
121or if the API returns a non-success status code (i.e., 4xx or 5xx response),
122a subclass of `APIError` will be thrown:
123
124<!-- prettier-ignore -->
125```ts
126async function main() {
127 const zone = await client.zones.get({ zone_id: '023e105f4ecef8ad9ca31a8372d0c353' }).catch(async (err) => {
128 if (err instanceof Cloudflare.APIError) {
129 console.log(err.status); // 400
130 console.log(err.name); // BadRequestError
131 console.log(err.headers); // {server: 'nginx', ...}
132 } else {
133 throw err;
134 }
135 });
136}
137
138main();
139```
140
141Error codes are as followed:
142
143| Status Code | Error Type |
144| ----------- | -------------------------- |
145| 400 | `BadRequestError` |
146| 401 | `AuthenticationError` |
147| 403 | `PermissionDeniedError` |
148| 404 | `NotFoundError` |
149| 422 | `UnprocessableEntityError` |
150| 429 | `RateLimitError` |
151| >=500 | `InternalServerError` |
152| N/A | `APIConnectionError` |
153
154### Retries
155
156Certain errors will be automatically retried 2 times by default, with a short exponential backoff.
157Connection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict,
158429 Rate Limit, and >=500 Internal errors will all be retried by default.
159
160You can use the `maxRetries` option to configure or disable this:
161
162<!-- prettier-ignore -->
163```js
164// Configure the default for all requests:
165const client = new Cloudflare({
166 maxRetries: 0, // default is 2
167});
168
169// Or, configure per-request:
170await client.zones.get({ zone_id: '023e105f4ecef8ad9ca31a8372d0c353' }, {
171 maxRetries: 5,
172});
173```
174
175### Timeouts
176
177Requests time out after 1 minute by default. You can configure this with a `timeout` option:
178
179<!-- prettier-ignore -->
180```ts
181// Configure the default for all requests:
182const client = new Cloudflare({
183 timeout: 20 * 1000, // 20 seconds (default is 1 minute)
184});
185
186// Override per-request:
187await client.zones.edit({ zone_id: '023e105f4ecef8ad9ca31a8372d0c353' }, {
188 timeout: 5 * 1000,
189});
190```
191
192On timeout, an `APIConnectionTimeoutError` is thrown.
193
194Note that requests which time out will be [retried twice by default](#retries).
195
196## Auto-pagination
197
198List methods in the Cloudflare API are paginated.
199You can use the `for await … of` syntax to iterate through items across all pages:
200
201```ts
202async function fetchAllAccounts(params) {
203 const allAccounts = [];
204 // Automatically fetches more pages as needed.
205 for await (const account of client.accounts.list()) {
206 allAccounts.push(account);
207 }
208 return allAccounts;
209}
210```
211
212Alternatively, you can request a single page at a time:
213
214```ts
215let page = await client.accounts.list();
216for (const account of page.result) {
217 console.log(account);
218}
219
220// Convenience methods are provided for manually paginating:
221while (page.hasNextPage()) {
222 page = await page.getNextPage();
223 // ...
224}
225```
226
227## Advanced Usage
228
229### Accessing raw Response data (e.g., headers)
230
231The "raw" `Response` returned by `fetch()` can be accessed through the `.asResponse()` method on the `APIPromise` type that all methods return.
232
233You can also use the `.withResponse()` method to get the raw `Response` along with the parsed data.
234
235<!-- prettier-ignore -->
236```ts
237const client = new Cloudflare();
238
239const response = await client.zones
240 .create({ account: { id: '023e105f4ecef8ad9ca31a8372d0c353' }, name: 'example.com', type: 'full' })
241 .asResponse();
242console.log(response.headers.get('X-My-Header'));
243console.log(response.statusText); // access the underlying Response object
244
245const { data: zone, response: raw } = await client.zones
246 .create({ account: { id: '023e105f4ecef8ad9ca31a8372d0c353' }, name: 'example.com', type: 'full' })
247 .withResponse();
248console.log(raw.headers.get('X-My-Header'));
249console.log(zone.id);
250```
251
252### Making custom/undocumented requests
253
254This library is typed for convenient access to the documented API. If you need to access undocumented
255endpoints, params, or response properties, the library can still be used.
256
257#### Undocumented endpoints
258
259To make requests to undocumented endpoints, you can use `client.get`, `client.post`, and other HTTP verbs.
260Options on the client, such as retries, will be respected when making these requests.
261
262```ts
263await client.post('/some/path', {
264 body: { some_prop: 'foo' },
265 query: { some_query_arg: 'bar' },
266});
267```
268
269#### Undocumented request params
270
271To make requests using undocumented parameters, you may use `// @ts-expect-error` on the undocumented
272parameter. This library doesn't validate at runtime that the request matches the type, so any extra values you
273send will be sent as-is.
274
275```ts
276client.foo.create({
277 foo: 'my_param',
278 bar: 12,
279 // @ts-expect-error baz is not yet public
280 baz: 'undocumented option',
281});
282```
283
284For requests with the `GET` verb, any extra params will be in the query, all other requests will send the
285extra param in the body.
286
287If you want to explicitly send an extra argument, you can do so with the `query`, `body`, and `headers` request
288options.
289
290#### Undocumented response properties
291
292To access undocumented response properties, you may access the response object with `// @ts-expect-error` on
293the response object, or cast the response object to the requisite type. Like the request params, we do not
294validate or strip extra properties from the response from the API.
295
296### Customizing the fetch client
297
298By default, this library uses `node-fetch` in Node, and expects a global `fetch` function in other environments.
299
300If you would prefer to use a global, web-standards-compliant `fetch` function even in a Node environment,
301(for example, if you are running Node with `--experimental-fetch` or using NextJS which polyfills with `undici`),
302add the following import before your first import `from "Cloudflare"`:
303
304```ts
305// Tell TypeScript and the package to use the global web fetch instead of node-fetch.
306// Note, despite the name, this does not add any polyfills, but expects them to be provided if needed.
307import 'cloudflare/shims/web';
308import Cloudflare from 'cloudflare';
309```
310
311To do the inverse, add `import "cloudflare/shims/node"` (which does import polyfills).
312This can also be useful if you are getting the wrong TypeScript types for `Response` ([more details](https://github.com/cloudflare/cloudflare-typescript/tree/main/src/_shims#readme)).
313
314### Logging and middleware
315
316You may also provide a custom `fetch` function when instantiating the client,
317which can be used to inspect or alter the `Request` or `Response` before/after each request:
318
319```ts
320import { fetch } from 'undici'; // as one example
321import Cloudflare from 'cloudflare';
322
323const client = new Cloudflare({
324 fetch: async (url: RequestInfo, init?: RequestInit): Promise<Response> => {
325 console.log('About to make a request', url, init);
326 const response = await fetch(url, init);
327 console.log('Got response', response);
328 return response;
329 },
330});
331```
332
333Note that if given a `DEBUG=true` environment variable, this library will log all requests and responses automatically.
334This is intended for debugging purposes only and may change in the future without notice.
335
336### Configuring an HTTP(S) Agent (e.g., for proxies)
337
338By default, this library uses a stable agent for all http/https requests to reuse TCP connections, eliminating many TCP & TLS handshakes and shaving around 100ms off most requests.
339
340If you would like to disable or customize this behavior, for example to use the API behind a proxy, you can pass an `httpAgent` which is used for all requests (be they http or https), for example:
341
342<!-- prettier-ignore -->
343```ts
344import http from 'http';
345import { HttpsProxyAgent } from 'https-proxy-agent';
346
347// Configure the default for all requests:
348const client = new Cloudflare({
349 httpAgent: new HttpsProxyAgent(process.env.PROXY_URL),
350});
351
352// Override per-request:
353await client.zones.delete(
354 { zone_id: '023e105f4ecef8ad9ca31a8372d0c353' },
355 {
356 httpAgent: new http.Agent({ keepAlive: false }),
357 },
358);
359```
360
361## Semantic versioning
362
363This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:
364
3651. Changes that only affect static types, without breaking runtime behavior.
3661. Changes to library internals which are technically public but not intended or documented for external use.
3671. Changes that we do not expect to impact the vast majority of users in practice.
368
369## Requirements
370
371TypeScript >= 4.5 is supported.
372
373The following runtimes are supported:
374
375- Web browsers (Up-to-date Chrome, Firefox, Safari, Edge, and more)
376- Node.js 18 LTS or later ([non-EOL](https://endoflife.date/nodejs)) versions.
377- Deno v1.28.0 or higher.
378- Bun 1.0 or later.
379- Cloudflare Workers.
380- Vercel Edge Runtime.
381- Jest 28 or greater with the `"node"` environment (`"jsdom"` is not supported at this time).
382- Nitro v2.6 or greater.
383
384Note that React Native is not supported at this time.
385
386If you are interested in other runtime environments, please open or upvote an issue on GitHub.
387
388## Maintenance
389
390This SDK is actively maintained, however, many issues are tracked outside of GitHub on internal Cloudflare systems. Members of the community are welcome to join and discuss your issues during our twice monthly triage meetings. For urgent issues, please contact [Cloudflare support](https://www.support.cloudflare.com/s/?language=en_US).
391
392* [Community triage meeting](https://calendar.google.com/calendar/embed?src=c_dbf6ce250643f2e60f806d28f3fc09a9de24cbe0ab3ffb699838303d2adfc9e4%40group.calendar.google.com&ctz=America%2FLos_Angeles)
393
394## Contributing
395
396See [the contributing documentation](./CONTRIBUTING.md).
397