Skip to content
This repository has been archived by the owner on Apr 11, 2024. It is now read-only.

Commit

Permalink
Add logger feature and updated retry error messages
Browse files Browse the repository at this point in the history
  • Loading branch information
melissaluu committed Oct 23, 2023
1 parent 6553ba7 commit 8287803
Show file tree
Hide file tree
Showing 4 changed files with 426 additions and 49 deletions.
29 changes: 29 additions & 0 deletions packages/graphql-client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ const client = createGraphQLClient({
| url | `string` | The Storefront API URL |
| headers | `{[key: string]: string}` | Headers to be included in requests |
| 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`. |
| fetchAPI? | `(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()`. |
| 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. |

## Client properties

Expand Down Expand Up @@ -180,3 +182,30 @@ if (response.ok) {
const {errors, data, extensions} = await response.json();
}
```

## Log Content Types

### `HTTPResponseLog`

This log content is sent to the logger whenever a HTTP response is received by the client.

| Property | Type | Description |
| -------- | ------------------------ | ---------------------------------- |
| type | `LogType['HTTP-Response']` | The type of log content. Is always set to `HTTP-Response` |
| content | `{requestParams: `[RequestParams](#requestparams)`, response: Response}` | Contextual data regarding the received response |

### `HTTPRetryLog`

This log content is sent to the logger whenever the client attempts to retry HTTP requests.

| Property | Type | Description |
| -------- | ------------------------ | ---------------------------------- |
| type | `LogType['HTTP-Retry']` | The type of log content. Is always set to `HTTP-Retry` |
| content | `{requestParams: `[RequestParams](#requestparams)`, lastResponse?: Response, retryAttempt: number, maxRetries: number}` | Contextual data regarding the upcoming retry attempt. <br /><br/>`lastResponse`: previous response <br/> `retryAttempt`: the current retry attempt count <br/> `maxRetries`: the maximum number of retries |

### `RequestParams`

| Property | Type | Description |
| -------- | ------------------------ | ---------------------------------- |
| url | `string` | Requested URL |
| init? | `{method?: string, headers?: HeaderInit, body?: string}` | The request information |
53 changes: 43 additions & 10 deletions packages/graphql-client/src/graphql-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import {
CustomFetchAPI,
GraphQLClient,
ClientResponse,
LogContentTypes,
ClientConfig,
} from "./types";
import { getErrorMessage } from "./utilities";

Expand Down Expand Up @@ -66,23 +68,42 @@ export function createGraphQLClient<TClientOptions extends ClientOptions>({
url,
fetchAPI = fetch,
retries = 0,
logger,
}: TClientOptions): GraphQLClient {
validateRetries(retries);

const config = {
const config: ClientConfig = {
headers,
url,
retries,
};

const clientLogger = (logContent: LogContentTypes) => {
if (logger) {
logger(logContent);
}
};

const httpFetch = async (
params: Parameters<CustomFetchAPI>,
requestParams: Parameters<CustomFetchAPI>,
count: number,
maxTries: number
maxRetries: number
): ReturnType<GraphQLClient["fetch"]> => {
const nextCount = count + 1;
const maxTries = maxRetries + 1;
let response: Response | undefined;

try {
const response = await fetchAPI(...params);
response = await fetchAPI(...requestParams);

clientLogger({
type: "HTTP-Response",
content: {
requestParams,
response,
},
});

if (
!response.ok &&
RETRIABLE_STATUS_CODES.includes(response.status) &&
Expand All @@ -95,13 +116,26 @@ export function createGraphQLClient<TClientOptions extends ClientOptions>({
} catch (error) {
if (nextCount <= maxTries) {
await sleep(RETRY_WAIT_TIME);
return httpFetch(params, nextCount, maxTries);

clientLogger({
type: "HTTP-Retry",
content: {
requestParams,
lastResponse: response,
retryAttempt: count,
maxRetries,
},
});

return httpFetch(requestParams, nextCount, maxRetries);
}

throw new Error(
`${ERROR_PREFIX} Exceeded maximum number of ${maxTries} network tries. Last message - ${getErrorMessage(
error
)}`
`${ERROR_PREFIX}${
maxRetries > 0
? ` Attempted maximum number of ${maxRetries} network retries. Last message -`
: ""
} ${getErrorMessage(error)}`
);
}
};
Expand Down Expand Up @@ -132,9 +166,8 @@ export function createGraphQLClient<TClientOptions extends ClientOptions>({
body,
},
];
const maxTries = (overrideRetries ?? retries) + 1;

return httpFetch(fetchParams, 1, maxTries);
return httpFetch(fetchParams, 1, overrideRetries ?? retries);
};

const request: GraphQLClient["request"] = async (...props) => {
Expand Down
Loading

0 comments on commit 8287803

Please sign in to comment.