@apollo/datasource-rest
Advanced tools
Comparing version 5.0.1 to 5.0.2
@@ -84,3 +84,3 @@ /// <reference types="node" /> | ||
protected cacheOptionsFor?(url: string, response: FetcherResponse, request: FetcherRequestInit): ValueOrPromise<CacheOptions | undefined>; | ||
protected didEncounterError(error: Error, _request: RequestOptions): void; | ||
protected didEncounterError(_error: Error, _request: RequestOptions): void; | ||
protected parseBody(response: FetcherResponse): Promise<object | string>; | ||
@@ -87,0 +87,0 @@ private cloneDataSourceFetchResult; |
@@ -43,4 +43,3 @@ "use strict"; | ||
} | ||
didEncounterError(error, _request) { | ||
throw error; | ||
didEncounterError(_error, _request) { | ||
} | ||
@@ -155,3 +154,9 @@ parseBody(response) { | ||
async fetch(path, incomingRequest = {}) { | ||
var _a, _b; | ||
var _a; | ||
const downcasedHeaders = {}; | ||
if (incomingRequest.headers) { | ||
Object.entries(incomingRequest.headers).forEach(([key, value]) => { | ||
downcasedHeaders[key.toLowerCase()] = value; | ||
}); | ||
} | ||
const augmentedRequest = { | ||
@@ -162,3 +167,3 @@ ...incomingRequest, | ||
: this.urlSearchParamsFromRecord(incomingRequest.params), | ||
headers: (_a = incomingRequest.headers) !== null && _a !== void 0 ? _a : Object.create(null), | ||
headers: downcasedHeaders, | ||
}; | ||
@@ -176,6 +181,3 @@ if (!augmentedRequest.method) | ||
augmentedRequest.body = JSON.stringify(augmentedRequest.body); | ||
if (!augmentedRequest.headers) { | ||
augmentedRequest.headers = { 'content-type': 'application/json' }; | ||
} | ||
else if (!augmentedRequest.headers['content-type']) { | ||
if (!augmentedRequest.headers['content-type']) { | ||
augmentedRequest.headers['content-type'] = 'application/json'; | ||
@@ -246,3 +248,3 @@ } | ||
else { | ||
for (const key of (_b = policy.invalidateDeduplicationKeys) !== null && _b !== void 0 ? _b : []) { | ||
for (const key of (_a = policy.invalidateDeduplicationKeys) !== null && _a !== void 0 ? _a : []) { | ||
this.deduplicationPromises.delete(key); | ||
@@ -249,0 +251,0 @@ } |
{ | ||
"name": "@apollo/datasource-rest", | ||
"description": "REST DataSource for Apollo Server v4", | ||
"version": "5.0.1", | ||
"version": "5.0.2", | ||
"author": "Apollo <packages@apollographql.com>", | ||
@@ -33,19 +33,18 @@ "license": "MIT", | ||
"devDependencies": { | ||
"@apollo/server": "4.3.0", | ||
"@apollo/utils.withrequired": "2.0.0", | ||
"@apollo/server": "4.3.2", | ||
"@changesets/changelog-github": "0.4.8", | ||
"@changesets/cli": "2.26.0", | ||
"@types/jest": "29.2.5", | ||
"@types/jest": "29.4.0", | ||
"@types/lodash.isplainobject": "4.0.7", | ||
"@types/node": "14.18.36", | ||
"cspell": "6.18.1", | ||
"cspell": "6.22.0", | ||
"form-data": "4.0.0", | ||
"graphql": "16.6.0", | ||
"jest": "29.3.1", | ||
"jest": "29.4.1", | ||
"jest-junit": "15.0.0", | ||
"nock": "13.2.9", | ||
"prettier": "2.8.2", | ||
"ts-jest": "29.0.3", | ||
"nock": "13.3.0", | ||
"prettier": "2.8.3", | ||
"ts-jest": "29.0.5", | ||
"ts-node": "10.9.1", | ||
"typescript": "4.9.4" | ||
"typescript": "4.9.5" | ||
}, | ||
@@ -55,4 +54,5 @@ "dependencies": { | ||
"@apollo/utils.keyvaluecache": "^2.0.0", | ||
"@apollo/utils.withrequired": "^2.0.0", | ||
"@types/http-cache-semantics": "^4.0.1", | ||
"http-cache-semantics": "^4.1.0", | ||
"http-cache-semantics": "^4.1.1", | ||
"lodash.isplainobject": "^4.0.6", | ||
@@ -65,5 +65,5 @@ "node-fetch": "^2.6.7" | ||
"volta": { | ||
"node": "18.13.0", | ||
"npm": "9.2.0" | ||
"node": "18.14.0", | ||
"npm": "9.4.1" | ||
} | ||
} |
@@ -193,4 +193,9 @@ # Apollo REST Data Source | ||
##### `didEncounterError` | ||
By default, this method just throws the `error` it was given. If you override this method, you can choose to either perform some additional logic and still throw, or to swallow the error by not throwing the error result. | ||
> Note: In previous versions of RESTDataSource (< v5), this hook was expected to throw the error it received (the default implementation did exactly that). This is no longer required; as mentioned below, the error will be thrown immediately after invoking `didEncounterError`. | ||
You can implement this hook in order to inspect (or modify) errors that are thrown while fetching, parsing the body (`parseBody()`), or by the `throwIfResponseIsError()` hook. The error that this hook receives will be thrown immediately after this hook is invoked. | ||
You can also throw a different error here altogether. Note that by default, errors are `GraphQLError`s (coming from `errorFromResponse`). | ||
##### `parseBody` | ||
@@ -276,20 +281,18 @@ | ||
Data sources allow you to intercept fetches to set headers, query parameters, or make other changes to the outgoing request. This is most often used for authorization or other common concerns that apply to all requests. Data sources also get access to the GraphQL context, which is a great place to store a user token or other information you need to have available. | ||
Data sources allow you to intercept fetches to set headers, query parameters, or make other changes to the outgoing request. This is most often used for authorization or other common concerns that apply to all requests. The `constructor` can be overridden to require additional contextual information when the class is instantiated like so: | ||
You can easily set a header on every request: | ||
```ts | ||
class PersonalizationAPI extends RESTDataSource { | ||
private token: string; | ||
```javascript | ||
class PersonalizationAPI extends RESTDataSource { | ||
willSendRequest(path, request) { | ||
request.headers['authorization'] = this.context.token; | ||
constructor(token: string) { | ||
super(); | ||
this.token = token; | ||
} | ||
} | ||
``` | ||
Or add a query parameter: | ||
```javascript | ||
class PersonalizationAPI extends RESTDataSource { | ||
willSendRequest(path, request) { | ||
request.params.set('api_key', this.context.token); | ||
// set an authorization header | ||
request.headers['authorization'] = this.token; | ||
// or set a query parameter | ||
request.params.set('api_key', this.token); | ||
} | ||
@@ -307,5 +310,5 @@ } | ||
private token: string; | ||
constructor(options: { cache: KeyValueCache; token: string}) { | ||
super(options); | ||
this.token = options.token; | ||
constructor(token: string) { | ||
super(); | ||
this.token = token; | ||
} | ||
@@ -319,3 +322,26 @@ | ||
### Processing Responses | ||
> Looking for `didReceiveResponse`? This section is probably interesting to you. | ||
You might need to read or mutate the response before it's returned. For example, you might need to log a particular header for each request. To do this, you can override the public `fetch` method like so: | ||
```ts | ||
class MyDataSource extends RESTDataSource { | ||
override async fetch<TResult>( | ||
path: string, | ||
incomingRequest: DataSourceRequest = {} | ||
) { | ||
const result = await super.fetch(path, incomingRequest); | ||
const header = result.response.headers.get('my-custom-header'); | ||
if (header) { | ||
console.log(`Found header: ${header}`); | ||
} | ||
return result; | ||
} | ||
} | ||
``` | ||
This example leverages the default `fetch` implementation from the parent (`super`). We append our step to the promise chain, read the header, and return the original result that the `super.fetch` promise resolved to (`{ parsedBody, response }`). | ||
### Integration with Apollo Server | ||
@@ -322,0 +348,0 @@ |
@@ -260,4 +260,7 @@ import type { | ||
protected didEncounterError(error: Error, _request: RequestOptions) { | ||
throw error; | ||
protected didEncounterError(_error: Error, _request: RequestOptions) { | ||
// left as a no-op instead of an unimplemented optional method to avoid | ||
// breaking an existing use case where one calls | ||
// `super.didEncounterErrors(...)` This could be unimplemented / undefined | ||
// in a theoretical next major of this package. | ||
} | ||
@@ -455,2 +458,10 @@ | ||
): Promise<DataSourceFetchResult<TResult>> { | ||
const downcasedHeaders: Record<string, string> = {}; | ||
if (incomingRequest.headers) { | ||
// map incoming headers to lower-case headers | ||
Object.entries(incomingRequest.headers).forEach(([key, value]) => { | ||
downcasedHeaders[key.toLowerCase()] = value; | ||
}); | ||
} | ||
const augmentedRequest: AugmentedRequest = { | ||
@@ -463,3 +474,3 @@ ...incomingRequest, | ||
: this.urlSearchParamsFromRecord(incomingRequest.params), | ||
headers: incomingRequest.headers ?? Object.create(null), | ||
headers: downcasedHeaders, | ||
}; | ||
@@ -484,5 +495,3 @@ // Default to GET in the case that `fetch` is called directly with no method | ||
// If Content-Type header has not been previously set, set to application/json | ||
if (!augmentedRequest.headers) { | ||
augmentedRequest.headers = { 'content-type': 'application/json' }; | ||
} else if (!augmentedRequest.headers['content-type']) { | ||
if (!augmentedRequest.headers['content-type']) { | ||
augmentedRequest.headers['content-type'] = 'application/json'; | ||
@@ -489,0 +498,0 @@ } |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
105165
16
1562
386
8
+ Added@apollo/utils.withrequired@2.0.1(transitive)
Updatedhttp-cache-semantics@^4.1.1