machinebox / graphql Goto Github PK
View Code? Open in Web Editor NEWSimple low-level GraphQL HTTP client for Go
Home Page: https://blog.machinebox.io/a-graphql-client-library-for-go-5bffd0455878
License: Apache License 2.0
Simple low-level GraphQL HTTP client for Go
Home Page: https://blog.machinebox.io/a-graphql-client-library-for-go-5bffd0455878
License: Apache License 2.0
when execute below query in thegraph for uniswap online explorer
all of them have result
but when invoke it from program, only first query (tokenDaydata query) have result, the second & thrid failed parse
program api endpoint: https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2
program code: https://github.com/huahuayu/graphql commitId: 1c05c8d0ac16f934d431b319f9b9ac666d1d90f3
tokenDaydata query
{
tokenDayDatas(orderBy: date, orderDirection: asc,
where: {
token: "0x6b175474e89094c44da98b954eedeac495271d0f"
}
) {
id
date
priceUSD
totalLiquidityToken
totalLiquidityUSD
totalLiquidityETH
dailyVolumeETH
dailyVolumeToken
dailyVolumeUSD
}
}
global stat query
{
uniswapFactory(id: "0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f"){
totalVolumeUSD
totalLiquidityUSD
txCount
}
}
pair query data
{
pair(id: "0xa478c2975ab1ea89e8196811f51a7b7ade33eb11"){
token0 {
id
symbol
name
derivedETH
}
token1 {
id
symbol
name
derivedETH
}
reserve0
reserve1
reserveUSD
trackedReserveETH
token0Price
token1Price
volumeUSD
txCount
}
}
{0 0 0 1589328000 0x6b175474e89094c44da98b954eedeac495271d0f-18395 0 0 220 0} # first query
&{{{ { } { } }}} # second query
&{{{ }}} # third query
The parser of response have problem, the query is success but the second & third response is not parsed.
The res is not parsed correctly when it is a struct.
if err := graphqlClient.Run(context.Background(), graphqlRequest, &res); err != nil {
panic(err.Error())
}
If it's a interface{} passed in as response, then it will be ok, but it's in map[string]interface{} format.
A simple query request is working via the "GraphQL Playground" against our GraphQL server.
However, it's getting error "Must Provide Query String" while using your package to make the request.
Not sure if that's because of the ContentType (multipart/form-data vs application/json). That's definitely a blocker.
Hi !
I can't find a way to get the response status code when an HTTP error is returned.
My use case is that I want to check if it is a 401 (in which case I want to renew the client token).
Thanks !
I spent a good amount of time troubleshooting this and it could use some documentation, the response struct does not need the data
field as client.Run
expects GraphQL will always return data.
Hi ,
This lib is superb and we are using in prod so many thanks for creating it.
But there's a problem with the headers that are being always logged here https://github.com/machinebox/graphql/blob/master/graphql.go#L124,
This could expose sensitive information, mostly auth headers.
Can we avoid logging those headers? (I can create the PR but I just wanted to ask first :) )
Thanks in advance
I'm sending a delete mutation in statement that requires an array of uuids. In graphiql it works to declare the variable and give it
"variable":["uuid1","uuid2"]
When I print the req.Vars() to the logs to see what is getting passed, the data works when I copy it into graphiql to test.
I get map[id_array:["18259036-f4f9-298f-7cf5-529977cd0254","d4b1141b-2d82-4b67-e523-6c0d55c8fc5b"]]
However when I use the machinebox client I get the following error graphql: invalid input syntax for type uuid: "["18259036-f4f9-298f-7cf5-529977cd0254","d4b1141b-2d82-4b67-e523-6c0d55c8fc5b"]"
It appears to be wrapping double quotes around the square brackets later in the request process.
Hi there! I notice when I go get github.com/machinebox/graphql
, the version I have is missing the response status code checks that landed in #19. Does something need to be published or a version updated for me to get the latest code? Thank you!
Hi, after a few hours investigating what is happening, I can't find the problem.
Here is my full code, I have used that website to convert a response in struct from a web interface response (playground).
https://mholt.github.io/json-to-go/
import (
"fmt"
"github.com/machinebox/graphql"
)
// StatsResponse structure to parse a stats response.
type StatsResponse struct {
Data struct {
Stats struct {
Report struct {
Edges []struct {
Node struct {
StatsData struct {
Access struct {
AccessData struct {
Code string `json:"code"`
Name string `json:"name"`
Supplier struct {
SupplierData struct {
Code string `json:"code"`
Name string `json:"name"`
} `json:"supplierData"`
} `json:"supplier"`
} `json:"accessData"`
} `json:"access"`
Client struct {
ClientData struct {
Code string `json:"code"`
Name string `json:"name"`
} `json:"clientData"`
} `json:"client"`
Operations []struct {
Operation struct {
OperationData struct {
Code string `json:"code"`
Types []string `json:"types"`
API struct {
Code string `json:"code"`
} `json:"api"`
} `json:"operationData"`
} `json:"operation"`
TotalHits int `json:"totalHits"`
TrafficType string `json:"trafficType"`
DetailedHits []struct {
Code string `json:"code"`
Type string `json:"type"`
Hits int `json:"hits"`
Time int `json:"time"`
} `json:"detailedHits"`
} `json:"operations"`
} `json:"statsData"`
AdviseMessage []struct {
Code int `json:"code"`
Description string `json:"description"`
Level string `json:"level"`
External struct {
Code string `json:"code"`
Message string `json:"message"`
} `json:"external"`
} `json:"adviseMessage"`
} `json:"node"`
} `json:"edges"`
} `json:"report"`
} `json:"stats"`
} `json:"data"`
}
type filterInput struct {
From time.Time `json:"from"`
To time.Time `json:"to"`
Mode string `json:"mode"`
Owners []string `json:"owners"`
Clients []string `json:"clients"`
Suppliers []string `json:"suppliers"`
ServiceApis []string `json:"serviceApis"`
Operation []string `json:"operation"`
Groups []string `json:"groups"`
}
client := graphql.NewClient("https://api.xxxxxxx.com")
req := graphql.NewRequest(`
query QueryStatsDetails($filterInput: StatsFilterInput!) {
stats {
report(filter: $filterInput) {
edges {
node {
statsData {
access {
accessData {
code
name
supplier {
supplierData {
code
name
}
}
}
}
client {
clientData {
code
name
}
}
operations {
operation {
operationData {
code
types
api {
code
}
}
}
totalHits
trafficType
detailedHits {
code
type
hits
time
}
}
}
adviseMessage {
code
description
level
external {
code
message
}
}
}
}
}
}
}
`)
var filterInputBuyer = filterInput{
From: time.Date(2019, time.April, 30, 0, 0, 0, 0, time.UTC),
To: time.Date(2019, time.April, 30, 23, 59, 59, 0, time.UTC),
Mode: "BUYER",
Clients: make([]string, 0, 1),
ServiceApis: make([]string, 0, 8),
Operation: make([]string, 0, 4),
Groups: make([]string, 0, 1),
}
filterInputBuyer.Clients = append(filterInputBuyer.Clients, "cli8")
filterInputBuyer.Groups = append(filterInputBuyer.Groups, "XXXXXX")
filterInputBuyer.Operation = append(filterInputBuyer.Operation, "SEARCH", "QUOTE", "BOOKING", "OTHER")
filterInputBuyer.ServiceApis = append(filterInputBuyer.ServiceApis, "ACTIVITIES", "CAR", "HOTEL", "PACKAGE", "PAYMENT", "TRANSFERS", "TRANSPORTATION", "VIRTUALACCOUNT")
// Set authorization bearer
req.Header.Add("Authorization", header)
req.Var("filterInput", filterInputBuyer)
var res StatsResponse
ctx := context.Background()
if err := client.Run(ctx, req, &res); err != nil {
log.Fatal(err)
}
fmt.Println("response", res)
I'm always receiving an empty res object, and if I send it through playground works perfectly. What am I doing wrong? Someone can help me?
Many thanks!
query := mutation ($activeIp: String!) { registerActive(regReq:{ active: { ip:$active } }) { status } }
req := graphql.NewRequest(query)
req.Var("active", "1.1.1.1")
while sending I get:
graphql: name 'json' is not defined
Why don't we implement this https://github.com/jaydenseric/graphql-multipart-request-spec for file upload. When uploading file, it use operation
field containing json for specifying our query and variables. Then it use separated fields for specifying files.
I think there should be something like
if res.StatusCode != http.StatusOK {
after
res, err := c.httpClient.Do(r)
In case the server returns a 400 or a 500, the current code returns:
2018/01/17 17:44:37 << {"errors":[{}]}
graphql:
Hi there,
Look like this project is no longer maintained?
Thanks.
The graphQL spec specifies an extensions field in the top level response. It's reserved for implementation specific data. However right now there is no way for a client to reach that data. Some endpoints return useful data about query cost. Perhaps a function like RunWithExtensions
and convert Run
to just pass nil
to it for backwards compatibility and for anyone that doesn't care about them. I'd be willing to put together a PR if this is something that would be integrated.
We noticed an issue when using this library against AWS API Gateway with a WAF, although this issue is not limited to these technologies.
When hitting a WAF if you don't pass the rules you will get a 403
response with the body of {"message":"Forbidden"}
. When graphql parses this it it chokes.
Lines 140 to 145 in 3a92531
If you read the above code it attempts to decode the JSON body. Only if this fails does it check the status code. This causes bugs because the status code is 403, and a non-graphql layer is returning a JSON output.
This ends up with a graphql response that thinks it is successful, but in reality failed. The only sign that it failed is that the object that gets returned doesn't have any decoded data in it (unless it by chance has a "message" field).
My suggested fix would be to check the status code first, and error if it is a non-200. While this is not an official API definition APIs-guru points out this issue:
Note: For any non-2XX response, the client should not rely on the body to be in GraphQL format since the source of the response may not be the GraphQL server but instead some intermediary such as API gateways, firewalls, etc.
My concern would be that some non-compliant graphql instance would be returning 403 and similar error codes with valid graphql errors. In which case you encounter a new bug. Potentially we could do both, check if status code is non-200 and return an error. Then also parse the JSON?
Github graphql errors.
We were running a lot of graphql queries using multiple coroutines, we were running into issues where data returned is null.
In this case, we assume there is no more data from Github and stop the iteration. Eventually, we realized that data that we have doesn't match up with that of Github. Further debugging we found that we were getting secondary rate limit errors which were not sent back to the client.
Function:
c.runWithJSON(ctx, req, resp)
res, err := c.httpClient.Do(r)
if err != nil {
return err
}
defer res.Body.Close()
Does not propagate 403 rate limit errors , in which case if there is 403 library will try to read the data and pass it upstream.
Example error message:
"documentation_url": "https://docs.github.com/en/free-pro-team@latest/rest/overview/resources-in-the-rest-api#secondary-rate-limits",
"message": "You have exceeded a secondary rate limit. Please wait a few minutes before you try again."
Sample fix:
if res.StatusCode != 200 {
return errors.Wrap(err, "status code error ")
}
How do i get "response header" like Content-Encoding
? I need to extract gzip response.
I've used code like this before for http
if resp.Header.Get("Content-Encoding") == "gzip" {
// resp.Header.Del("Content-Length")
zr, err := gzip.NewReader(resp.Body)
if err != nil {
return nil, err
}
resp.Body = gzreadCloser{zr, resp.Body}
}
Has anyone seen this kind of error before? I ran this client on a loop for the last 12 hours, and around once every hour i noticed this error. It did not return any other contextual information
As title. I cannot find any examples about mutation apis.
It seems only support query?
https://github.com/machinebox/graphql/blob/master/graphql.go#L102
What is this ResponseStruct?
For a query or mutation, we must use a wrapper struct as the response struct.
This is very counterintuitive and should be pointed out in the example.
For example, for the following query,
type Query {
lesson(id: ID!): Lesson!
}
We need the following wrapper struct as the response,
type RespData {
Lesson: Lesson json: "lesson"
}
Or we can do as following:
var respData map[string]interface{}
convertMapDataToLesson(respData)
OpenTelemetry info can't transfer to the called api,I hav filled the ctx on client.Run(ctx, req, &result)
Hi!
I see errors
decoding response: json: cannot unmarshal string into Go struct field graphResponse.Errors of type graphql.graphErr
So, how I can easily print raw response without changing the library?
Anyone know if this supports subscriptions ? Could not see it.
Library looks great for wrapping grpc microservices. Am guessing that was the teams main use case ?
Hello,
When can we have this in a release, please?
Line 142 in 3a92531
We need this check and it's not available in V2.2. Can master be promoted to a release sometime soon?
Thanks.
Thank you for this excellent package! Made writing some scripts with Go and our GraphQL API (specifically this GraphQL API which has been amazing https://github.com/hasura/graphql-engine).
We are using Hasura with Lambda event functions, which takes a events.APIGatewayProxyRequest
. Since we are using the "serverless" functionality we decided to use Go for Lambda and started writing unit tests against our Hasura API.
My question is to make sure I am on the right track, I have used some of your test code to get myself pretty far, so thank you, but I am stuck on one specific problem. Here are the steps I have taken so far:
srv.URL
to graphql.NewClient(srv.URL)
Here is a sample of the test:
srv := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
io.WriteString(w, `{
"data": {
"insert_bookings": {
"returning": [
{
"id": "TX123456789",
"created_at": "2019-06-19T00:08:16.547491+00:00",
"updated_at": "2019-06-19T00:08:16.547491+00:00"
}
]
},
"insert_booking_events": {
"returning": [
{
"id": "bdeee2fe-7318-46bd-9b16-6c47ba12129a",
"vehicle_bookings_id": "TX123456789",
"status": "completed",
"created_at": "2019-06-19T00:08:16.547491+00:00",
"updated_at": "2019-06-19T00:08:16.547491+00:00"
}
]
}
}
}`)
}))
defer srv.Close()
However, when running the tests, I am getting an error with unsupported protocol scheme ""
that is coming from:
if err := client.Run(context.Background(), req, &resp); err != nil {
log.Fatal(err)
}
Any help or pointers would be greatly appreciated!
The latest tagged version of the package doesn't include getters for the Request struct and some other part of the source code present on GitHub. When working with VGO it leads to using an outdated project compared to the actual sources.
Could you please create a new release for that purpose ?
Hey @matryer!
I just discovered the existence of this Go GraphQL client via reddit.
I hope you don't mind this question, but I wanted to ask if https://github.com/shurcooL/graphql (and/or https://github.com/shurcooL/githubql) is on your radar already or not? It's an open source Go implementation of a GraphQL client. If you're interested, I can share some links with additional background information on its design and history, API design decisions and tradeoffs, etc.
Let me know if you're open to talking more about this and potentially working together to improve our projects. My goal is for Go users to have as nice a Go GraphQL client available to them as possible.
Thanks!
It would be nice if https://github.com/machinebox/graphql/blob/master/graphql.go#L48 could take a Doer
interface, compatible with the std lib *http.Client
so that clients can pass in whatever http client they want:
type Doer interface {
Do(req *http.Request) (*http.Response, error)
}
This shouldn't break any clients using the std lib today.
I'd be happy to create a PR if you don't see any issue with the change.
Is the object input type supported for making requests.
https://medium.com/graphql-mastery/json-as-an-argument-for-graphql-mutations-and-queries-3cd06d252a04
Hello I am new to go programming. When I import github.com/machinebox/graphql
in a go file, then run go mod tidy
, the following stuff appears in console
github.com/my/project/server imports
github.com/machinebox/graphql imports
github.com/pkg/errors: module github.com/pkg/errors@latest found (v0.9.1), but does not contain package github.com/pkg/errors
It indicates that the dependency of pkg/errors is not satisfied. Go won't let me compile this file either, as same thing happens.
I guess it requires explicitly import at graphql.go Line42.
Like this?
"github.com/pkg/[email protected]"
Hi,
req := graphql.NewRequest(`
query {
getAccessTokenByAppSecret(
clientId: $clientID,
secret: $appSecret
)
}
`)
req.Var("clientID", clientID)
req.Var("appSecret", appSecret)
ctx := context.Background()
var responseData map[string]interface{}
if err := c.userGraphqlClient.Run(ctx, req, &responseData); err != nil {
log.Fatal(err)
}
☆ examples »go run main.go
2018/03/18 01:52:04 >> variables: {"appSecret":"5cf63e2b82f2d6b41bdcfec8b483b740","clientID":"5a48b6ae863b3b0001893bbc"}
2018/03/18 01:52:04 >> files: 0
2018/03/18 01:52:04 >> query:
query {
getAccessTokenByAppSecret(
clientId: $clientID,
secret: $appSecret
)
}
2018/03/18 01:52:04 >> headers: map[Content-Type:[multipart/form-data; boundary=f262269d26f9acbc6a727ad9e0becd29acbc33c1f0110691763f4cb54862] Accept:[application/json]]
2018/03/18 01:52:05 << POST body missing. Did you forget use body-parser middleware?
2018/03/18 01:52:05 decoding response: invalid character 'P' looking for beginning of value
exit status 1
I have faced some issue after sending the request from the postman
schema :
export const types = scalar Upload
;
export const queries = ``;
export const mutations = singleUpload(file: Upload!): String!,
;
request :
{"query":"mutation SingleUpload($file:Upload!){\n singleUpload(file:$file)\n}"}
result after request:
Must provide query string.
please provide me the solution
file_upload_gql.pdf
With graphQL it's possible the response could be partially successful. With the way the client is currently configured, it's parsing the errors property and returning an error with the first error in the array if it's not empty.
Would you be open to a PR that instead passes the entire response? This would allow the caller to decide how it wants to handle the returned errors. We're also currently losing additional error context if more than one error is present.
D
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.