package httpclient import ( "bytes" "context" "encoding/json" "fmt" "net/http" ) type GraphQLRequest struct { Query string `json:"query"` Variables any `json:"variables,omitempty"` } type graphQLResponse[T any] struct { Data T `json:"data"` Errors []struct { Message string `json:"message"` } `json:"errors"` } // Post sends a GraphQL request and unmarshals the `data` field into T. func Post[T any](ctx context.Context, client *http.Client, url string, req GraphQLRequest, headers map[string]string) (T, error) { var zero T body, err := json.Marshal(req) if err != nil { return zero, err } httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body)) if err != nil { return zero, err } httpReq.Header.Set("Content-Type", "application/json") httpReq.Header.Set("Accept", "application/json") for k, v := range headers { httpReq.Header.Set(k, v) } resp, err := client.Do(httpReq) if err != nil { return zero, err } defer resp.Body.Close() var gqlResp graphQLResponse[T] if err := json.NewDecoder(resp.Body).Decode(&gqlResp); err != nil { return zero, err } if len(gqlResp.Errors) > 0 { return zero, fmt.Errorf("graphql: %s", gqlResp.Errors[0].Message) } return gqlResp.Data, nil }