Skip to content

Commit

Permalink
feat: fetch (POC)
Browse files Browse the repository at this point in the history
  • Loading branch information
danielbankhead committed Apr 19, 2024
1 parent 0cc7856 commit 23e7626
Show file tree
Hide file tree
Showing 6 changed files with 186 additions and 255 deletions.
12 changes: 4 additions & 8 deletions README.md
Expand Up @@ -4,7 +4,7 @@
[![codecov](https://codecov.io/gh/googleapis/gaxios/branch/master/graph/badge.svg)](https://codecov.io/gh/googleapis/gaxios)
[![Code Style: Google](https://img.shields.io/badge/code%20style-google-blueviolet.svg)](https://github.com/google/gts)

> An HTTP request client that provides an `axios` like interface over top of `node-fetch`.
> An HTTP request client that provides an `axios` like interface over top of `fetch`.
## Install

Expand Down Expand Up @@ -71,10 +71,6 @@ interface GaxiosOptions = {
// Defaults to `0`, which is the same as unset.
maxContentLength: 2000,

// The max number of HTTP redirects to follow.
// Defaults to 100.
maxRedirects: 100,

// The querystring parameters that will be encoded using `qs` and
// appended to the url
params: {
Expand Down Expand Up @@ -114,9 +110,9 @@ interface GaxiosOptions = {
// status code. Defaults to (>= 200 && < 300)
validateStatus: (status: number) => true,

// Implementation of `fetch` to use when making the API call. By default,
// will use the browser context if available, and fall back to `node-fetch`
// in node.js otherwise.
/**
* Implementation of `fetch` to use when making the API call. Will use `fetch` by default.
*/
fetchImplementation?: typeof fetch;

// Configuration for retrying of requests.
Expand Down
4 changes: 1 addition & 3 deletions package.json
Expand Up @@ -71,7 +71,7 @@
"multiparty": "^4.2.1",
"mv": "^2.1.1",
"ncp": "^2.0.0",
"nock": "^13.0.0",
"nock": "^14.0.0-beta.5",
"null-loader": "^4.0.0",
"puppeteer": "^21.0.0",
"sinon": "^17.0.0",
Expand All @@ -85,8 +85,6 @@
"dependencies": {
"extend": "^3.0.2",
"https-proxy-agent": "^7.0.1",
"is-stream": "^2.0.0",
"node-fetch": "^3.3.2",
"uuid": "^9.0.1"
}
}
133 changes: 63 additions & 70 deletions src/common.ts
Expand Up @@ -118,22 +118,17 @@ export class GaxiosError<T = any> extends Error {
}
}

/**
* @deprecated - use native {@link globalThis.Headers}.
*/
export interface Headers {
[index: string]: any;

Check warning on line 125 in src/common.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type
}
export type GaxiosPromise<T = any> = Promise<GaxiosResponse<T>>;

Check warning on line 127 in src/common.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type

export interface GaxiosXMLHttpRequest {
responseURL: string;
}

export interface GaxiosResponse<T = any> {
export interface GaxiosResponse<T = any> extends Response {

Check warning on line 129 in src/common.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type
config: GaxiosOptions;
data: T;
status: number;
statusText: string;
headers: Headers;
request: GaxiosXMLHttpRequest;
}

export interface GaxiosMultipartOptions {
Expand All @@ -144,10 +139,12 @@ export interface GaxiosMultipartOptions {
/**
* Request options that are used to form the request.
*/
export interface GaxiosOptions {
export interface GaxiosOptions extends Omit<RequestInit, 'headers'> {
/**
* Optional method to override making the actual HTTP request. Useful
* for writing tests.
*
* @deprecated - Use {@link GaxiosOptions.fetchImplementation} instead.
*/
adapter?: <T = any>(

Check warning on line 149 in src/common.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type
options: GaxiosOptions,
Expand All @@ -169,20 +166,38 @@ export interface GaxiosOptions {
| 'OPTIONS'
| 'TRACE'
| 'PATCH';
/**
* Recommended: Provide a native {@link globalThis.Headers Headers} object.
*
* @privateRemarks
*
* This type does not have the native {@link globalThis.Headers Headers} in
* its signature as it would break customers looking to modify headers before
* providing to this library.
*/
headers?: Headers;
/**
* The data to send in the {@link RequestInit.body} of the request. Data objects will be
* serialized as JSON, except for `FormData`.
*
* Note: if you would like to provide a Content-Type header other than
* application/json you you must provide a string or readable stream, rather
* than an object:
*
* @example
*
* {data: JSON.stringify({some: 'data'})}
* {data: fs.readFile('./some-data.jpeg')}
*/
data?: any;

Check warning on line 192 in src/common.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type
body?: any;
/**
* The maximum size of the http response content in bytes allowed.
*/
maxContentLength?: number;
/**
* The maximum number of redirects to follow. Defaults to 20.
*/
maxRedirects?: number;
follow?: number;
/**
* A collection of parts to send as a `Content-Type: multipart/related` request.
*
* This is passed to {@link RequestInit.body}.
*/
multipart?: GaxiosMultipartOptions[];
params?: any;

Check warning on line 203 in src/common.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type
Expand All @@ -203,15 +218,24 @@ export interface GaxiosOptions {
validateStatus?: (status: number) => boolean;
retryConfig?: RetryConfig;
retry?: boolean;
// Enables aborting via AbortController
/**
* Enables aborting via {@link AbortController}
*/
signal?: AbortSignal;
size?: number;
/**
* Implementation of `fetch` to use when making the API call. By default,
* will use the browser context if available, and fall back to `node-fetch`
* in node.js otherwise.
* Implementation of `fetch` to use when making the API call. Will use `fetch` by default.
*
* @example
*
* let customFetchCalled = false;
* const myFetch = (...args: Parameters<typeof fetch>) => {
* customFetchCalled = true;
* return fetch(...args);
* };
*
* {fetchImplementation: myFetch};
*/
fetchImplementation?: FetchImplementation;
fetchImplementation?: typeof fetch;
// Configure client to use mTLS:
cert?: string;
key?: string;
Expand Down Expand Up @@ -258,7 +282,7 @@ export interface GaxiosOptions {
errorRedactor?: typeof defaultErrorRedactor | false;
}
/**
* A partial object of `GaxiosResponse` with only redactable keys
* A partial object of `GaxiosOptions` with only redactable keys
*
* @experimental
*/
Expand Down Expand Up @@ -330,41 +354,6 @@ export interface RetryConfig {
retryBackoff?: (err: GaxiosError, defaultBackoffMs: number) => Promise<void>;
}

export type FetchImplementation = (
input: FetchRequestInfo,
init?: FetchRequestInit
) => Promise<FetchResponse>;

export type FetchRequestInfo = any;

export interface FetchResponse {
readonly status: number;
readonly statusText: string;
readonly url: string;
readonly body: unknown | null;
arrayBuffer(): Promise<unknown>;
blob(): Promise<unknown>;
readonly headers: FetchHeaders;
json(): Promise<any>;
text(): Promise<string>;
}

export interface FetchRequestInit {
method?: string;
}

export interface FetchHeaders {
append(name: string, value: string): void;
delete(name: string): void;
get(name: string): string | null;
has(name: string): boolean;
set(name: string, value: string): void;
forEach(
callbackfn: (value: string, key: string) => void,
thisArg?: any
): void;
}

function translateData(responseType: string | undefined, data: any) {

Check warning on line 357 in src/common.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type
switch (responseType) {
case 'stream':
Expand Down Expand Up @@ -395,23 +384,27 @@ export function defaultErrorRedactor<T = any>(data: {
const REDACT =
'<<REDACTED> - See `errorRedactor` option in `gaxios` for configuration>.';

function redactHeaders(headers?: Headers) {
function redactHeaders(headers?: Headers | globalThis.Headers) {
if (!headers) return;

for (const key of Object.keys(headers)) {
// any casing of `Authentication`
if (/^authentication$/i.test(key)) {
headers[key] = REDACT;
}
const source: string[] =
headers instanceof Headers
? // TS is missing Headers#keys at the time of writing
(headers as {} as {keys(): string[]}).keys()
: Object.keys(headers);

for (const key of source) {
// any casing of `Authentication`
// any casing of `Authorization`
if (/^authorization$/i.test(key)) {
headers[key] = REDACT;
}

// anything containing secret, such as 'client secret'
if (/secret/i.test(key)) {
headers[key] = REDACT;
if (
/^authentication$/i.test(key) ||
/^authorization$/i.test(key) ||
/secret/i.test(key)
) {
headers instanceof Headers
? headers.set(key, REDACT)
: (headers[key] = REDACT);
}
}
}
Expand Down

0 comments on commit 23e7626

Please sign in to comment.