Skip to content

Commit f29f111

Browse files
committed
Add Logging for GraphQL Deprecated Reason
* Add log and log type for deprecation reason/notice * Add documentation covering the new log type * Allow the logging of any deprecation reason from GraphQL requests to allow apps to monitor these
1 parent 3d82a57 commit f29f111

File tree

8 files changed

+100
-10
lines changed

8 files changed

+100
-10
lines changed

.changeset/dirty-pumas-laugh.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@shopify/admin-api-client': minor
3+
'@shopify/graphql-client': minor
4+
'@shopify/shopify-api': minor
5+
---
6+
7+
Add Logging for GraphQL Deprecated Reason

packages/api-clients/admin-api-client/README.md

+10-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const {data, errors, extensions} = await client.request(operation, {
5858
| userAgentPrefix? | `string` | Any prefix you wish to include in the User-Agent for requests made by the library. |
5959
| retries? | `number` | The number of HTTP request retries if the request was abandoned or the server responded with a `Too Many Requests (429)` or `Service Unavailable (503)` response. Default value is `0`. Maximum value is `3`. |
6060
| customFetchApi? | `(url: string, init?: {method?: string, headers?: HeaderInit, body?: string}) => Promise<Response>` | A replacement `fetch` function that will be used in all client network requests. By default, the client uses `window.fetch()`. |
61-
| logger? | `(logContent:`[`UnsupportedApiVersionLog`](#unsupportedapiversionlog) `\|`[`HTTPResponseLog`](#httpresponselog)`\|`[`HTTPRetryLog`](#httpretrylog)`) => void` | A logger function that accepts [log content objects](#log-content-types). This logger will be called in certain conditions with contextual information. |
61+
| logger? | `(logContent:`[`UnsupportedApiVersionLog`](#unsupportedapiversionlog) `\|`[`HTTPResponseLog`](#httpresponselog)`\|`[`HTTPRetryLog`](#httpretrylog)`\|`[`HTTPResponseGraphQLDeprecationNotice`](#httpresponsegraphqldeprecationnotice)`) => void` | A logger function that accepts [log content objects](#log-content-types). This logger will be called in certain conditions with contextual information. |
6262

6363
### Client properties
6464

@@ -363,6 +363,15 @@ This log content is sent to the logger whenever the client attempts to retry HTT
363363
| type | `LogType['HTTP-Retry']` | The type of log content. Is always set to `HTTP-Retry` |
364364
| content | `{`[`requestParams`](#requestparams)`: [url, init?], lastResponse?: Response, retryAttempt: number, maxRetries: number}` | Contextual data regarding the upcoming retry attempt. <br /><br/>`requestParams`: [parameters](#requestparams) used in the request<br/>`lastResponse`: previous response <br/> `retryAttempt`: the current retry attempt count <br/> `maxRetries`: the maximum number of retries |
365365

366+
### `HTTPResponseGraphQLDeprecationNotice`
367+
368+
This log content is sent to the logger whenever a HTTP response with a `X-Shopify-API-Deprecated-Reason` is received by the client.
369+
370+
| Property | Type | Description |
371+
| -------- | ------------------------ | ---------------------------------- |
372+
| type | `LogType['HTTP-Response-GraphQL-Deprecation-Notice']` | The type of log content. Is always set to `HTTP-Response-GraphQL-Deprecation-Notice` |
373+
| content | `{`[`requestParams`](#requestparams)`: [url, init?], deprecationNotice: string}` | Contextual data regarding the request and received deprecation information |
374+
366375
#### `RequestParams`
367376

368377
| Property | Type | Description |

packages/api-clients/admin-api-client/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export type {
1616
FetchResponseBody,
1717
HTTPResponseLog,
1818
HTTPRetryLog,
19+
HTTPResponseGraphQLDeprecationNotice,
1920
LogContent,
2021
ResponseWithType,
2122
ReturnData,

packages/api-clients/graphql-client/README.md

+10-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ const client = createGraphQLClient({
7171
| headers | `Record<string, string \| string[]>` | Headers to be included in requests |
7272
| retries? | `number` | The number of HTTP request retries if the request was abandoned or the server responded with a `Too Many Requests (429)` or `Service Unavailable (503)` response. Default value is `0`. Maximum value is `3`. |
7373
| customFetchApi? | `(url: string, init?: {method?: string, headers?: HeaderInit, body?: string}) => Promise<Response>` | A replacement `fetch` function that will be used in all client network requests. By default, the client uses `window.fetch()`. |
74-
| logger? | `(logContent: `[`HTTPResponseLog`](#httpresponselog)`\|`[`HTTPRetryLog`](#httpretrylog)`) => void` | A logger function that accepts [log content objects](#log-content-types). This logger will be called in certain conditions with contextual information. |
74+
| logger? | `(logContent: `[`HTTPResponseLog`](#httpresponselog)`\|`[`HTTPRetryLog`](#httpretrylog)`\|`[`HTTPResponseGraphQLDeprecationNotice`](#httpresponsegraphqldeprecationnotice)`) => void` | A logger function that accepts [log content objects](#log-content-types). This logger will be called in certain conditions with contextual information. |
7575

7676
## Client properties
7777

@@ -313,6 +313,15 @@ This log content is sent to the logger whenever the client attempts to retry HTT
313313
| type | `LogType['HTTP-Retry']` | The type of log content. Is always set to `HTTP-Retry` |
314314
| content | `{`[`requestParams`](#requestparams)`: [url, init?], lastResponse?: Response, retryAttempt: number, maxRetries: number}` | Contextual data regarding the upcoming retry attempt. <br /><br/>`requestParams`: [parameters](#requestparams) used in the request<br/>`lastResponse`: previous response <br/> `retryAttempt`: the current retry attempt count <br/> `maxRetries`: the maximum number of retries |
315315

316+
### `HTTPResponseGraphQLDeprecationNotice`
317+
318+
This log content is sent to the logger whenever a HTTP response with a `X-Shopify-API-Deprecated-Reason` is received by the client.
319+
320+
| Property | Type | Description |
321+
| -------- | ------------------------ | ---------------------------------- |
322+
| type | `LogType['HTTP-Response-GraphQL-Deprecation-Notice']` | The type of log content. Is always set to `HTTP-Response-GraphQL-Deprecation-Notice` |
323+
| content | `{`[`requestParams`](#requestparams)`: [url, init?], deprecationNotice: string}` | Contextual data regarding the request and received deprecation information |
324+
316325
### `RequestParams`
317326

318327
| Property | Type | Description |

packages/api-clients/graphql-client/src/graphql-client/http-fetch.ts

+17-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import {CLIENT, RETRIABLE_STATUS_CODES, RETRY_WAIT_TIME} from './constants';
2-
import {CustomFetchApi, GraphQLClient, Logger} from './types';
3-
import {formatErrorMessage, getErrorMessage} from './utilities';
1+
import { CLIENT, RETRIABLE_STATUS_CODES, RETRY_WAIT_TIME } from './constants';
2+
import { CustomFetchApi, GraphQLClient, Logger } from './types';
3+
import { formatErrorMessage, getErrorMessage } from './utilities';
44

55
interface GenerateHttpFetchOptions {
66
clientLogger: Logger;
@@ -45,6 +45,17 @@ export function generateHttpFetch({
4545
throw new Error();
4646
}
4747

48+
const deprecationNotice = response?.headers.get('X-Shopify-API-Deprecated-Reason') || '';
49+
if (deprecationNotice) {
50+
clientLogger({
51+
type: 'HTTP-Response-GraphQL-Deprecation-Notice',
52+
content: {
53+
requestParams,
54+
deprecationNotice,
55+
},
56+
});
57+
}
58+
4859
return response;
4960
} catch (error) {
5061
if (nextCount <= maxTries) {
@@ -68,10 +79,9 @@ export function generateHttpFetch({
6879

6980
throw new Error(
7081
formatErrorMessage(
71-
`${
72-
maxRetries > 0
73-
? `Attempted maximum number of ${maxRetries} network retries. Last message - `
74-
: ''
82+
`${maxRetries > 0
83+
? `Attempted maximum number of ${maxRetries} network retries. Last message - `
84+
: ''
7585
}${getErrorMessage(error)}`,
7686
client,
7787
),

packages/api-clients/graphql-client/src/graphql-client/tests/http-fetch.test.ts

+37
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,43 @@ describe('httpFetch utility', () => {
116116
expect(fetch).toHaveBeenCalledTimes(1);
117117
});
118118

119+
it('logs any graphql deprecation notices', async () => {
120+
const httpFetch = generateHttpFetch({clientLogger});
121+
const mockedResponseWithDeprecation = new Response(
122+
JSON.stringify({data: {}}),
123+
{
124+
status: 200,
125+
headers: new Headers({
126+
'X-Shopify-API-Deprecated-Reason': 'A deprecation notice',
127+
'Content-Type': 'application/json',
128+
}),
129+
},
130+
);
131+
132+
fetchMock.mockResolvedValue(mockedResponseWithDeprecation);
133+
134+
const requestParams: Parameters<CustomFetchApi> = [
135+
url,
136+
{
137+
method: 'POST',
138+
body: JSON.stringify({query: operation}),
139+
},
140+
];
141+
const response = await httpFetch(requestParams, 1, 2);
142+
143+
expect(response.status).toBe(200);
144+
expect(fetch).toHaveBeenCalledTimes(1);
145+
146+
expect(clientLogger).toHaveBeenCalledTimes(1);
147+
expect(clientLogger).toHaveBeenNthCalledWith(1, {
148+
type: 'HTTP-Response-GraphQL-Deprecation-Notice',
149+
content: {
150+
requestParams,
151+
deprecationNotice: 'A deprecation notice',
152+
},
153+
});
154+
});
155+
119156
describe('retries', () => {
120157
let httpFetch: ReturnType<typeof generateHttpFetch>;
121158

packages/api-clients/graphql-client/src/graphql-client/types.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,14 @@ export interface HTTPResponseLog extends LogContent {
6060
};
6161
}
6262

63+
export interface HTTPResponseGraphQLDeprecationNotice extends LogContent {
64+
type: 'HTTP-Response-GraphQL-Deprecation-Notice';
65+
content: {
66+
requestParams: Parameters<CustomFetchApi>;
67+
deprecationNotice: string;
68+
};
69+
}
70+
6371
export interface HTTPRetryLog extends LogContent {
6472
type: 'HTTP-Retry';
6573
content: {
@@ -70,7 +78,7 @@ export interface HTTPRetryLog extends LogContent {
7078
};
7179
}
7280

73-
export type LogContentTypes = HTTPResponseLog | HTTPRetryLog;
81+
export type LogContentTypes = HTTPResponseLog | HTTPRetryLog | HTTPResponseGraphQLDeprecationNotice;
7482

7583
export type Logger<TLogContentTypes = LogContentTypes> = (
7684
logContent: TLogContentTypes,

packages/apps/shopify-api/lib/clients/common.ts

+9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {
22
HTTPResponseLog,
33
HTTPRetryLog,
4+
HTTPResponseGraphQLDeprecationNotice,
45
LogContent,
56
} from '@shopify/admin-api-client';
67
import {StatusCode} from '@shopify/network';
@@ -47,6 +48,14 @@ export function clientLoggerFactory(config: ConfigInterface) {
4748
});
4849
break;
4950
}
51+
case 'HTTP-Response-GraphQL-Deprecation-Notice': {
52+
const responseLog: HTTPResponseGraphQLDeprecationNotice['content'] = logContent.content;
53+
logger(config).debug('Received response containing Deprecated GraphQL Notice', {
54+
requestParams: JSON.stringify(responseLog.requestParams),
55+
deprecationNotice: responseLog.deprecationNotice,
56+
});
57+
break;
58+
}
5059
default: {
5160
logger(config).debug(`HTTP request event: ${logContent.content}`);
5261
break;

0 commit comments

Comments
 (0)