Giter Club home page Giter Club logo

gaxios's Introduction

gaxios

npm version codecov Code Style: Google

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

Install

$ npm install gaxios

Example

const {request} = require('gaxios');
const res = await request({
  url: 'https://www.googleapis.com/discovery/v1/apis/',
});

Setting Defaults

Gaxios supports setting default properties both on the default instance, and on additional instances. This is often useful when making many requests to the same domain with the same base settings. For example:

const gaxios = require('gaxios');
gaxios.instance.defaults = {
  baseURL: 'https://example.com'
  headers: {
    Authorization: 'SOME_TOKEN'
  }
}
gaxios.request({url: '/data'}).then(...);

Note that setting default values will take precedence over other authentication methods, i.e., application default credentials.

Request Options

interface GaxiosOptions = {
  // The url to which the request should be sent.  Required.
  url: string,

  // The HTTP method to use for the request.  Defaults to `GET`.
  method: 'GET',

  // The base Url to use for the request. Prepended to the `url` property above.
  baseURL: 'https://example.com';

  // The HTTP methods to be sent with the request.
  headers: { 'some': 'header' },

  // The data to send in the body of the request. Data objects will be
  // serialized as JSON.
  //
  // 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:
  // data: JSON.stringify({some: 'data'})
  // data: fs.readFile('./some-data.jpeg')
  data: {
    some: 'data'
  },

  // The max size of the http response content in bytes allowed.
  // 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: {
    querystring: 'parameters'
  },

  // By default, we use the `querystring` package in node core to serialize
  // querystring parameters.  You can override that and provide your
  // own implementation.
  paramsSerializer: (params) => {
    return qs.stringify(params);
  },

  // The timeout for the HTTP request in milliseconds. Defaults to 0.
  timeout: 1000,

  // Optional method to override making the actual HTTP request. Useful
  // for writing tests and instrumentation
  adapter?: async (options, defaultAdapter) => {
    const res = await defaultAdapter(options);
    res.data = {
      ...res.data,
      extraProperty: 'your extra property',
    };
    return res;
  };

  // The expected return type of the request.  Options are:
  // json | stream | blob | arraybuffer | text | unknown
  // Defaults to `unknown`.
  responseType: 'unknown',

  // The node.js http agent to use for the request.
  agent: someHttpsAgent,

  // Custom function to determine if the response is valid based on the
  // 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.
  fetchImplementation?: typeof fetch;

  // Configuration for retrying of requests.
  retryConfig: {
    // The number of times to retry the request.  Defaults to 3.
    retry?: number;

    // The number of retries already attempted.
    currentRetryAttempt?: number;

    // The HTTP Methods that will be automatically retried.
    // Defaults to ['GET','PUT','HEAD','OPTIONS','DELETE']
    httpMethodsToRetry?: string[];

    // The HTTP response status codes that will automatically be retried.
    // Defaults to: [[100, 199], [408, 408], [429, 429], [500, 599]]
    statusCodesToRetry?: number[][];

    // Function to invoke when a retry attempt is made.
    onRetryAttempt?: (err: GaxiosError) => Promise<void> | void;

    // Function to invoke which determines if you should retry
    shouldRetry?: (err: GaxiosError) => Promise<boolean> | boolean;

    // When there is no response, the number of retries to attempt. Defaults to 2.
    noResponseRetries?: number;

    // The amount of time to initially delay the retry, in ms.  Defaults to 100ms.
    retryDelay?: number;
  },

  // Enables default configuration for retries.
  retry: boolean,

  // Cancelling a request requires the `abort-controller` library.
  // See https://github.com/bitinn/node-fetch#request-cancellation-with-abortsignal
  signal?: AbortSignal

  /**
   * A collection of parts to send as a `Content-Type: multipart/related` request.
   */
  multipart?: GaxiosMultipartOptions;

  /**
   * An optional proxy to use for requests.
   * Available via `process.env.HTTP_PROXY` and `process.env.HTTPS_PROXY` as well - with a preference for the this config option when multiple are available.
   * The `agent` option overrides this.
   *
   * @see {@link GaxiosOptions.noProxy}
   * @see {@link GaxiosOptions.agent}
   */
  proxy?: string | URL;
  /**
   * A list for excluding traffic for proxies.
   * Available via `process.env.NO_PROXY` as well as a common-separated list of strings - merged with any local `noProxy` rules.
   *
   * - When provided a string, it is matched by
   *   - Wildcard `*.` and `.` matching are available. (e.g. `.example.com` or `*.example.com`)
   * - When provided a URL, it is matched by the `.origin` property.
   *   - For example, requesting `https://example.com` with the following `noProxy`s would result in a no proxy use:
   *     - new URL('https://example.com')
   *     - new URL('https://example.com:443')
   *   - The following would be used with a proxy:
   *     - new URL('http://example.com:80')
   *     - new URL('https://example.com:8443')
   * - When provided a regular expression it is used to match the stringified URL
   *
   * @see {@link GaxiosOptions.proxy}
   */
  noProxy?: (string | URL | RegExp)[];

  /**
   * An experimental, customizable error redactor.
   *
   * Set `false` to disable.
   *
   * @remarks
   *
   * This does not replace the requirement for an active Data Loss Prevention (DLP) provider. For DLP suggestions, see:
   * - https://cloud.google.com/sensitive-data-protection/docs/redacting-sensitive-data#dlp_deidentify_replace_infotype-nodejs
   * - https://cloud.google.com/sensitive-data-protection/docs/infotypes-reference#credentials_and_secrets
   *
   * @experimental
   */
  errorRedactor?: typeof defaultErrorRedactor | false;
}

License

Apache-2.0

gaxios's People

Contributors

alexander-fenster avatar atjeff avatar bcoe avatar beckend avatar danielbankhead avatar ddelgrosso1 avatar elierotenberg avatar fhinkel avatar forty avatar fossprime avatar gcf-merge-on-green[bot] avatar gcf-owl-bot[bot] avatar google-cloud-policy-bot[bot] avatar jkwlui avatar justinbeckwith avatar lushu avatar marapper avatar mitchellwills avatar release-please[bot] avatar renovate-bot avatar renovate[bot] avatar sebiniemann avatar seriousmanual avatar sofisl avatar stephenplusplus avatar summer-ji-eng avatar surferjeffatgoogle avatar vinteo avatar wilhuff avatar yoshi-automation avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gaxios's Issues

Add maxRedirects option from axios

  • It would be nice to have request option parity with axios for the 'maxRedirects' property at the per request level to allow NOT following any redirects.
    E.g. I call an auth server and want to access the location header from a 302 response code without a redirect

New Bug ignore me

Thanks for stopping by to let us know something could be better!

PLEASE READ: If you have a support contract with Google, please create an issue in the support console instead of filing on GitHub. This will ensure a timely response.

Please run down the following list and make sure you've tried the usual "quick fixes":

If you are still having issues, please be sure to include as much information as possible:

Environment details

  • OS:
  • Node.js version:
  • npm version:
  • gaxios version:

Steps to reproduce

  1. ?
  2. ?

Making sure to follow these steps will guarantee the quickest resolution possible.

Thanks!

Add adapter option from axios

It looks like with the move from axios to gaxios, googleapis lost the ability to define adapters using axios' adapter option. We've previously used this to instrument googleapi client requests and would like to continue that while upgrading to future versions of googleapis.

Add maxContentLength option from axios

๐Ÿ‘‹ With the move from axios to gaxios, the googleapis module lost the ability to specify maxContentLength for requests. We've previously been using this option and googleapis itself used it until migrating to using googleapis-common which relied on gaxios. It'd be nice to have the option to set a max content length for situations when you'd like to limit response size.

`Content-Type` response header is ignored

Related to googleapis/google-api-nodejs-client#1777.

We accept a responseType as part of the request config that dictates what processing we do with the response body before returning it in res.data. By default, we just assume json if not told otherwise. The problem pops up when the content type is defined in a response header, and we just ignore it. When an application/gzip content type comes back in a header, I'd argue we shouldn't try JSON.parse-ing that by default :)

What is gaxios?

I'm confused. I was reading the Google OAuth2 workflow when I saw a link to this library. What is the advantage of using this over axios?

Synthesis failed for gaxios

Hello! Autosynth couldn't regenerate gaxios. ๐Ÿ’”

Here's the output from running synth.py:

Cloning into 'working_repo'...
Switched to branch 'autosynth'
Traceback (most recent call last):
  File "/home/kbuilder/.pyenv/versions/3.6.1/lib/python3.6/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/home/kbuilder/.pyenv/versions/3.6.1/lib/python3.6/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/tmpfs/src/git/autosynth/autosynth/synth.py", line 256, in <module>
    main()
  File "/tmpfs/src/git/autosynth/autosynth/synth.py", line 196, in main
    last_synth_commit_hash = get_last_metadata_commit(args.metadata_path)
  File "/tmpfs/src/git/autosynth/autosynth/synth.py", line 149, in get_last_metadata_commit
    text=True,
  File "/home/kbuilder/.pyenv/versions/3.6.1/lib/python3.6/subprocess.py", line 403, in run
    with Popen(*popenargs, **kwargs) as process:
TypeError: __init__() got an unexpected keyword argument 'text'

Google internal developers can see the full log here.

Interceptors?

Hey friends, I found this module via JustinBeckwith/retry-axios#1, and tried it out as a 'drop-in replacement' for axios because I need that sweet retry goodness and retry-axios has this issue where it only retries once, then seems to...forget my config. Something seems to be missing, though: interceptors!

Is your feature request related to a problem? Please describe.
I think this is a feature request, unless I'm really bad at reading documentation. Couldn't see an indication in the source code that it's supported either.

So I copy/paste replaced axios with gaxios, ran my code...

const requests = require('gaxios'),
  _ = require('lodash')

const logHttpErrorDetails = requests.interceptors.response.use(/* my fully sick function for logging all error responses */)

...and got this error:
TypeError: Cannot read property 'response' of undefined

Describe the solution you'd like
I would like axios-like interceptors supported for use in gaxios.

Describe alternatives you've considered
Probably just going back to axios and putting up with my retry-axios issue.

Additional context
๐Ÿ™

Configure CI

We need to have the CI configured for this repo on the backend. It has browser tests, so should look similar to google-auth-library.

Error when using GaxiosPromise as return type of async function

Environment details

  • OS: Ubuntu 19.10
  • Node.js version: 10.16.3
  • npm version: 6.9.0
  • gaxios version: 2.2.0

Steps to reproduce

submitAction = async (action: SubmitAction): 
  GaxiosPromise<sheets_v4.Schema$BatchUpdateSpreadsheetResponse> => { ... }
Error: TS1055: Type 'GaxiosPromise' is not a valid async function return type in ES5/ES3 because it does not refer to a Promise-compatible constructor value.

Adding export const GaxiosPromise = Promise; in common.d.ts fixes the problem, but I'm not sure how to achieve this during the build process, hence no PR.
Got solution from here: microsoft/TypeScript#12776 (comment)

Make time units clear for retry configuration

No units are specified for the retryDelay option, which makes it hard to be sure what the value represents.

    // The amount of time to initially delay the retry.  Defaults to 100.
    retryDelay?: number;

I was using the option in a library that uses gaxios as a dependency of a dependency, so I had to dig through multiple layers to end up in the source code here to confirm that it uses milliseconds.

It'd be helpful for the units of the number to be in the option name, so that it's called something like retryDelayMilliseconds. Or even better, initialRetryDelayMilliseconds.

I didn't look through all other options to see whether they're missing units, but generally, I think it's helpful for all units to be specified wherever possible, to reduce ambiguity.

URL is not a constructor at Gaxios.validateOpts

It looks like after migration from axios to gaxios in googleapis v37.0.0 feat: make it webpackable feature does not work properly.
Build with webpack works fine but getting an error on any request: URL is not a constructor at Gaxios.validateOpts gaxios.ts#L151
Node URL Api is incompatible with node-url in webpack's lib. Some details can be found here:
webpack/node-libs-browser#69
webpack/node-libs-browser#78

Is it supposed to be used with webpack ?

@alexander-fenster

Real request information in response object

There is no way to know what real URL was fetched if maxRedirects/follow is setted.

Is your feature request related to a problem? Please describe.

When we try to parse relative links (it's a bad but real) in the crawled page we can not say how turn it out in absolute links.

Describe the solution you'd like

Most we need real response URL after some redirects chain happens.

node-fetch Response have url property with final page URL.

axios response have request property as XMLHttpRequest object with final page URL in responseURL property.

So it can be done with limited and incomplete interface of XMLHttpRequest. Something like this marapper@836fca1

Describe alternatives you've considered
Full and comlete implementation of axios response? But it's not neccessary in most cases.

Additional context

It could solve linkinator' issues JustinBeckwith/linkinator#108

@vc102375 Oh, that's bad. `URL` class was added in v6.13.0. The easiest way for you is switching to Node.js v8 since v6 will be EOL in less than a month.

@vc102375 Oh, that's bad. URL class was added in v6.13.0. The easiest way for you is switching to Node.js v8 since v6 will be EOL in less than a month.

As a quick workaround, you can add this to the very beginning of the your application:

const url = require('url'); // legacy Node6 url
const semver = require('semver');
class Node6CompatibilityURL {
  constructor(str) {
    this.url = url.parse(str);
    this.origin = this.url.protocol + '//';
    this.pathname = this.url.pathname ? this.url.pathname : '';
    this.search = this.url.search ? this.url.search : '';
    this.href = this.url.href ? this.url.href : '';
  }
}

if (semver.lt(process.version, '6.13.0')) {
  window = {};
  window.URL = Node6CompatibilityURL; // no warranty ๐Ÿ˜ฑ 
}

Make sure you npm install semver to make it work. This code creates a global window object with window.URL that will make gaxios think it's running in browser mode, so it will use this instead of the URL class that will appear in v6.13.0. Thanks for semver check, it will keep working even after you upgrade Node.js. Please try that and let me know if it helped.

Originally posted by @alexander-fenster in #44 (comment)

`baseURL` is appended to URL again on retry

Steps to reproduce

  1. Set baseURL (eg: 'https://www.google.com')
  2. Send a request to 404 page (eg: '/asdf') with retry option enabled. Browser will try to request to these following URLs:

The problem seems to be at these places:

err.config = opts;

return this.request<T>(err.config);

opts = this.validateOpts(opts);

gaxios/src/gaxios.ts

Lines 149 to 152 in 7137a2d

const baseUrl = opts.baseUrl || opts.baseURL;
if (baseUrl) {
opts.url = baseUrl + opts.url;
}

On retry, request() will be called recursively. Hence validateOpts() will also be called and the baseUrl will be appended again and again.

My proposed solution is to add a new property to GaxiosOptions to handle the modified URL instead of mutating the original URL.

Looks like yarn and npm is not up to date, how might this have happened?

In yarn there exists version 1.8.5: https://yarnpkg.com/en/package/gaxios
Github it does not exists: https://github.com/googleapis/gaxios
In the registry of yarn it does not exsist: https://registry.yarnpkg.com/gaxios/
NPM does not have the version: https://www.npmjs.com/package/gaxios

But this breaks my build, for some reason, I have it in my lockfile with version 1.8.5, without having it as a dependency myself. Its a child dependency of google libs.

So maybe I should delete the lockfile and update?
Currently putting 1.8.4 in my resolution works, but not sure how that will affect, as it is not my own dependency.

Version 1.0.6 of gaxios doesn't seem to have any *.js files in it

Saw this while investigating "Error: Cannot find module 'gaxios'" error that started happening for my program today. See below, it seems version 1.0.2 has "build" directory but version 1.0.6 that was released today does not.

@azina:node_modules$
@azina:test$ npm install [email protected]
...
+ [email protected]
updated 1 package and audited 524 packages in 0.638s
found 0 vulnerabilities

@azina:test$ ls node_modules/gaxios/
LICENSE  README.md  build  package.json


@azina:test$ npm install [email protected]
...
+ [email protected]
updated 1 package and audited 524 packages in 0.76s
found 0 vulnerabilities

@azina:test$ ls node_modules/gaxios/
LICENSE  README.md  package.json

Simplify stream usage

(source: googleapis/gcs-resumable-upload#174 (comment))

When sending a POST request, node-fetch embeds the stream in the request options.

Expected

const reqOpts = {uri: 'http://')

fs.createReadStream('file.zip')
  .on('error', console.error)
  .pipe(fetch(reqOpts))
  .on('error', console.error)
  .pipe(dest)

Actual

const readFileStream =  fs.createReadStream('file.zip')
readFileStream.on('error', console.error)

const reqOpts = {uri: 'http://', body: readFileStream} // < embedded
const resp = await fetch(reqOpts)

resp.data
  .on('error', console.error)
  .pipe(dest)

I believe there is room for simplification here. Doing a GET response could be easier, too.

Expected

const reqOpts = {uri: 'http://')

fetch(reqOpts)
  .on('error', console.error)
  .pipe(fs.createWriteStream('file.zip'))
  .on('error', console.error)

Actual

const reqOpts = {uri: 'http://', responseType: 'stream'}
const resp = await fetch(reqOpts)

resp.data
  .on('error', console.error)
  .pipe(fs.createWriteStream('file.zip'))
  .on('error', console.error)

Please correct any of these examples, if there is an easier option I don't know about!

Transitioning from request

I'm coming to gaxios from request. In the latter I'm used to specifying gzip: true in my request options, to ensure compression is used in the response (if available). This does not appear to be available in gaxios so I'm wondering if it is effectively enabled by default? Not that I'd ever want to, but is it possible in gaxios to disable compression?

And it seems to me that the following drop-in replacements can also be made when transitioning from request to gaxios... please correct me if I'm wrong!

  • json: true becomes responseType: 'json' (though this is the default anyway so could be omitted)
  • body: { a: x, b: y } becomes data: { a: x, b: y }
  • qs: { a: x, b: y } becomes params: { a: x, b: y }

What about an equivalent for auth: { bearer: bearerToken }? See here.

And an equivalent to resolveWithFullResponse? See here.

Why?

Only really useful if you're trying to migrate from axios to the fetch

It might be helpful to indicate why someone would be inclined to make this migration. At least, as a sample of 1, count me as curious.

Typescript errors when building my project

I am attempting to build my Node.js and typescript project, and am running into a couple of issues.

node_modules/gaxios/build/src/index.d.ts(22,12): error TS1005: '>' expected.
node_modules/gaxios/build/src/index.d.ts(22,49): error TS1109: Expression expected.

gaxios is being used as a dependency of Google-Auth-Library and it's using version 1.2.1.

Is there a fix I can make myself for this?

Forced 'Content-Type' header

Gaxios rewrites the Content-Type header when the payload is of type 'object' in validateOpts:

    if (opts.data) {
      if (this.isReadableStream(opts.data)) {
        opts.body = opts.data;
      } else if (typeof opts.data === 'object') { // <-- Here
        opts.body = JSON.stringify(opts.data);
        opts.headers['Content-Type'] = 'application/json';
      } else {
        opts.body = opts.data;
      }
    }

I am currently updating to the google publisher v3 API (NodeJS) and I've hit a snag.
I am reading and passing the apk data as follows:

const apk = fs.readFileSync(apkFilePath);

this.publisher.edits.apks.upload({
           editId,
           packageName,
           media: {
               mimeType: 'application/vnd.android.package-archive',
               body: apk
            }
}, (err, res) => {});

In this case, I am explicitly specifying the mimeType to the one required by the upload API, apk variable is of type Buffer, but a typeof check returns 'object'. The upload API then returns

Media type 'application/json' is not supported. Valid media types: [application/octet-stream, application/vnd.android.package-archive] 

I'm not sure why there's a need to force the header and serialization when the user has explicitly set them, maybe I am missing something though ๐Ÿค”

case sensitivity of headers should not matter

Currently if one were to set a "content-type" header and a "Content-Type" header, the two are not equivalent.

I've seen libraries like express approach this differently, such that headers are case-insensitive.

ie11 Gaxios

Hello! I'm currently encountering issues using this lib with IE11 (Nextjs, Apollo, GraphQL). Basically i'm getting a syntax error and the breakpoint is being setted in the class GaxiosError. Any clue on this? Thanks :)

Synthesis failed for gaxios

Hello! Autosynth couldn't regenerate gaxios. ๐Ÿ’”

Here's the output from running synth.py:

Cloning into 'working_repo'...
Switched to branch 'autosynth'
Running synthtool
['/tmpfs/src/git/autosynth/env/bin/python3', '-m', 'synthtool', 'synth.py', '--']
synthtool > Executing /tmpfs/src/git/autosynth/working_repo/synth.py.
.eslintignore
.eslintrc.yml
.github/ISSUE_TEMPLATE/bug_report.md
.github/ISSUE_TEMPLATE/feature_request.md
.github/ISSUE_TEMPLATE/support_request.md
.github/PULL_REQUEST_TEMPLATE.md
synthtool > Wrote metadata to synth.metadata.
Traceback (most recent call last):
  File "/home/kbuilder/.pyenv/versions/3.6.1/lib/python3.6/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/home/kbuilder/.pyenv/versions/3.6.1/lib/python3.6/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/tmpfs/src/git/autosynth/env/lib/python3.6/site-packages/synthtool/__main__.py", line 99, in <module>
    main()
  File "/tmpfs/src/git/autosynth/env/lib/python3.6/site-packages/click/core.py", line 764, in __call__
    return self.main(*args, **kwargs)
  File "/tmpfs/src/git/autosynth/env/lib/python3.6/site-packages/click/core.py", line 717, in main
    rv = self.invoke(ctx)
  File "/tmpfs/src/git/autosynth/env/lib/python3.6/site-packages/click/core.py", line 956, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/tmpfs/src/git/autosynth/env/lib/python3.6/site-packages/click/core.py", line 555, in invoke
    return callback(*args, **kwargs)
  File "/tmpfs/src/git/autosynth/env/lib/python3.6/site-packages/synthtool/__main__.py", line 91, in main
    spec.loader.exec_module(synth_module)  # type: ignore
  File "<frozen importlib._bootstrap_external>", line 678, in exec_module
  File "<frozen importlib._bootstrap>", line 205, in _call_with_frames_removed
  File "/tmpfs/src/git/autosynth/working_repo/synth.py", line 6, in <module>
    templates = common_templates.node_library()
  File "/tmpfs/src/git/autosynth/env/lib/python3.6/site-packages/synthtool/gcp/common.py", line 89, in node_library
    return self._generic_library("node_library", **kwargs)
  File "/tmpfs/src/git/autosynth/env/lib/python3.6/site-packages/synthtool/gcp/common.py", line 49, in _generic_library
    result = t.render(**kwargs)
  File "/tmpfs/src/git/autosynth/env/lib/python3.6/site-packages/synthtool/sources/templates.py", line 83, in render
    _render_to_path(self.env, template_name, self.dir, kwargs)
  File "/tmpfs/src/git/autosynth/env/lib/python3.6/site-packages/synthtool/sources/templates.py", line 53, in _render_to_path
    output.dump(fh)
  File "/tmpfs/src/git/autosynth/env/lib/python3.6/site-packages/jinja2/environment.py", line 1313, in dump
    fp.writelines(iterable)
  File "/tmpfs/src/git/autosynth/env/lib/python3.6/site-packages/jinja2/environment.py", line 1357, in __next__
    return self._next()
  File "/tmpfs/src/git/autosynth/env/lib/python3.6/site-packages/jinja2/environment.py", line 1125, in generate
    yield self.environment.handle_exception()
  File "/tmpfs/src/git/autosynth/env/lib/python3.6/site-packages/jinja2/environment.py", line 832, in handle_exception
    reraise(*rewrite_traceback_stack(source=source))
  File "/tmpfs/src/git/autosynth/env/lib/python3.6/site-packages/jinja2/_compat.py", line 28, in reraise
    raise value.with_traceback(tb)
  File "/tmpfs/src/git/autosynth/env/lib/python3.6/site-packages/synthtool/gcp/templates/node_library/.github/PULL_REQUEST_TEMPLATE.md", line 2, in top-level template code
    - [ ] Make sure to open an issue as a [bug/issue](https://github.com/{{ metadata['repo']['repo'] }}/issues/new/choose) before writing your code!  That way we can discuss the change, evaluate designs, and agree on the general idea
  File "/tmpfs/src/git/autosynth/env/lib/python3.6/site-packages/jinja2/environment.py", line 452, in getitem
    return obj[argument]
jinja2.exceptions.UndefinedError: 'dict object' has no attribute 'repo'

Synthesis failed

Google internal developers can see the full log here.

Support cancellation like Axios

With google-api-nodejs-client's move from Axios to gaxios, the cancellation feature has been lost. This turns out to be important for certain use cases.

For example, the PubSub pull API has an option to return immediately or wait for some messages to arrive. Waiting for some messages is desirable if polling in a loop, so the loop doesn't poll overly frequently causing a high request volume and incurring costs for each request. But if the client decides to cancel the request, it may be stuck waiting for an indeterminate amount of time without the ability to cancel the request.

The ideal solution would be to support the same cancellation semantics as Axios, or some other cancellation API.

Cancellation causes retry with default retry handler

Steps to reproduce

  1. Configure gaxios with an onRetryAttempt handler that logs to console.
  2. Create a gaxios request and then use the cancellation api (AbortController) to cancel it.
  3. Note that the console output indicates the request is an AbortError, and gaxios will attempt to retry the request.

I think this is likely an omission in shouldRetryRequest. While this function can be overridden, the default behavior is probably surprising.

gaxios fails with jest

The default test environment that Jest uses for testing is a browser-like one through jsdom.

The browser-like environment makes your following line of code fail:

const fetch = isBrowser() ? window.fetch : nodeFetch;

because typeof window !== 'undefined' in isBrowser() evaluates to true but window.fetch is undefined.

Maybe, you can directly check against the existence of window.fetch instead of relying on isBrowser.

If you agree, I can send you a PR to replace each and every check against isBrowser with a feature-detection check.

Use retryDelay parameter properly

When I look for how the retry is implemented with exponential delay, I found that retryDelay is not used when calculating the delay.

Maybe the delay could be an addition or multiplication with the retryDelay parameter ? This could let anyone modify the initial delay, or the delay time between retries.

Alternatively, maybe removing the retryDelay from the README and in the code would be less misleading ?

I don't think this break anything, but I guess this would produce a better code quality.

TypeError: this.validateOpts is not a function

Environment details

  • OS: mac, firebase
  • Node.js version: 8.15.0
  • npm version: 6.4.1
  • gaxios version: 2.0.1

Steps to reproduce

Make a request.

Error on ๐Ÿ‘‹ line.

class Gaxios {
    /**
     * The Gaxios class is responsible for making HTTP requests.
     * @param defaults The default set of options to be used for this instance.
     */
    constructor(defaults) {
        this.agentCache = new Map();
        this.defaults = defaults || {};
    }
    /**
     * Perform an HTTP request with the given options.
     * @param opts Set of HTTP options that will be used for this HTTP request.
     */
    async request(opts = {}) {
        opts = this.validateOpts(opts); // <-- ๐Ÿ‘‹๐Ÿ‘‹๐Ÿ‘‹๐Ÿ‘‹๐Ÿ‘‹๐Ÿ‘‹๐Ÿ‘‹๐Ÿ‘‹๐Ÿ‘‹
        try {
            let translatedResponse;
            if (opts.adapter) {
                translatedResponse = await opts.adapter(opts);
            }

function `isReadableStream` failed to judge the object returned from @google-cloud/storage's File.createReadStream

  • OS: Mac OS
  • Node.js version: v11.6.0
  • npm version: v6.11.2
  • gaxios version: 2.0.1

Steps to reproduce

  1. I am using google-api-nodejs-client to upload file to Google Analytics Data Import. Basically, this API expects a readable stream to fulfill a HTTP POST (upload).
  2. It works fine when I use a local file, e.g. fs.createReadStream
  3. It will fail when I use Cloud Storage @google-cloud/storage's file.createReadStream. The Error message is "Error: Media type 'application/json' is not supported. Valid media types: [application/octet-stream]"

I have dug into the code and find the main reason is the function isReadableStream in gaxios.js.
The object from @google-cloud/storage does have the _read function and act as a 'Readable', but it is not the instance of stream.Readable. So the function isReadableStream will always return false here and the request will be changed from application/octet-stream to application/json.

I think the solution maybe:

  • change the logic of this function
    or
  • create a Readable object based the object from @google-cloud/storage (I am not sure this is a good idea)

Please kindly advise. Thanks!

BaseUrl behaves differently from axios

There are 2 discrepancies between gaxios and axios

  1. In axios it's spelled as baseURL instead of baseUrl
  2. baseUrl is supposed to be prepended to the url param specified in the request, however, this breaks if baseUrl contains sub path, think of 'https://googleapi.com/v2/'. It's probably compliant with the standard interpretation of baseUrl, but it's inconsistent with Axios' behavior and what's described in readme.
> const api = new URL('/account/me', 'https://googleapi.com/v2/')
TypeError: URL is not a constructor
URL {
  href: 'https://googleapi.com/account/me',
  origin: 'https://googleapi.com',
  protocol: 'https:',
  username: '',
  password: '',
  host: 'googleapi.com',
  hostname: 'googleapi.com',
  port: '',
  pathname: '/account/me'',
  search: '',
  searchParams: URLSearchParams {},
  hash: '' }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.