Skip to content

Releases: apollographql/datasource-rest

v5.1.1

01 May 18:42
d8d5c0d

Choose a tag to compare

Patch Changes

v5.1.0

24 Apr 19:27
49a0bb9

Choose a tag to compare

Minor Changes

  • #186 5ac9b52 Thanks @js-lowes! - Customize the logger used by RESTDataSource.
    By default the RESTDataSource will use console.
    Common use cases would be to override the default logger with pino or winston.

    E.g.

    const pino = require('pino');
    const loggerPino = pino({});
    const dataSource = new (class extends RESTDataSource {})({
      logger: loggerPino,
    });

    In the example above, all logging calls made by the RESTDataSource will now use the pino logger instead of the console logger.

v5.0.2

06 Feb 22:36
c65c14b

Choose a tag to compare

Patch Changes

  • #159 ee018a7 Thanks @trevor-scheer! - Update http-cache-semantics package to latest patch, resolving a security
    issue.

    Unlike many security updates Apollo repos receive, this is an actual (non-dev)
    dependency of this package which means it is actually a user-facing security
    issue.

    The potential impact of this issue is limited to a DOS attack (via an
    inefficient regex).

    This security issue would only affect you if either:

    • you pass untrusted (i.e. from your users) cache-control request headers
    • you sending requests to untrusted REST server that might return malicious
      cache-control headers

    Since http-cache-semantics is a careted (^) dependency in this package, the
    security issue can (and might already) be resolved via a package-lock.json
    update within your project (possibly triggered by npm audit or another
    dependency update which has already updated its version of the package in
    question). If npm ls http-cache-semantics reveals a tree of dependencies which
    only include the 4.1.1 version (and no references to any previous versions)
    then you are currently unaffected and this patch should have (for all intents
    and purpose) no effect.

    More details available here: GHSA-rc47-6667-2j5j

  • #160 786c44f Thanks @trevor-scheer! - Add missing @apollo/utils.withrequired type dependency which is part of the
    public typings (via the AugmentedRequest type).

  • #154 bb0cff0 Thanks @JustinSomers! - Addresses duplicate content-type header bug due to upper-cased headers being forwarded. This change instead maps all headers to lowercased headers.

v5.0.1

12 Jan 00:46
485b02d

Choose a tag to compare

Patch Changes

  • #137 c9ffa7f Thanks @trevor-scheer! - Create intermediate request types (PostRequest, etc.) for consistency and export them.
    Export DataSourceRequest, DataSourceConfig, and DataSourceFetchResult types.

v5.0.0

10 Jan 16:54
c1cee39

Choose a tag to compare

Version 5 of RESTDataSource addresses many of the long-standing issues and PRs that have existed in this repository (and its former location in the apollo-server repository). While this version does include a number of breaking changes, our hope is that the updated API makes this package more usable and its caching-related behavior less surprising.

The entries below enumerate all of the changes in v5 in detail along with their associated PRs. If you are migrating from v3 or v4, we recommend at least skimming the entries below to see if you're affected by the breaking changes. As always, we recommend using TypeScript with our libraries. This will be especially helpful in surfacing changes to the API which affect your usage. Even if you don't use TypeScript, you can still benefit from the typings we provide using various convenience tools like // @ts-check (with compatible editors like VS Code).

TL;DR

At a higher level, the most notable changes include:

Breaking

  • Remove magic around request deduplication behavior and provide a hook to configure its behavior. Previously, requests were deduplicated forever by default. Now, only requests happening concurrently will be deduplicated (and subsequently cleared from the in-memory cache).
  • Cache keys now include the request method by default (no more overlap in GET and POST requests).
  • Remove the semantically confusing didReceiveResponse hook.
  • Paths now behave as links would in a web browser, allowing path segments to contain colons.

Additive

  • Introduce a public fetch method, giving access to the full Response object
  • Improve ETag header semantics (correctly handle Last-Modified header)
  • Introduce a public head class method for issuing HEAD requests

Major Changes

  • #100 2e51657 Thanks @glasser! - Instead of memoizing GET requests forever in memory, only apply de-duplication during the lifetime of the original request. Replace the memoizeGetRequests field with a requestDeduplicationPolicyFor() method to determine how de-duplication works per request.

    To restore the surprising infinite-unconditional-cache behavior of previous versions, use this implementation of requestDeduplicationPolicyFor() (which replaces deduplicate-during-request-lifetime with deduplicate-until-invalidated):

    override protected requestDeduplicationPolicyFor(
      url: URL,
      request: RequestOptions,
    ): RequestDeduplicationPolicy {
      const cacheKey = this.cacheKeyFor(url, request);
      if (request.method === 'GET') {
        return {
          policy: 'deduplicate-until-invalidated',
          deduplicationKey: `${request.method} ${cacheKey}`,
        };
      } else {
        return {
          policy: 'do-not-deduplicate',
          invalidateDeduplicationKeys: [`GET ${cacheKey}`],
        };
      }
    }

    To restore the behavior of memoizeGetRequests = false, use this implementation of requestDeduplicationPolicyFor():

    protected override requestDeduplicationPolicyFor() {
      return { policy: 'do-not-deduplicate' } as const;
    }
  • #89 4a249ec Thanks @trevor-scheer! - This change restores the full functionality of willSendRequest which
    previously existed in the v3 version of this package. The v4 change introduced a
    regression where the incoming request's body was no longer included in the
    object passed to the willSendRequest hook, it was always undefined.

    For consistency and typings reasons, the path argument is now the first
    argument to the willSendRequest hook, followed by the AugmentedRequest
    request object.

  • #115 be4371f Thanks @glasser! - The errorFromResponse method now receives an options object with url, request, response, and parsedBody rather than just a response, and the body has already been parsed.

  • #110 ea43a27 Thanks @trevor-scheer! - Update default cacheKeyFor to include method

    In its previous form, cacheKeyFor only used the URL to calculate the cache key. As a result, when cacheOptions.ttl was specified, the method was ignored. This could lead to surprising behavior where a POST request's response was cached and returned for a GET request (for example).

    The default cacheKeyFor now includes the request method, meaning there will now be distinct cache entries for a given URL per method.

  • #88 2c3dbd0 Thanks @glasser! - When passing params as an object, parameters with undefined values are now skipped, like with JSON.stringify. So you can write:

    getUser(query: string | undefined) {
      return this.get('user', { params: { query } });
    }

    and if query is not provided, the query parameter will be left off of the URL instead of given the value undefined.

    As part of this change, we've removed the ability to provide params in formats other than this kind of object or as an URLSearchParams object. Previously, we allowed every form of input that could be passed to new URLSearchParams(). If you were using one of the other forms (like a pre-serialized URL string or an array of two-element arrays), just pass it directly to new URLSearchParams; note that the feature of stripping undefined values will not occur in this case. For example, you can replace this.get('user', { params: [['query', query]] }) with this.get('user', { params: new URLSearchParams([['query', query]]) }). (URLSearchParams is available in Node as a global.)

  • #107 4b2a6f9 Thanks @trevor-scheer! - Remove didReceiveResponse hook

    The naming of this hook is deceiving; if this hook is overridden it becomes
    responsible for returning the parsed body and handling errors if they occur. It
    was originally introduced in
    apollographql/apollo-server#1324, where the author
    implemented it due to lack of access to the complete response (headers) in the
    fetch methods (get, post, ...). This approach isn't a type safe way to
    accomplish this and places the burden of body parsing and error handling on the
    user.

    Removing this hook is a prerequisite to a subsequent change that will introduce
    the ability to fetch a complete response (headers included) aside from the
    provided fetch methods which only return a body. This change will reinstate the
    functionality that the author of this hook had originally intended in a more
    direct manner.

  • #95 c59b82f Thanks @glasser! - Simplify interpretation of this.baseURL so it works exactly like links in a web browser.

    If you set this.baseURL to an URL with a non-empty path component, this may change the URL that your methods talk to. Specifically:

    • Paths passed to methods such as this.get('/foo') now replace the entire URL path from this.baseURL. If you did not intend this, write this.get('foo') instead.
    • If this.baseURL has a non-empty path and does not end in a trailing slash, paths such as this.get('foo') will replace the last component of the URL path instead of adding a new component. If you did not intend this, add a trailing slash to this.baseURL.

    If you preferred the v4 semantics and do not want to make the changes described above, you can restore v4 semantics by overriding resolveURL in your subclass with the following code from v4:

    override resolveURL(path: string): ValueOrPromise<URL> {
      if (path.startsWith('/')) {
        path = path.slice(1);
      }
      const baseURL = this.baseURL;
      if (baseURL) {
        const normalizedBaseURL = baseURL.endsWith('/')
          ? baseURL
          : baseURL.concat('/');
        return new URL(path, normalizedBaseURL);
      } else {
        return new URL(path);
      }
    }

    As part of this change, it is now possible to specify URLs whose first path segment contains a colon, such as this.get('/foo:bar').

  • #121 32f8f04 Thanks @glasser! - We now write to the shared HTTP-header-sensitive cache in the background rather than before the fetch resolves. By default, errors talking to the cache are logged with console.log; override catchCacheWritePromiseErrors to customize. If you call fetch(), the result object has a httpCache.cacheWritePromise field that you can await if you want to know when the cache write ends.

Minor Changes

Read more

v4.3.2

12 Oct 19:47
1249df2

Choose a tag to compare

Patch Changes

v4.3.1

12 Oct 15:11
a24447b

Choose a tag to compare

Patch Changes

v4.3.0

10 Oct 20:59
99dbd38

Choose a tag to compare

Minor Changes

v4.2.0

22 Aug 19:32
25862e1

Choose a tag to compare

Minor Changes

  • #5 1857515 Thanks @smyrick! - Rename requestCacheEnabled to memoizeGetRequests. Acknowledging this is
    actually a breaking change, but this package has been live for a weekend with
    nothing recommending its usage yet.

v4.1.0

19 Aug 22:18

Choose a tag to compare

Minor Changes