diff --git a/.changeset/long-experts-chew.md b/.changeset/long-experts-chew.md new file mode 100644 index 0000000..91a88ad --- /dev/null +++ b/.changeset/long-experts-chew.md @@ -0,0 +1,5 @@ +--- +'@apollo/datasource-rest': minor +--- + +Add metadata if response came from cache diff --git a/package.json b/package.json index 9229ab1..21927cb 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "test:ci": "jest --coverage --ci --maxWorkers=2 --reporters=default --reporters=jest-junit", "watch": "tsc --build --watch", "lint": "eslint src/**/*.ts", + "changeset-add": "changeset add", "changeset-publish": "changeset publish", "changeset-check": "changeset status --verbose --since=origin/main" }, diff --git a/src/HTTPCache.ts b/src/HTTPCache.ts index fda4a56..d4ffee5 100644 --- a/src/HTTPCache.ts +++ b/src/HTTPCache.ts @@ -29,6 +29,7 @@ interface SneakyCachePolicy extends CachePolicy { interface ResponseWithCacheWritePromise { response: FetcherResponse; + responseFromCache?: Boolean; cacheWritePromise?: Promise; } @@ -72,7 +73,10 @@ export class HTTPCache { // refreshing headers with HEAD requests, responding to HEADs with cached // and valid GETs, etc.) if (requestOpts.method === 'HEAD') { - return { response: await this.httpFetch(urlString, requestOpts) }; + return { + response: await this.httpFetch(urlString, requestOpts), + responseFromCache: false, + }; } const entry = @@ -127,6 +131,7 @@ export class HTTPCache { status: policy._status, headers: cachePolicyHeadersToNodeFetchHeadersInit(headers), }), + responseFromCache: true, }; } else { // We aren't sure that we're allowed to use the cached response, so we are diff --git a/src/__tests__/HTTPCache.test.ts b/src/__tests__/HTTPCache.test.ts index 0f6b255..8a9e66a 100644 --- a/src/__tests__/HTTPCache.test.ts +++ b/src/__tests__/HTTPCache.test.ts @@ -63,10 +63,12 @@ describe('HTTPCache', () => { it('fetches a response from the origin when not cached', async () => { mockGetAdaLovelace(); - const { response, cacheWritePromise } = await httpCache.fetch(adaUrl); + const { response, responseFromCache, cacheWritePromise } = + await httpCache.fetch(adaUrl); expect(cacheWritePromise).toBeUndefined(); expect(await response.json()).toEqual({ name: 'Ada Lovelace' }); + expect(responseFromCache).toBeFalsy(); }); it('returns a cached response when not expired', async () => { @@ -79,11 +81,12 @@ describe('HTTPCache', () => { await cacheWritePromise; jest.advanceTimersByTime(10000); - const { response } = await httpCache.fetch(adaUrl); + const { response, responseFromCache } = await httpCache.fetch(adaUrl); expect(response.url).toBe(adaUrl.toString()); expect(await response.json()).toEqual({ name: 'Ada Lovelace' }); expect(response.headers.get('age')).toEqual('10'); + expect(responseFromCache).toBe(true); }); it('fetches a fresh response from the origin when expired', async () => { @@ -96,12 +99,13 @@ describe('HTTPCache', () => { mockGetAlanTuring({ 'cache-control': 'max-age=30' }); - const { response } = await httpCache.fetch( + const { response, responseFromCache } = await httpCache.fetch( new URL('https://api.example.com/people/1'), ); expect(await response.json()).toEqual({ name: 'Alan Turing' }); expect(response.headers.get('age')).toBeNull(); + expect(responseFromCache).toBeFalsy(); }); describe('overriding TTL', () => {