diff --git a/src/AwesomeGraphQLClient.ts b/src/AwesomeGraphQLClient.ts index 48b09a3..1272292 100644 --- a/src/AwesomeGraphQLClient.ts +++ b/src/AwesomeGraphQLClient.ts @@ -8,14 +8,16 @@ import assert from './util/assert' import formatGetRequestUrl from './util/formatGetRequestUrl' import isExtractableFileEnhanced from './util/isExtractableFileEnhanced' import isResponseJSON from './util/isResponseJSON' +import { RequestResult } from './util/types' export default class AwesomeGraphQLClient< TQuery = string, - FetchOptions extends { [key: string]: any } = RequestInit + TFetchOptions extends { [key: string]: any } = RequestInit, + TRequestResult extends RequestResult = Response > { private endpoint: string - private fetch: (url: string, options?: FetchOptions) => Promise - private fetchOptions?: FetchOptions + private fetch: (url: string, options?: TFetchOptions) => Promise + private fetchOptions?: TFetchOptions private formatQuery?: (query: TQuery) => string private FormData: any @@ -23,11 +25,11 @@ export default class AwesomeGraphQLClient< /** GraphQL endpoint */ endpoint: string /** Fetch polyfill if necessary */ - fetch?: (url: string, options?: any) => Promise + fetch?: (url: string, options?: any) => Promise /** FormData polyfill if necessary */ FormData?: any /** Overrides for fetch options */ - fetchOptions?: FetchOptions + fetchOptions?: TFetchOptions /** Custom query formatter */ formatQuery?: (query: TQuery) => string }) { @@ -39,7 +41,7 @@ export default class AwesomeGraphQLClient< ) this.endpoint = config.endpoint - this.fetch = config.fetch || fetch.bind(null) + this.fetch = config.fetch || (fetch.bind(null) as any) this.fetchOptions = config.fetchOptions this.FormData = @@ -89,14 +91,14 @@ export default class AwesomeGraphQLClient< * * @param fetchOptions new overrides for fetch options */ - setFetchOptions(fetchOptions: FetchOptions): void { + setFetchOptions(fetchOptions: TFetchOptions): void { this.fetchOptions = fetchOptions } /** * Returns current overrides for fetch options */ - getFetchOptions(): FetchOptions | undefined { + getFetchOptions(): TFetchOptions | undefined { return this.fetchOptions } @@ -119,9 +121,10 @@ export default class AwesomeGraphQLClient< async requestSafe( query: TQuery, variables?: TVariables, - fetchOptions?: FetchOptions, + fetchOptions?: TFetchOptions, ): Promise< - { data: TData; response: Response } | { error: GraphQLRequestError | Error } + | { data: TData; response: TRequestResult } + | { error: GraphQLRequestError | Error } > { try { const queryAsString = this.formatQuery ? this.formatQuery(query) : query @@ -141,7 +144,7 @@ export default class AwesomeGraphQLClient< }, } - let response: Response + let response: TRequestResult | Response if (options.method.toUpperCase() === 'GET') { const url = formatGetRequestUrl({ @@ -149,7 +152,7 @@ export default class AwesomeGraphQLClient< query: queryAsString, variables, }) - response = await this.fetch(url, (options as unknown) as FetchOptions) + response = await this.fetch(url, (options as unknown) as TFetchOptions) } else { const body = this.createRequestBody(queryAsString, variables) @@ -160,11 +163,11 @@ export default class AwesomeGraphQLClient< typeof body === 'string' ? { ...options.headers, 'Content-Type': 'application/json' } : options.headers, - } as unknown) as FetchOptions) + } as unknown) as TFetchOptions) } if (!response.ok) { - if (isResponseJSON(response)) { + if (isResponseJSON(response as any)) { const { errors } = await response.json() if (errors?.[0]?.message) { @@ -215,7 +218,7 @@ export default class AwesomeGraphQLClient< async request( query: TQuery, variables?: TVariables, - fetchOptions?: FetchOptions, + fetchOptions?: TFetchOptions, ): Promise { const result = await this.requestSafe( query, diff --git a/src/GraphQLRequestError.ts b/src/GraphQLRequestError.ts index ff79986..36031b3 100644 --- a/src/GraphQLRequestError.ts +++ b/src/GraphQLRequestError.ts @@ -1,16 +1,23 @@ -interface GraphQLRequestErrorOptions { - query: string - variables?: Record - response: Response - message: string -} +import { RequestResult } from './util/types' -export default class GraphQLRequestError extends Error { +export default class GraphQLRequestError< + TResponse extends RequestResult = Response +> extends Error { query: string variables?: Record - response: Response + response: TResponse - constructor({ query, variables, response, message }: GraphQLRequestErrorOptions) { + constructor({ + query, + variables, + response, + message, + }: { + query: string + variables?: Record + response: TResponse + message: string + }) { super(`GraphQL Request Error: ${message}`) this.query = query diff --git a/src/util/isResponseJSON.ts b/src/util/isResponseJSON.ts index d440b78..899e8d1 100644 --- a/src/util/isResponseJSON.ts +++ b/src/util/isResponseJSON.ts @@ -1,4 +1,6 @@ -const isResponseJSON = (response: Response): boolean => +import { RequestResult } from './types' + +const isResponseJSON = (response: { headers: RequestResult['headers'] }): boolean => (response.headers.get('Content-Type') || '').includes('application/json') export default isResponseJSON diff --git a/src/util/types.ts b/src/util/types.ts new file mode 100644 index 0000000..60cd8f2 --- /dev/null +++ b/src/util/types.ts @@ -0,0 +1,10 @@ +interface Headers { + get(name: string): string | null +} + +export interface RequestResult { + ok: boolean + headers: Headers + json: () => Promise + status: number +}