Skip to content

Commit

Permalink
New requestDeduplication field on DataSourceFetchResult (#122)
Browse files Browse the repository at this point in the history
This field is returned if you call `fetch` instead of `get` (etc) and it
tells you what the deduplication policy was and if it matched.

Also allow `this.fetch` to be called with only one argument (because we
previously made `method` optional).

Part of #41 (which also requests adding information on the other cache's
status).
  • Loading branch information
glasser authored Dec 14, 2022
1 parent 1882112 commit 130dc98
Show file tree
Hide file tree
Showing 3 changed files with 503 additions and 52 deletions.
2 changes: 2 additions & 0 deletions .changeset/wet-ligers-tap.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ Add public `fetch` method
Users previously had no well-defined way to access the complete response (i.e. for header inspection). The public API of HTTP helper methods only returned the parsed response body. A `didReceiveResponse` hook existed as an attempt to solve this, but its semantics weren't well-defined, nor was it a type safe approach to solving the problem.

The new `fetch` method allows users to "bypass" the convenience of the HTTP helpers in order to construct their own full request and inspect the complete response themselves.

The `DataSourceFetchResult` type returned by this method also contains other useful information, like a `requestDeduplication` field containing the request's deduplication policy and whether it was deduplicated against a previous request.
33 changes: 28 additions & 5 deletions src/RESTDataSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,15 @@ export interface DataSourceConfig {
cache?: KeyValueCache;
fetch?: Fetcher;
}

export interface RequestDeduplicationResult {
policy: RequestDeduplicationPolicy;
deduplicatedAgainstPreviousRequest: boolean;
}
export interface DataSourceFetchResult<TResult> {
parsedBody: TResult;
response: FetcherResponse;
requestDeduplication: RequestDeduplicationResult;
// This is primarily returned so that tests can be deterministic.
cacheWritePromise: Promise<void> | undefined;
}
Expand Down Expand Up @@ -257,10 +263,15 @@ export abstract class RESTDataSource {
}

private cloneDataSourceFetchResult<TResult>(
dataSourceFetchResult: DataSourceFetchResult<TResult>,
dataSourceFetchResult: Omit<
DataSourceFetchResult<TResult>,
'requestDeduplication'
>,
requestDeduplicationResult: RequestDeduplicationResult,
): DataSourceFetchResult<TResult> {
return {
...dataSourceFetchResult,
requestDeduplication: requestDeduplicationResult,
parsedBody: this.cloneParsedBody(dataSourceFetchResult.parsedBody),
};
}
Expand Down Expand Up @@ -413,7 +424,7 @@ export abstract class RESTDataSource {

public async fetch<TResult>(
path: string,
incomingRequest: DataSourceRequest,
incomingRequest: DataSourceRequest = {},
): Promise<DataSourceFetchResult<TResult>> {
const augmentedRequest: AugmentedRequest = {
...incomingRequest,
Expand Down Expand Up @@ -511,7 +522,10 @@ export abstract class RESTDataSource {
);
if (previousRequestPromise)
return previousRequestPromise.then((result) =>
this.cloneDataSourceFetchResult(result),
this.cloneDataSourceFetchResult(result, {
policy,
deduplicatedAgainstPreviousRequest: true,
}),
);

const thisRequestPromise = performRequest();
Expand All @@ -529,7 +543,10 @@ export abstract class RESTDataSource {
// Note: we could try to get fancy and only clone if no de-duplication
// happened (and we're "deduplicate-during-request-lifetime") but we
// haven't quite bothered yet.
return this.cloneDataSourceFetchResult(await thisRequestPromise);
return this.cloneDataSourceFetchResult(await thisRequestPromise, {
policy,
deduplicatedAgainstPreviousRequest: false,
});
} finally {
if (policy.policy === 'deduplicate-during-request-lifetime') {
this.deduplicationPromises.delete(policy.deduplicationKey);
Expand All @@ -539,7 +556,13 @@ export abstract class RESTDataSource {
for (const key of policy.invalidateDeduplicationKeys ?? []) {
this.deduplicationPromises.delete(key);
}
return performRequest();
return {
...(await performRequest()),
requestDeduplication: {
policy,
deduplicatedAgainstPreviousRequest: false,
},
};
}
}

Expand Down
Loading

0 comments on commit 130dc98

Please sign in to comment.