@shopify/graphql-client
Advanced tools
Comparing version 0.2.0 to 0.3.0
import { ClientOptions, GraphQLClient } from "./types"; | ||
export declare function createGraphQLClient<TClientOptions extends ClientOptions>({ headers, url, fetchAPI, retries, }: TClientOptions): GraphQLClient; | ||
export declare function createGraphQLClient<TClientOptions extends ClientOptions>({ headers, url, fetchAPI, retries, logger, }: TClientOptions): GraphQLClient; | ||
//# sourceMappingURL=graphql-client.d.ts.map |
@@ -42,3 +42,3 @@ import { getErrorMessage } from "./utilities"; | ||
} | ||
export function createGraphQLClient({ headers, url, fetchAPI = fetch, retries = 0, }) { | ||
export function createGraphQLClient({ headers, url, fetchAPI = fetch, retries = 0, logger, }) { | ||
validateRetries(retries); | ||
@@ -50,6 +50,20 @@ const config = { | ||
}; | ||
const httpFetch = async (params, count, maxTries) => { | ||
const clientLogger = (logContent) => { | ||
if (logger) { | ||
logger(logContent); | ||
} | ||
}; | ||
const httpFetch = async (requestParams, count, maxRetries) => { | ||
const nextCount = count + 1; | ||
const maxTries = maxRetries + 1; | ||
let response; | ||
try { | ||
const response = await fetchAPI(...params); | ||
response = await fetchAPI(...requestParams); | ||
clientLogger({ | ||
type: "HTTP-Response", | ||
content: { | ||
requestParams, | ||
response, | ||
}, | ||
}); | ||
if (!response.ok && | ||
@@ -65,5 +79,16 @@ RETRIABLE_STATUS_CODES.includes(response.status) && | ||
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)}`); | ||
throw new Error(`${ERROR_PREFIX}${maxRetries > 0 | ||
? ` Attempted maximum number of ${maxRetries} network retries. Last message -` | ||
: ""} ${getErrorMessage(error)}`); | ||
} | ||
@@ -89,4 +114,3 @@ }; | ||
]; | ||
const maxTries = (overrideRetries ?? retries) + 1; | ||
return httpFetch(fetchParams, 1, maxTries); | ||
return httpFetch(fetchParams, 1, overrideRetries ?? retries); | ||
}; | ||
@@ -93,0 +117,0 @@ const request = async (...props) => { |
@@ -25,2 +25,24 @@ export type CustomFetchAPI = (url: string, init?: { | ||
} | ||
export type LogType = "HTTP-Response" | "HTTP-Retry"; | ||
export interface LogContent { | ||
type: LogType; | ||
content: any; | ||
} | ||
export interface HTTPResponseLog extends LogContent { | ||
type: "HTTP-Response"; | ||
content: { | ||
requestParams: Parameters<CustomFetchAPI>; | ||
response: Response; | ||
}; | ||
} | ||
export interface HTTPRetryLog extends LogContent { | ||
type: "HTTP-Retry"; | ||
content: { | ||
requestParams: Parameters<CustomFetchAPI>; | ||
lastResponse?: Response; | ||
retryAttempt: number; | ||
maxRetries: number; | ||
}; | ||
} | ||
export type LogContentTypes = HTTPResponseLog | HTTPRetryLog; | ||
export interface ClientOptions { | ||
@@ -31,7 +53,8 @@ headers: Headers; | ||
retries?: number; | ||
logger?: (logContent: LogContentTypes) => void; | ||
} | ||
export interface ClientConfig { | ||
readonly headers: Headers; | ||
readonly url: string; | ||
readonly retries: number; | ||
readonly headers: ClientOptions["headers"]; | ||
readonly url: ClientOptions["url"]; | ||
readonly retries: ClientOptions["retries"]; | ||
} | ||
@@ -38,0 +61,0 @@ export interface RequestOptions { |
@@ -25,2 +25,24 @@ type CustomFetchAPI = (url: string, init?: { | ||
} | ||
type LogType = "HTTP-Response" | "HTTP-Retry"; | ||
interface LogContent { | ||
type: LogType; | ||
content: any; | ||
} | ||
interface HTTPResponseLog extends LogContent { | ||
type: "HTTP-Response"; | ||
content: { | ||
requestParams: Parameters<CustomFetchAPI>; | ||
response: Response; | ||
}; | ||
} | ||
interface HTTPRetryLog extends LogContent { | ||
type: "HTTP-Retry"; | ||
content: { | ||
requestParams: Parameters<CustomFetchAPI>; | ||
lastResponse?: Response; | ||
retryAttempt: number; | ||
maxRetries: number; | ||
}; | ||
} | ||
type LogContentTypes = HTTPResponseLog | HTTPRetryLog; | ||
interface ClientOptions { | ||
@@ -31,7 +53,8 @@ headers: Headers; | ||
retries?: number; | ||
logger?: (logContent: LogContentTypes) => void; | ||
} | ||
interface ClientConfig { | ||
readonly headers: Headers; | ||
readonly url: string; | ||
readonly retries: number; | ||
readonly headers: ClientOptions["headers"]; | ||
readonly url: ClientOptions["url"]; | ||
readonly retries: ClientOptions["retries"]; | ||
} | ||
@@ -51,4 +74,4 @@ interface RequestOptions { | ||
declare function createGraphQLClient<TClientOptions extends ClientOptions>({ headers, url, fetchAPI, retries, }: TClientOptions): GraphQLClient; | ||
declare function createGraphQLClient<TClientOptions extends ClientOptions>({ headers, url, fetchAPI, retries, logger, }: TClientOptions): GraphQLClient; | ||
export { ClientConfig, ClientOptions, ClientResponse, CustomFetchAPI, GQLExtensions, GraphQLClient, Headers, OperationVariables, RequestOptions, RequestParams, ResponseError, createGraphQLClient }; | ||
export { ClientConfig, ClientOptions, ClientResponse, CustomFetchAPI, GQLExtensions, GraphQLClient, HTTPResponseLog, HTTPRetryLog, Headers, LogContent, LogContentTypes, LogType, OperationVariables, RequestOptions, RequestParams, ResponseError, createGraphQLClient }; |
@@ -45,3 +45,3 @@ 'use strict'; | ||
} | ||
function createGraphQLClient({ headers, url, fetchAPI = fetch, retries = 0, }) { | ||
function createGraphQLClient({ headers, url, fetchAPI = fetch, retries = 0, logger, }) { | ||
validateRetries(retries); | ||
@@ -53,6 +53,20 @@ const config = { | ||
}; | ||
const httpFetch = async (params, count, maxTries) => { | ||
const clientLogger = (logContent) => { | ||
if (logger) { | ||
logger(logContent); | ||
} | ||
}; | ||
const httpFetch = async (requestParams, count, maxRetries) => { | ||
const nextCount = count + 1; | ||
const maxTries = maxRetries + 1; | ||
let response; | ||
try { | ||
const response = await fetchAPI(...params); | ||
response = await fetchAPI(...requestParams); | ||
clientLogger({ | ||
type: "HTTP-Response", | ||
content: { | ||
requestParams, | ||
response, | ||
}, | ||
}); | ||
if (!response.ok && | ||
@@ -68,5 +82,16 @@ RETRIABLE_STATUS_CODES.includes(response.status) && | ||
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 - ${utilities.getErrorMessage(error)}`); | ||
throw new Error(`${ERROR_PREFIX}${maxRetries > 0 | ||
? ` Attempted maximum number of ${maxRetries} network retries. Last message -` | ||
: ""} ${utilities.getErrorMessage(error)}`); | ||
} | ||
@@ -92,4 +117,3 @@ }; | ||
]; | ||
const maxTries = (overrideRetries ?? retries) + 1; | ||
return httpFetch(fetchParams, 1, maxTries); | ||
return httpFetch(fetchParams, 1, overrideRetries ?? retries); | ||
}; | ||
@@ -96,0 +120,0 @@ const request = async (...props) => { |
import { ClientOptions, GraphQLClient } from "./types"; | ||
export declare function createGraphQLClient<TClientOptions extends ClientOptions>({ headers, url, fetchAPI, retries, }: TClientOptions): GraphQLClient; | ||
export declare function createGraphQLClient<TClientOptions extends ClientOptions>({ headers, url, fetchAPI, retries, logger, }: TClientOptions): GraphQLClient; | ||
//# sourceMappingURL=graphql-client.d.ts.map |
@@ -25,2 +25,24 @@ export type CustomFetchAPI = (url: string, init?: { | ||
} | ||
export type LogType = "HTTP-Response" | "HTTP-Retry"; | ||
export interface LogContent { | ||
type: LogType; | ||
content: any; | ||
} | ||
export interface HTTPResponseLog extends LogContent { | ||
type: "HTTP-Response"; | ||
content: { | ||
requestParams: Parameters<CustomFetchAPI>; | ||
response: Response; | ||
}; | ||
} | ||
export interface HTTPRetryLog extends LogContent { | ||
type: "HTTP-Retry"; | ||
content: { | ||
requestParams: Parameters<CustomFetchAPI>; | ||
lastResponse?: Response; | ||
retryAttempt: number; | ||
maxRetries: number; | ||
}; | ||
} | ||
export type LogContentTypes = HTTPResponseLog | HTTPRetryLog; | ||
export interface ClientOptions { | ||
@@ -31,7 +53,8 @@ headers: Headers; | ||
retries?: number; | ||
logger?: (logContent: LogContentTypes) => void; | ||
} | ||
export interface ClientConfig { | ||
readonly headers: Headers; | ||
readonly url: string; | ||
readonly retries: number; | ||
readonly headers: ClientOptions["headers"]; | ||
readonly url: ClientOptions["url"]; | ||
readonly retries: ClientOptions["retries"]; | ||
} | ||
@@ -38,0 +61,0 @@ export interface RequestOptions { |
@@ -52,3 +52,3 @@ /*! shopify/graphql-client -- Copyright (c) 2023-present, Shopify Inc. -- license (MIT): https://github.com///github/blob/main/LICENSE */ | ||
} | ||
function createGraphQLClient({ headers, url, fetchAPI = fetch, retries = 0, }) { | ||
function createGraphQLClient({ headers, url, fetchAPI = fetch, retries = 0, logger, }) { | ||
validateRetries(retries); | ||
@@ -60,6 +60,20 @@ const config = { | ||
}; | ||
const httpFetch = async (params, count, maxTries) => { | ||
const clientLogger = (logContent) => { | ||
if (logger) { | ||
logger(logContent); | ||
} | ||
}; | ||
const httpFetch = async (requestParams, count, maxRetries) => { | ||
const nextCount = count + 1; | ||
const maxTries = maxRetries + 1; | ||
let response; | ||
try { | ||
const response = await fetchAPI(...params); | ||
response = await fetchAPI(...requestParams); | ||
clientLogger({ | ||
type: "HTTP-Response", | ||
content: { | ||
requestParams, | ||
response, | ||
}, | ||
}); | ||
if (!response.ok && | ||
@@ -75,5 +89,16 @@ RETRIABLE_STATUS_CODES.includes(response.status) && | ||
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)}`); | ||
throw new Error(`${ERROR_PREFIX}${maxRetries > 0 | ||
? ` Attempted maximum number of ${maxRetries} network retries. Last message -` | ||
: ""} ${getErrorMessage(error)}`); | ||
} | ||
@@ -99,4 +124,3 @@ }; | ||
]; | ||
const maxTries = (overrideRetries ?? retries) + 1; | ||
return httpFetch(fetchParams, 1, maxTries); | ||
return httpFetch(fetchParams, 1, overrideRetries ?? retries); | ||
}; | ||
@@ -103,0 +127,0 @@ const request = async (...props) => { |
/*! shopify/graphql-client -- Copyright (c) 2023-present, Shopify Inc. -- license (MIT): https://github.com///github/blob/main/LICENSE */ | ||
!function(e,r){"object"==typeof exports&&"undefined"!=typeof module?r(exports):"function"==typeof define&&define.amd?define(["exports"],r):r((e="undefined"!=typeof globalThis?globalThis:e||self).ShopifyGraphQLClient={})}(this,(function(e){"use strict";function r(e){return e instanceof Error?e.message:JSON.stringify(e)}const t="GraphQL Client:",n=`${t} An error occurred while fetching from the API. Review 'graphQLErrors' for details.`,s=`${t} Response returned unexpected Content-Type:`,o="application/json",a=0,i=3,c=[429,503];function u(e){if(void 0!==e&&(e<a||e>i))throw new Error(`${t} The provided "retries" value (${e}) is invalid - it cannot be less than ${a} or greater than ${i}`)}e.createGraphQLClient=function({headers:e,url:a,fetchAPI:i=fetch,retries:d=0}){u(d);const f=async(e,n,s)=>{const o=n+1;try{const r=await i(...e);if(!r.ok&&c.includes(r.status)&&o<=s)throw new Error;return r}catch(n){if(o<=s)return await async function(e){return new Promise((r=>setTimeout(r,e)))}(1e3),f(e,o,s);throw new Error(`${t} Exceeded maximum number of ${s} network tries. Last message - ${r(n)}`)}},fetch=async(r,t={})=>{const{variables:n,headers:s,url:o,retries:i}=t,c=JSON.stringify({query:r,variables:n});u(i);const h=[o??a,{method:"POST",headers:{...e,...s},body:c}];return f(h,1,(i??d)+1)};return{config:{headers:e,url:a,retries:d},fetch:fetch,request:async(...e)=>{try{const r=await fetch(...e),{status:a,statusText:i}=r,c=r.headers.get("content-type")||"";return r.ok?c.includes(o)?async function(e){const{errors:r,data:s,extensions:o}=await e.json(),a=o?{extensions:o}:{};return r||!s?{error:{networkStatusCode:e.status,message:r?n:`${t} An unknown error has occurred. The API did not return a data object or any errors in its response.`,...r?{graphQLErrors:r}:{}},...a}:{data:s,...a}}(r):{error:{networkStatusCode:a,message:`${s} ${c}`}}:{error:{networkStatusCode:a,message:i}}}catch(e){return{error:{message:r(e)}}}}}}})); | ||
!function(e,r){"object"==typeof exports&&"undefined"!=typeof module?r(exports):"function"==typeof define&&define.amd?define(["exports"],r):r((e="undefined"!=typeof globalThis?globalThis:e||self).ShopifyGraphQLClient={})}(this,(function(e){"use strict";function r(e){return e instanceof Error?e.message:JSON.stringify(e)}const t="GraphQL Client:",n=`${t} An error occurred while fetching from the API. Review 'graphQLErrors' for details.`,s=`${t} Response returned unexpected Content-Type:`,o="application/json",a=0,i=3,u=[429,503];function c(e){if(void 0!==e&&(e<a||e>i))throw new Error(`${t} The provided "retries" value (${e}) is invalid - it cannot be less than ${a} or greater than ${i}`)}e.createGraphQLClient=function({headers:e,url:a,fetchAPI:i=fetch,retries:d=0,logger:f}){c(d);const h=e=>{f&&f(e)},p=async(e,n,s)=>{const o=n+1,a=s+1;let c;try{if(c=await i(...e),h({type:"HTTP-Response",content:{requestParams:e,response:c}}),!c.ok&&u.includes(c.status)&&o<=a)throw new Error;return c}catch(i){if(o<=a)return await async function(e){return new Promise((r=>setTimeout(r,e)))}(1e3),h({type:"HTTP-Retry",content:{requestParams:e,lastResponse:c,retryAttempt:n,maxRetries:s}}),p(e,o,s);throw new Error(`${t}${s>0?` Attempted maximum number of ${s} network retries. Last message -`:""} ${r(i)}`)}},fetch=async(r,t={})=>{const{variables:n,headers:s,url:o,retries:i}=t,u=JSON.stringify({query:r,variables:n});c(i);const f=[o??a,{method:"POST",headers:{...e,...s},body:u}];return p(f,1,i??d)};return{config:{headers:e,url:a,retries:d},fetch:fetch,request:async(...e)=>{try{const r=await fetch(...e),{status:a,statusText:i}=r,u=r.headers.get("content-type")||"";return r.ok?u.includes(o)?async function(e){const{errors:r,data:s,extensions:o}=await e.json(),a=o?{extensions:o}:{};return r||!s?{error:{networkStatusCode:e.status,message:r?n:`${t} An unknown error has occurred. The API did not return a data object or any errors in its response.`,...r?{graphQLErrors:r}:{}},...a}:{data:s,...a}}(r):{error:{networkStatusCode:a,message:`${s} ${u}`}}:{error:{networkStatusCode:a,message:i}}}catch(e){return{error:{message:r(e)}}}}}}})); | ||
//# sourceMappingURL=graphql-client.min.js.map |
{ | ||
"name": "@shopify/graphql-client", | ||
"version": "0.2.0", | ||
"version": "0.3.0", | ||
"description": "Shopify GraphQL Client - A lightweight generic GraphQL JS client to interact with Shopify GraphQL APIs", | ||
@@ -5,0 +5,0 @@ "repository": { |
# GraphQL Client | ||
The GraphQL Client is a generic GraphQL client that can be used directly to interact with a GraphQL API. Client users are expected to provide the full API URL and necessary headers. | ||
The GraphQL Client can be used to interact with any Shopify's GraphQL APIs. Client users are expected to provide the full API URL and necessary headers. | ||
@@ -27,2 +27,4 @@ ## Initialization | ||
| 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. | | ||
@@ -184,1 +186,28 @@ ## Client properties | ||
``` | ||
## 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)`: [url, init?], response: Response}` | Contextual data regarding the request and 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)`: [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 | | ||
### `RequestParams` | ||
| Property | Type | Description | | ||
| -------- | ------------------------ | ---------------------------------- | | ||
| url | `string` | Requested URL | | ||
| init? | `{method?: string, headers?: HeaderInit, body?: string}` | The request information | |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
73361
866
212