Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(deps): use gaxios for HTTP requests instead of axios #593

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
"client library"
],
"dependencies": {
"axios": "^0.18.0",
"base64-js": "^1.3.0",
"fast-text-encoding": "^1.0.0",
"gaxios": "^1.1.1",
"gcp-metadata": "^0.9.3",
"gtoken": "^2.3.2",
"https-proxy-agent": "^2.2.1",
Expand Down
6 changes: 3 additions & 3 deletions src/auth/authclient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
* limitations under the License.
*/

import {AxiosPromise, AxiosRequestConfig} from 'axios';
import {EventEmitter} from 'events';
import {GaxiosOptions, GaxiosPromise} from 'gaxios';

import {DefaultTransporter} from '../transporters';

Expand All @@ -30,9 +30,9 @@ export abstract class AuthClient extends EventEmitter {
credentials: Credentials = {};

/**
* Provides an alternative Axios request implementation with auth credentials
* Provides an alternative Gaxios request implementation with auth credentials
*/
abstract request<T>(opts: AxiosRequestConfig): AxiosPromise<T>;
abstract request<T>(opts: GaxiosOptions): GaxiosPromise<T>;

/**
* Sets the auth credentials.
Expand Down
8 changes: 4 additions & 4 deletions src/auth/computeclient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

import {AxiosError, AxiosPromise, AxiosRequestConfig, AxiosResponse} from 'axios';
import {GaxiosError, GaxiosOptions, GaxiosPromise} from 'gaxios';
import * as gcpMetadata from 'gcp-metadata';
import * as messages from '../messages';
import {CredentialRequest, Credentials} from './credentials';
Expand Down Expand Up @@ -82,10 +82,10 @@ export class Compute extends OAuth2Client {
return {tokens, res: null};
}

protected requestAsync<T>(opts: AxiosRequestConfig, retry = false):
AxiosPromise<T> {
protected requestAsync<T>(opts: GaxiosOptions, retry = false):
GaxiosPromise<T> {
return super.requestAsync<T>(opts, retry).catch(e => {
const res = (e as AxiosError).response;
const res = (e as GaxiosError).response;
if (res && res.status) {
let helpfulMessage = null;
if (res.status === 403) {
Expand Down
4 changes: 2 additions & 2 deletions src/auth/googleauth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
* limitations under the License.
*/

import {AxiosRequestConfig, AxiosResponse} from 'axios';
import {exec} from 'child_process';
import * as fs from 'fs';
import {GaxiosOptions, GaxiosResponse} from 'gaxios';
import * as gcpMetadata from 'gcp-metadata';
import * as os from 'os';
import * as path from 'path';
Expand Down Expand Up @@ -732,7 +732,7 @@ export class GoogleAuth {
* @param opts Axios request options for the HTTP request.
*/
// tslint:disable-next-line no-any
async request<T = any>(opts: AxiosRequestConfig): Promise<AxiosResponse<T>> {
async request<T = any>(opts: GaxiosOptions): Promise<GaxiosResponse<T>> {
const client = await this.getClient();
return client.request<T>(opts);
}
Expand Down
63 changes: 33 additions & 30 deletions src/auth/oauth2client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

import {AxiosError, AxiosPromise, AxiosRequestConfig, AxiosResponse} from 'axios';
import {GaxiosError, GaxiosOptions, GaxiosPromise, GaxiosResponse} from 'gaxios';
import * as querystring from 'querystring';
import * as stream from 'stream';

Expand Down Expand Up @@ -264,53 +264,53 @@ export interface GenerateAuthUrlOpts {
}

export interface GetTokenCallback {
(err: AxiosError|null, token?: Credentials|null,
res?: AxiosResponse|null): void;
(err: GaxiosError|null, token?: Credentials|null,
res?: GaxiosResponse|null): void;
}

export interface GetTokenResponse {
tokens: Credentials;
res: AxiosResponse|null;
res: GaxiosResponse|null;
}

export interface GetAccessTokenCallback {
(err: AxiosError|null, token?: string|null, res?: AxiosResponse|null): void;
(err: GaxiosError|null, token?: string|null, res?: GaxiosResponse|null): void;
}

export interface GetAccessTokenResponse {
token?: string|null;
res?: AxiosResponse|null;
res?: GaxiosResponse|null;
}

export interface RefreshAccessTokenCallback {
(err: AxiosError|null, credentials?: Credentials|null,
res?: AxiosResponse|null): void;
(err: GaxiosError|null, credentials?: Credentials|null,
res?: GaxiosResponse|null): void;
}

export interface RefreshAccessTokenResponse {
credentials: Credentials;
res: AxiosResponse|null;
res: GaxiosResponse|null;
}

export interface RequestMetadataResponse {
headers: Headers;
res?: AxiosResponse<void>|null;
res?: GaxiosResponse<void>|null;
}

export interface RequestMetadataCallback {
(err: AxiosError|null, headers?: Headers,
res?: AxiosResponse<void>|null): void;
(err: GaxiosError|null, headers?: Headers,
res?: GaxiosResponse<void>|null): void;
}

export interface GetFederatedSignonCertsCallback {
(err: AxiosError|null, certs?: Certificates,
response?: AxiosResponse<void>|null): void;
(err: GaxiosError|null, certs?: Certificates,
response?: GaxiosResponse<void>|null): void;
}

export interface FederatedSignonCertsResponse {
certs: Certificates;
format: CertificateFormat;
res?: AxiosResponse<void>|null;
res?: GaxiosResponse<void>|null;
}

export interface RevokeCredentialsResult {
Expand Down Expand Up @@ -715,7 +715,7 @@ export class OAuth2Client extends AuthClient {
r = await this.refreshToken(thisCreds.refresh_token);
tokens = r.tokens;
} catch (err) {
const e = err as AxiosError;
const e = err as GaxiosError;
if (e.response &&
(e.response.status === 403 || e.response.status === 404)) {
e.message = 'Could not refresh access token.';
Expand Down Expand Up @@ -747,14 +747,17 @@ export class OAuth2Client extends AuthClient {
* @param token The existing token to be revoked.
* @param callback Optional callback fn.
*/
revokeToken(token: string): AxiosPromise<RevokeCredentialsResult>;
revokeToken(token: string): GaxiosPromise<RevokeCredentialsResult>;
revokeToken(
token: string,
callback: BodyResponseCallback<RevokeCredentialsResult>): void;
revokeToken(
token: string, callback?: BodyResponseCallback<RevokeCredentialsResult>):
AxiosPromise<RevokeCredentialsResult>|void {
const opts = {url: OAuth2Client.getRevokeTokenUrl(token), method: 'POST'};
GaxiosPromise<RevokeCredentialsResult>|void {
const opts: GaxiosOptions = {
url: OAuth2Client.getRevokeTokenUrl(token),
method: 'POST'
};
if (callback) {
this.transporter.request<RevokeCredentialsResult>(opts).then(
r => callback(null, r), callback);
Expand All @@ -768,11 +771,11 @@ export class OAuth2Client extends AuthClient {
* Revokes access token and clears the credentials object
* @param callback callback
*/
revokeCredentials(): AxiosPromise<RevokeCredentialsResult>;
revokeCredentials(): GaxiosPromise<RevokeCredentialsResult>;
revokeCredentials(callback: BodyResponseCallback<RevokeCredentialsResult>):
void;
revokeCredentials(callback?: BodyResponseCallback<RevokeCredentialsResult>):
AxiosPromise<RevokeCredentialsResult>|void {
GaxiosPromise<RevokeCredentialsResult>|void {
if (callback) {
this.revokeCredentialsAsync().then(res => callback(null, res), callback);
} else {
Expand All @@ -798,10 +801,10 @@ export class OAuth2Client extends AuthClient {
* @param callback callback.
* @return Request object
*/
request<T>(opts: AxiosRequestConfig): AxiosPromise<T>;
request<T>(opts: AxiosRequestConfig, callback: BodyResponseCallback<T>): void;
request<T>(opts: AxiosRequestConfig, callback?: BodyResponseCallback<T>):
AxiosPromise<T>|void {
request<T>(opts: GaxiosOptions): GaxiosPromise<T>;
request<T>(opts: GaxiosOptions, callback: BodyResponseCallback<T>): void;
request<T>(opts: GaxiosOptions, callback?: BodyResponseCallback<T>):
GaxiosPromise<T>|void {
if (callback) {
this.requestAsync<T>(opts).then(r => callback(null, r), e => {
return callback(e, e.response);
Expand All @@ -811,9 +814,9 @@ export class OAuth2Client extends AuthClient {
}
}

protected async requestAsync<T>(opts: AxiosRequestConfig, retry = false):
Promise<AxiosResponse<T>> {
let r2: AxiosResponse;
protected async requestAsync<T>(opts: GaxiosOptions, retry = false):
Promise<GaxiosResponse<T>> {
let r2: GaxiosResponse;
try {
const r = await this.getRequestMetadataAsync(opts.url);
if (r.headers && r.headers.Authorization) {
Expand All @@ -826,7 +829,7 @@ export class OAuth2Client extends AuthClient {
}
r2 = await this.transporter.request<T>(opts);
} catch (e) {
const res = (e as AxiosError).response;
const res = (e as GaxiosError).response;
if (res) {
const statusCode = res.status;
// Retry the request for metadata if the following criteria are true:
Expand Down Expand Up @@ -944,7 +947,7 @@ export class OAuth2Client extends AuthClient {
this.certificateCacheFormat === format) {
return {certs: this.certificateCache, format};
}
let res: AxiosResponse;
let res: GaxiosResponse;
let url: string;
switch (format) {
case CertificateFormat.PEM:
Expand Down
62 changes: 20 additions & 42 deletions src/transporters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,44 +14,31 @@
* limitations under the License.
*/

import axios, {AxiosError, AxiosPromise, AxiosRequestConfig, AxiosResponse} from 'axios';
import {GaxiosError, GaxiosOptions, GaxiosPromise, GaxiosResponse, request} from 'gaxios';

import {isBrowser} from './isbrowser';
import {validate} from './options';

// tslint:disable-next-line variable-name
const HttpsProxyAgent = require('https-proxy-agent');

// tslint:disable-next-line no-var-requires
const pkg = require('../../package.json');
const PRODUCT_NAME = 'google-api-nodejs-client';

export interface Transporter {
request<T>(opts: AxiosRequestConfig): AxiosPromise<T>;
request<T>(opts: AxiosRequestConfig, callback?: BodyResponseCallback<T>):
void;
request<T>(opts: AxiosRequestConfig, callback?: BodyResponseCallback<T>):
AxiosPromise|void;
request<T>(opts: GaxiosOptions): GaxiosPromise<T>;
request<T>(opts: GaxiosOptions, callback?: BodyResponseCallback<T>): void;
request<T>(opts: GaxiosOptions, callback?: BodyResponseCallback<T>):
GaxiosPromise|void;
}

export interface BodyResponseCallback<T> {
// The `body` object is a truly dynamic type. It must be `any`.
(err: Error|null, res?: AxiosResponse<T>|null): void;
(err: Error|null, res?: GaxiosResponse<T>|null): void;
}

export interface RequestError extends AxiosError {
export interface RequestError extends GaxiosError {
errors: Error[];
}

/**
* Axios will use XHR if it is available. In the case of Electron,
* since XHR is there it will try to use that. This leads to OPTIONS
* preflight requests which googleapis DOES NOT like. This line of
* code pins the adapter to ensure it uses node.
* https://github.com/google/google-api-nodejs-client/issues/1083
*/
axios.defaults.adapter = require('axios/lib/adapters/http');

export class DefaultTransporter {
/**
* Default user agent.
Expand All @@ -60,10 +47,10 @@ export class DefaultTransporter {

/**
* Configures request options before making a request.
* @param opts AxiosRequestConfig options.
* @param opts GaxiosOptions options.
* @return Configured options.
*/
configure(opts: AxiosRequestConfig = {}): AxiosRequestConfig {
configure(opts: GaxiosOptions = {}): GaxiosOptions {
opts.headers = opts.headers || {};
if (!isBrowser()) {
// set transporter user agent if not in browser
Expand All @@ -79,16 +66,15 @@ export class DefaultTransporter {
}

/**
* Makes a request using Axios with given options.
* @param opts AxiosRequestConfig options.
* @param callback optional callback that contains AxiosResponse object.
* @return AxiosPromise, assuming no callback is passed.
* Makes a request using Gaxios with given options.
* @param opts GaxiosOptions options.
* @param callback optional callback that contains GaxiosResponse object.
* @return GaxiosPromise, assuming no callback is passed.
*/
request<T>(opts: AxiosRequestConfig): AxiosPromise<T>;
request<T>(opts: AxiosRequestConfig, callback?: BodyResponseCallback<T>):
void;
request<T>(opts: AxiosRequestConfig, callback?: BodyResponseCallback<T>):
AxiosPromise|void {
request<T>(opts: GaxiosOptions): GaxiosPromise<T>;
request<T>(opts: GaxiosOptions, callback?: BodyResponseCallback<T>): void;
request<T>(opts: GaxiosOptions, callback?: BodyResponseCallback<T>):
GaxiosPromise|void {
// ensure the user isn't passing in request-style options
opts = this.configure(opts);
try {
Expand All @@ -101,24 +87,16 @@ export class DefaultTransporter {
}
}

// If the user configured an `HTTPS_PROXY` environment variable, create
// a custom agent to proxy the request.
const proxy = process.env.HTTPS_PROXY || process.env.https_proxy;
if (proxy) {
opts.httpsAgent = new HttpsProxyAgent(proxy);
opts.proxy = false;
}

if (callback) {
axios(opts).then(
request<T>(opts).then(
r => {
callback(null, r);
},
e => {
callback(this.processError(e));
});
} else {
return axios(opts).catch(e => {
return request<T>(opts).catch(e => {
throw this.processError(e);
});
}
Expand All @@ -127,7 +105,7 @@ export class DefaultTransporter {
/**
* Changes the error to include details from the body.
*/
private processError(e: AxiosError): RequestError {
private processError(e: GaxiosError): RequestError {
const res = e.response;
const err = e as RequestError;
const body = res ? res.data : null;
Expand Down
Loading