1 | import type { TypedDocumentNode } from '@graphql-typed-document-node/core'
|
2 | import { callOrIdentity, HeadersInitToPlainObject } from '../../lib/prelude.js'
|
3 | import type { BatchRequestDocument, BatchRequestsOptions, BatchResult } from '../functions/batchRequests.js'
|
4 | import { parseBatchRequestArgs } from '../functions/batchRequests.js'
|
5 | import { parseRawRequestArgs } from '../functions/rawRequest.js'
|
6 | import { parseRequestArgs } from '../functions/request.js'
|
7 | import { analyzeDocument } from '../helpers/analyzeDocument.js'
|
8 | import { runRequest } from '../helpers/runRequest.js'
|
9 | import type { RequestDocument, RequestOptions, VariablesAndRequestHeadersArgs } from '../helpers/types.js'
|
10 | import {
|
11 | type GraphQLClientResponse,
|
12 | type RawRequestOptions,
|
13 | type RequestConfig,
|
14 | type Variables,
|
15 | } from '../helpers/types.js'
|
16 |
|
17 |
|
18 |
|
19 |
|
20 | export class GraphQLClient {
|
21 | constructor(
|
22 | private url: string,
|
23 | public readonly requestConfig: RequestConfig = {},
|
24 | ) {}
|
25 |
|
26 | |
27 |
|
28 |
|
29 | rawRequest: RawRequestMethod = async <
|
30 | T,
|
31 | $Variables extends Variables = Variables,
|
32 | >(
|
33 | ...args: RawRequestMethodArgs<$Variables>
|
34 | ): Promise<GraphQLClientResponse<T>> => {
|
35 | const [queryOrOptions, variables, requestHeaders] = args
|
36 | const rawRequestOptions = parseRawRequestArgs<$Variables>(
|
37 | queryOrOptions,
|
38 | variables,
|
39 | requestHeaders,
|
40 | )
|
41 | const {
|
42 | headers,
|
43 | fetch = globalThis.fetch,
|
44 | method = `POST`,
|
45 | requestMiddleware,
|
46 | responseMiddleware,
|
47 | excludeOperationName,
|
48 | ...fetchOptions
|
49 | } = this.requestConfig
|
50 | const { url } = this
|
51 | if (rawRequestOptions.signal !== undefined) {
|
52 | fetchOptions.signal = rawRequestOptions.signal
|
53 | }
|
54 |
|
55 | const document = analyzeDocument(
|
56 | rawRequestOptions.query,
|
57 | excludeOperationName,
|
58 | )
|
59 |
|
60 | const response = await runRequest({
|
61 | url,
|
62 | request: {
|
63 | _tag: `Single`,
|
64 | document,
|
65 | variables: rawRequestOptions.variables,
|
66 | },
|
67 | headers: {
|
68 | ...HeadersInitToPlainObject(callOrIdentity(headers)),
|
69 | ...HeadersInitToPlainObject(rawRequestOptions.requestHeaders),
|
70 | },
|
71 | fetch,
|
72 | method,
|
73 | fetchOptions,
|
74 | middleware: requestMiddleware,
|
75 | })
|
76 |
|
77 | if (responseMiddleware) {
|
78 | await responseMiddleware(response, {
|
79 | operationName: document.operationName,
|
80 | variables,
|
81 | url: this.url,
|
82 | })
|
83 | }
|
84 |
|
85 | if (response instanceof Error) {
|
86 | throw response
|
87 | }
|
88 |
|
89 | return response
|
90 | }
|
91 |
|
92 | |
93 |
|
94 |
|
95 |
|
96 | async request<T, V extends Variables = Variables>(document: RequestDocument | TypedDocumentNode<T, V>, ...variablesAndRequestHeaders: VariablesAndRequestHeadersArgs<V>): Promise<T>
|
97 | async request<T, V extends Variables = Variables>(options: RequestOptions<V, T>): Promise<T>
|
98 | async request<T, V extends Variables = Variables>(
|
99 | documentOrOptions:
|
100 | | RequestDocument
|
101 | | TypedDocumentNode<T, V>
|
102 | | RequestOptions<V>,
|
103 | ...variablesAndRequestHeaders: VariablesAndRequestHeadersArgs<V>
|
104 | ): Promise<T> {
|
105 | const [variables, requestHeaders] = variablesAndRequestHeaders
|
106 | const requestOptions = parseRequestArgs(
|
107 | documentOrOptions,
|
108 | variables,
|
109 | requestHeaders,
|
110 | )
|
111 |
|
112 | const {
|
113 | headers,
|
114 | fetch = globalThis.fetch,
|
115 | method = `POST`,
|
116 | requestMiddleware,
|
117 | responseMiddleware,
|
118 | excludeOperationName,
|
119 | ...fetchOptions
|
120 | } = this.requestConfig
|
121 | const { url } = this
|
122 | if (requestOptions.signal !== undefined) {
|
123 | fetchOptions.signal = requestOptions.signal
|
124 | }
|
125 |
|
126 | const analyzedDocument = analyzeDocument(
|
127 | requestOptions.document,
|
128 | excludeOperationName,
|
129 | )
|
130 |
|
131 | const response = await runRequest({
|
132 | url,
|
133 | request: {
|
134 | _tag: `Single`,
|
135 | document: analyzedDocument,
|
136 | variables: requestOptions.variables,
|
137 | },
|
138 | headers: {
|
139 | ...HeadersInitToPlainObject(callOrIdentity(headers)),
|
140 | ...HeadersInitToPlainObject(requestOptions.requestHeaders),
|
141 | },
|
142 | fetch,
|
143 | method,
|
144 | fetchOptions,
|
145 | middleware: requestMiddleware,
|
146 | })
|
147 |
|
148 | if (responseMiddleware) {
|
149 | await responseMiddleware(response, {
|
150 | operationName: analyzedDocument.operationName,
|
151 | variables: requestOptions.variables,
|
152 | url: this.url,
|
153 | })
|
154 | }
|
155 |
|
156 | if (response instanceof Error) {
|
157 | throw response
|
158 | }
|
159 |
|
160 | return response.data
|
161 | }
|
162 |
|
163 | |
164 |
|
165 |
|
166 | async batchRequests<
|
167 | $BatchResult extends BatchResult,
|
168 | $Variables extends Variables = Variables,
|
169 | >(
|
170 | documents: BatchRequestDocument<$Variables>[],
|
171 | requestHeaders?: HeadersInit,
|
172 | ): Promise<$BatchResult>
|
173 | async batchRequests<
|
174 | $BatchResult extends BatchResult,
|
175 | $Variables extends Variables = Variables,
|
176 | >(options: BatchRequestsOptions<$Variables>): Promise<$BatchResult>
|
177 | async batchRequests<
|
178 | $BatchResult extends BatchResult,
|
179 | $Variables extends Variables = Variables,
|
180 | >(
|
181 | documentsOrOptions:
|
182 | | BatchRequestDocument<$Variables>[]
|
183 | | BatchRequestsOptions<$Variables>,
|
184 | requestHeaders?: HeadersInit,
|
185 | ): Promise<$BatchResult> {
|
186 | const batchRequestOptions = parseBatchRequestArgs<$Variables>(
|
187 | documentsOrOptions,
|
188 | requestHeaders,
|
189 | )
|
190 | const { headers, excludeOperationName, ...fetchOptions } = this.requestConfig
|
191 |
|
192 | if (batchRequestOptions.signal !== undefined) {
|
193 | fetchOptions.signal = batchRequestOptions.signal
|
194 | }
|
195 |
|
196 | const analyzedDocuments = batchRequestOptions.documents.map(
|
197 | ({ document }) => analyzeDocument(document, excludeOperationName),
|
198 | )
|
199 | const expressions = analyzedDocuments.map(({ expression }) => expression)
|
200 | const hasMutations = analyzedDocuments.some(({ isMutation }) => isMutation)
|
201 | const variables = batchRequestOptions.documents.map(
|
202 | ({ variables }) => variables,
|
203 | )
|
204 |
|
205 | const response = await runRequest({
|
206 | url: this.url,
|
207 | request: {
|
208 | _tag: `Batch`,
|
209 | operationName: undefined,
|
210 | query: expressions,
|
211 | hasMutations,
|
212 | variables,
|
213 | },
|
214 | headers: {
|
215 | ...HeadersInitToPlainObject(callOrIdentity(headers)),
|
216 | ...HeadersInitToPlainObject(batchRequestOptions.requestHeaders),
|
217 | },
|
218 | fetch: this.requestConfig.fetch ?? globalThis.fetch,
|
219 | method: this.requestConfig.method || `POST`,
|
220 | fetchOptions,
|
221 | middleware: this.requestConfig.requestMiddleware,
|
222 | })
|
223 |
|
224 | if (this.requestConfig.responseMiddleware) {
|
225 | await this.requestConfig.responseMiddleware(response, {
|
226 | operationName: undefined,
|
227 | variables,
|
228 | url: this.url,
|
229 | })
|
230 | }
|
231 |
|
232 | if (response instanceof Error) {
|
233 | throw response
|
234 | }
|
235 |
|
236 | return response.data
|
237 | }
|
238 |
|
239 | setHeaders(headers: HeadersInit): this {
|
240 | this.requestConfig.headers = headers
|
241 | return this
|
242 | }
|
243 |
|
244 | |
245 |
|
246 |
|
247 | setHeader(key: string, value: string): this {
|
248 | const { headers } = this.requestConfig
|
249 |
|
250 | if (headers) {
|
251 |
|
252 |
|
253 | headers[key] = value
|
254 | } else {
|
255 | this.requestConfig.headers = { [key]: value }
|
256 | }
|
257 |
|
258 | return this
|
259 | }
|
260 |
|
261 | |
262 |
|
263 |
|
264 | setEndpoint(value: string): this {
|
265 | this.url = value
|
266 | return this
|
267 | }
|
268 | }
|
269 |
|
270 | interface RawRequestMethod {
|
271 | <T, V extends Variables = Variables>(
|
272 | query: string,
|
273 | variables?: V,
|
274 | requestHeaders?: HeadersInit,
|
275 | ): Promise<GraphQLClientResponse<T>>
|
276 | <T, V extends Variables = Variables>(options: RawRequestOptions<V>): Promise<
|
277 | GraphQLClientResponse<T>
|
278 | >
|
279 | }
|
280 |
|
281 | type RawRequestMethodArgs<V extends Variables> =
|
282 | | [query: string, variables?: V, requestHeaders?: HeadersInit]
|
283 | | [RawRequestOptions<V>]
|