@@ -47,61 +47,61 @@ func NewClient(url string, httpClient Doer) *Client {
47
47
// Query executes a single GraphQL query request,
48
48
// with a query derived from q, populating the response into it.
49
49
// q should be a pointer to struct that corresponds to the GraphQL schema.
50
- func (c * Client ) Query (ctx context.Context , q interface {} , variables map [string ]interface {} , options ... Option ) error {
50
+ func (c * Client ) Query (ctx context.Context , q any , variables map [string ]any , options ... Option ) error {
51
51
return c .do (ctx , queryOperation , q , variables , options ... )
52
52
}
53
53
54
54
// NamedQuery executes a single GraphQL query request, with operation name
55
55
//
56
56
// Deprecated: this is the shortcut of Query method, with NewOperationName option
57
- func (c * Client ) NamedQuery (ctx context.Context , name string , q interface {} , variables map [string ]interface {} , options ... Option ) error {
57
+ func (c * Client ) NamedQuery (ctx context.Context , name string , q any , variables map [string ]any , options ... Option ) error {
58
58
return c .do (ctx , queryOperation , q , variables , append (options , OperationName (name ))... )
59
59
}
60
60
61
61
// Mutate executes a single GraphQL mutation request,
62
62
// with a mutation derived from m, populating the response into it.
63
63
// m should be a pointer to struct that corresponds to the GraphQL schema.
64
- func (c * Client ) Mutate (ctx context.Context , m interface {} , variables map [string ]interface {} , options ... Option ) error {
64
+ func (c * Client ) Mutate (ctx context.Context , m any , variables map [string ]any , options ... Option ) error {
65
65
return c .do (ctx , mutationOperation , m , variables , options ... )
66
66
}
67
67
68
68
// NamedMutate executes a single GraphQL mutation request, with operation name
69
69
//
70
70
// Deprecated: this is the shortcut of Mutate method, with NewOperationName option
71
- func (c * Client ) NamedMutate (ctx context.Context , name string , m interface {} , variables map [string ]interface {} , options ... Option ) error {
71
+ func (c * Client ) NamedMutate (ctx context.Context , name string , m any , variables map [string ]any , options ... Option ) error {
72
72
return c .do (ctx , mutationOperation , m , variables , append (options , OperationName (name ))... )
73
73
}
74
74
75
75
// Query executes a single GraphQL query request,
76
76
// with a query derived from q, populating the response into it.
77
77
// q should be a pointer to struct that corresponds to the GraphQL schema.
78
78
// return raw bytes message.
79
- func (c * Client ) QueryRaw (ctx context.Context , q interface {} , variables map [string ]interface {} , options ... Option ) ([]byte , error ) {
79
+ func (c * Client ) QueryRaw (ctx context.Context , q any , variables map [string ]any , options ... Option ) ([]byte , error ) {
80
80
return c .doRaw (ctx , queryOperation , q , variables , options ... )
81
81
}
82
82
83
83
// NamedQueryRaw executes a single GraphQL query request, with operation name
84
84
// return raw bytes message.
85
- func (c * Client ) NamedQueryRaw (ctx context.Context , name string , q interface {} , variables map [string ]interface {} , options ... Option ) ([]byte , error ) {
85
+ func (c * Client ) NamedQueryRaw (ctx context.Context , name string , q any , variables map [string ]any , options ... Option ) ([]byte , error ) {
86
86
return c .doRaw (ctx , queryOperation , q , variables , append (options , OperationName (name ))... )
87
87
}
88
88
89
89
// MutateRaw executes a single GraphQL mutation request,
90
90
// with a mutation derived from m, populating the response into it.
91
91
// m should be a pointer to struct that corresponds to the GraphQL schema.
92
92
// return raw bytes message.
93
- func (c * Client ) MutateRaw (ctx context.Context , m interface {} , variables map [string ]interface {} , options ... Option ) ([]byte , error ) {
93
+ func (c * Client ) MutateRaw (ctx context.Context , m any , variables map [string ]any , options ... Option ) ([]byte , error ) {
94
94
return c .doRaw (ctx , mutationOperation , m , variables , options ... )
95
95
}
96
96
97
97
// NamedMutateRaw executes a single GraphQL mutation request, with operation name
98
98
// return raw bytes message.
99
- func (c * Client ) NamedMutateRaw (ctx context.Context , name string , m interface {} , variables map [string ]interface {} , options ... Option ) ([]byte , error ) {
99
+ func (c * Client ) NamedMutateRaw (ctx context.Context , name string , m any , variables map [string ]any , options ... Option ) ([]byte , error ) {
100
100
return c .doRaw (ctx , mutationOperation , m , variables , append (options , OperationName (name ))... )
101
101
}
102
102
103
- // buildAndRequest the common method that builds and send graphql request
104
- func (c * Client ) buildAndRequest ( ctx context. Context , op operationType , v interface {} , variables map [string ]interface {} , options ... Option ) ([] byte , * http. Response , io. Reader , Errors ) {
103
+ // buildQueryAndOptions the common method to build query and options
104
+ func (c * Client ) buildQueryAndOptions ( op operationType , v any , variables map [string ]any , options ... Option ) (string , * constructOptionsOutput , error ) {
105
105
var query string
106
106
var err error
107
107
var optionOutput * constructOptionsOutput
@@ -110,18 +110,18 @@ func (c *Client) buildAndRequest(ctx context.Context, op operationType, v interf
110
110
query , optionOutput , err = constructQuery (v , variables , options ... )
111
111
case mutationOperation :
112
112
query , optionOutput , err = constructMutation (v , variables , options ... )
113
+ default :
114
+ err = fmt .Errorf ("invalid operation type: %v" , op )
113
115
}
114
116
115
117
if err != nil {
116
- return nil , nil , nil , Errors {newError (ErrGraphQLEncode , err )}
118
+ return "" , nil , Errors {newError (ErrGraphQLEncode , err )}
117
119
}
118
-
119
- data , _ , resp , respBuf , errs := c .request (ctx , query , variables , optionOutput )
120
- return data , resp , respBuf , errs
120
+ return query , optionOutput , nil
121
121
}
122
122
123
123
// Request the common method that send graphql request
124
- func (c * Client ) request (ctx context.Context , query string , variables map [string ]interface {} , options * constructOptionsOutput ) ([]byte , []byte , * http.Response , io.Reader , Errors ) {
124
+ func (c * Client ) request (ctx context.Context , query string , variables map [string ]any , options * constructOptionsOutput ) ([]byte , []byte , * http.Response , io.Reader , Errors ) {
125
125
in := GraphQLRequestPayload {
126
126
Query : query ,
127
127
Variables : variables ,
@@ -248,35 +248,45 @@ func (c *Client) request(ctx context.Context, query string, variables map[string
248
248
249
249
// do executes a single GraphQL operation.
250
250
// return raw message and error
251
- func (c * Client ) doRaw (ctx context.Context , op operationType , v interface {}, variables map [string ]interface {}, options ... Option ) ([]byte , error ) {
252
- data , _ , _ , err := c .buildAndRequest (ctx , op , v , variables , options ... )
253
- if len (err ) > 0 {
254
- return data , err
251
+ func (c * Client ) doRaw (ctx context.Context , op operationType , v any , variables map [string ]any , options ... Option ) ([]byte , error ) {
252
+ query , optionsOutput , err := c .buildQueryAndOptions (op , v , variables , options ... )
253
+ if err != nil {
254
+ return nil , err
255
+ }
256
+ data , _ , _ , _ , errs := c .request (ctx , query , variables , optionsOutput )
257
+ if len (errs ) > 0 {
258
+ return data , errs
255
259
}
260
+
256
261
return data , nil
257
262
}
258
263
259
264
// do executes a single GraphQL operation and unmarshal json.
260
- func (c * Client ) do (ctx context.Context , op operationType , v interface {}, variables map [string ]interface {}, options ... Option ) error {
261
- data , resp , respBuf , errs := c .buildAndRequest (ctx , op , v , variables , options ... )
262
- return c .processResponse (v , data , resp , respBuf , errs )
265
+ func (c * Client ) do (ctx context.Context , op operationType , v any , variables map [string ]any , options ... Option ) error {
266
+ query , optionsOutput , err := c .buildQueryAndOptions (op , v , variables , options ... )
267
+ if err != nil {
268
+ return err
269
+ }
270
+ data , extData , resp , respBuf , errs := c .request (ctx , query , variables , optionsOutput )
271
+
272
+ return c .processResponse (v , data , optionsOutput .extensions , extData , resp , respBuf , errs )
263
273
}
264
274
265
275
// Executes a pre-built query and unmarshals the response into v. Unlike the Query method you have to specify in the query the
266
276
// fields that you want to receive as they are not inferred from v. This method is useful if you need to build the query dynamically.
267
- func (c * Client ) Exec (ctx context.Context , query string , v interface {} , variables map [string ]interface {} , options ... Option ) error {
277
+ func (c * Client ) Exec (ctx context.Context , query string , v any , variables map [string ]any , options ... Option ) error {
268
278
optionsOutput , err := constructOptions (options )
269
279
if err != nil {
270
280
return err
271
281
}
272
282
273
- data , _ , resp , respBuf , errs := c .request (ctx , query , variables , optionsOutput )
274
- return c .processResponse (v , data , resp , respBuf , errs )
283
+ data , extData , resp , respBuf , errs := c .request (ctx , query , variables , optionsOutput )
284
+ return c .processResponse (v , data , optionsOutput . extensions , extData , resp , respBuf , errs )
275
285
}
276
286
277
287
// Executes a pre-built query and returns the raw json message. Unlike the Query method you have to specify in the query the
278
288
// fields that you want to receive as they are not inferred from the interface. This method is useful if you need to build the query dynamically.
279
- func (c * Client ) ExecRaw (ctx context.Context , query string , variables map [string ]interface {} , options ... Option ) ([]byte , error ) {
289
+ func (c * Client ) ExecRaw (ctx context.Context , query string , variables map [string ]any , options ... Option ) ([]byte , error ) {
280
290
optionsOutput , err := constructOptions (options )
281
291
if err != nil {
282
292
return nil , err
@@ -289,10 +299,10 @@ func (c *Client) ExecRaw(ctx context.Context, query string, variables map[string
289
299
return data , nil
290
300
}
291
301
292
- // Executes a pre-built query and returns the raw json message and a map with extensions (values also as raw json objects). Unlike the
302
+ // ExecRawWithExtensions execute a pre-built query and returns the raw json message and a map with extensions (values also as raw json objects). Unlike the
293
303
// Query method you have to specify in the query the fields that you want to receive as they are not inferred from the interface. This method
294
304
// is useful if you need to build the query dynamically.
295
- func (c * Client ) ExecRawWithExtensions (ctx context.Context , query string , variables map [string ]interface {} , options ... Option ) ([]byte , []byte , error ) {
305
+ func (c * Client ) ExecRawWithExtensions (ctx context.Context , query string , variables map [string ]any , options ... Option ) ([]byte , []byte , error ) {
296
306
optionsOutput , err := constructOptions (options )
297
307
if err != nil {
298
308
return nil , nil , err
@@ -305,7 +315,7 @@ func (c *Client) ExecRawWithExtensions(ctx context.Context, query string, variab
305
315
return data , ext , nil
306
316
}
307
317
308
- func (c * Client ) processResponse (v interface {} , data []byte , resp * http.Response , respBuf io.Reader , errs Errors ) error {
318
+ func (c * Client ) processResponse (v any , data [] byte , extensions any , rawExtensions []byte , resp * http.Response , respBuf io.Reader , errs Errors ) error {
309
319
if len (data ) > 0 {
310
320
err := jsonutil .UnmarshalGraphQL (data , v )
311
321
if err != nil {
@@ -317,6 +327,14 @@ func (c *Client) processResponse(v interface{}, data []byte, resp *http.Response
317
327
}
318
328
}
319
329
330
+ if len (rawExtensions ) > 0 && extensions != nil {
331
+ err := json .Unmarshal (rawExtensions , extensions )
332
+ if err != nil {
333
+ we := newError (ErrGraphQLExtensionsDecode , err )
334
+ errs = append (errs , we )
335
+ }
336
+ }
337
+
320
338
if len (errs ) > 0 {
321
339
return errs
322
340
}
@@ -352,13 +370,13 @@ func (c *Client) WithDebug(debug bool) *Client {
352
370
type Errors []Error
353
371
354
372
type Error struct {
355
- Message string `json:"message"`
356
- Extensions map [string ]interface {} `json:"extensions"`
373
+ Message string `json:"message"`
374
+ Extensions map [string ]any `json:"extensions"`
357
375
Locations []struct {
358
376
Line int `json:"line"`
359
377
Column int `json:"column"`
360
378
} `json:"locations"`
361
- Path []interface {} `json:"path"`
379
+ Path []any `json:"path"`
362
380
err error
363
381
}
364
382
@@ -390,22 +408,22 @@ func (e Errors) Unwrap() []error {
390
408
return errs
391
409
}
392
410
393
- func (e Error ) getInternalExtension () map [string ]interface {} {
411
+ func (e Error ) getInternalExtension () map [string ]any {
394
412
if e .Extensions == nil {
395
- return make (map [string ]interface {} )
413
+ return make (map [string ]any )
396
414
}
397
415
398
416
if ex , ok := e .Extensions ["internal" ]; ok {
399
- return ex .(map [string ]interface {} )
417
+ return ex .(map [string ]any )
400
418
}
401
419
402
- return make (map [string ]interface {} )
420
+ return make (map [string ]any )
403
421
}
404
422
405
423
func newError (code string , err error ) Error {
406
424
return Error {
407
425
Message : err .Error (),
408
- Extensions : map [string ]interface {} {
426
+ Extensions : map [string ]any {
409
427
"code" : code ,
410
428
},
411
429
err : err ,
@@ -435,31 +453,35 @@ func (e Error) withRequest(req *http.Request, bodyReader io.Reader) Error {
435
453
if err != nil {
436
454
internal ["error" ] = err
437
455
} else {
438
- internal ["request" ] = map [string ]interface {} {
456
+ internal ["request" ] = map [string ]any {
439
457
"headers" : req .Header ,
440
458
"body" : string (bodyBytes ),
441
459
}
442
460
}
443
461
444
462
if e .Extensions == nil {
445
- e .Extensions = make (map [string ]interface {} )
463
+ e .Extensions = make (map [string ]any )
446
464
}
447
465
e .Extensions ["internal" ] = internal
448
466
return e
449
467
}
450
468
451
469
func (e Error ) withResponse (res * http.Response , bodyReader io.Reader ) Error {
452
470
internal := e .getInternalExtension ()
453
- bodyBytes , err := io .ReadAll (bodyReader )
454
- if err != nil {
455
- internal ["error" ] = err
456
- } else {
457
- internal ["response" ] = map [string ]interface {}{
458
- "headers" : res .Header ,
459
- "body" : string (bodyBytes ),
460
- }
471
+
472
+ response := map [string ]any {
473
+ "headers" : res .Header ,
461
474
}
462
475
476
+ if bodyReader != nil {
477
+ bodyBytes , err := io .ReadAll (bodyReader )
478
+ if err != nil {
479
+ internal ["error" ] = err
480
+ } else {
481
+ response ["body" ] = string (bodyBytes )
482
+ }
483
+ }
484
+ internal ["response" ] = response
463
485
e .Extensions ["internal" ] = internal
464
486
return e
465
487
}
@@ -470,7 +492,7 @@ func (e Error) withResponse(res *http.Response, bodyReader io.Reader) Error {
470
492
// The implementation is created on top of the JSON tokenizer available
471
493
// in "encoding/json".Decoder.
472
494
// This function is re-exported from the internal package
473
- func UnmarshalGraphQL (data []byte , v interface {} ) error {
495
+ func UnmarshalGraphQL (data []byte , v any ) error {
474
496
return jsonutil .UnmarshalGraphQL (data , v )
475
497
}
476
498
@@ -481,9 +503,10 @@ const (
481
503
mutationOperation
482
504
// subscriptionOperation // Unused.
483
505
484
- ErrRequestError = "request_error"
485
- ErrJsonEncode = "json_encode_error"
486
- ErrJsonDecode = "json_decode_error"
487
- ErrGraphQLEncode = "graphql_encode_error"
488
- ErrGraphQLDecode = "graphql_decode_error"
506
+ ErrRequestError = "request_error"
507
+ ErrJsonEncode = "json_encode_error"
508
+ ErrJsonDecode = "json_decode_error"
509
+ ErrGraphQLEncode = "graphql_encode_error"
510
+ ErrGraphQLDecode = "graphql_decode_error"
511
+ ErrGraphQLExtensionsDecode = "graphql_extensions_decode_error"
489
512
)
0 commit comments