core-go/client/graphql.go

97 lines
2.1 KiB
Go

package client
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"git.sr.ht/~sircmpwn/core-go/config"
"git.sr.ht/~sircmpwn/core-go/crypto"
"github.com/vektah/gqlparser/v2/gqlerror"
)
type GraphQLQuery struct {
Query string `json:"query"`
Variables map[string]interface{} `json:"variables"`
}
type InternalAuth struct {
Name string `json:"name"`
ClientID string `json:"client_id"`
NodeID string `json:"node_id"`
}
func Do(ctx context.Context, username string, svc string,
query GraphQLQuery, result interface{}) error {
body, err := json.Marshal(query)
if err != nil {
panic(err) // Programmer error
}
conf := config.ForContext(ctx)
origin, _ := conf.Get(svc, "api-origin")
if origin == "" {
origin = config.GetOrigin(conf, svc, false)
}
if origin == "" {
panic(fmt.Errorf("No %s origin specified in config.ini", svc))
}
reader := bytes.NewBuffer(body)
req, err := http.NewRequestWithContext(ctx,
"POST", fmt.Sprintf("%s/query", origin), reader)
if err != nil {
return err
}
req.Header.Add("Content-Type", "application/json")
auth := InternalAuth{
Name: username,
ClientID: config.ServiceName(ctx),
// TODO: Populate this:
NodeID: "core-go",
}
authBlob, err := json.Marshal(&auth)
if err != nil {
panic(err) // Programmer error
}
req.Header.Add("Authorization", fmt.Sprintf("Internal %s",
crypto.Encrypt(authBlob)))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
if resp.StatusCode != 200 {
return fmt.Errorf("%s returned status %d: %s",
svc, resp.StatusCode, string(respBody))
}
var respData struct {
Data interface{} `json:"data"`
Errors gqlerror.List `json:"errors"`
}
respData.Data = result
if err := json.Unmarshal(respBody, &respData); err != nil {
return fmt.Errorf("failed to parse GraphQL response: %v", err)
}
if len(respData.Errors) == 1 {
return respData.Errors[0]
} else if len(respData.Errors) > 1 {
return respData.Errors
}
return nil
}