Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support JSON scalar type #32

Open
andreimc opened this issue Oct 24, 2018 · 11 comments
Open

support JSON scalar type #32

andreimc opened this issue Oct 24, 2018 · 11 comments
Labels
API decision NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.

Comments

@andreimc
Copy link

struct field for status doesn't exist in any of 2 places to unmarshal

I have a JSON type and it seems to be expecting the whole object before running my unmarshal.

is there any way to ignore this given it's a JSON scalar return?

@dmitshur
Copy link
Member

Thanks for the report. How can I reproduce this?

@seta-tonypham
Copy link

seta-tonypham commented Oct 25, 2018

@dmitshur I have same issue too, My GQL like struct below
query { example(id:"123456") { id jsondata } }
jsondata result example is {foo: bar}

@dmitshur dmitshur added the WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided. label Oct 28, 2018
@dmitshur
Copy link
Member

dmitshur commented Oct 28, 2018

There's not enough information there for me to reproduce this. Can you please post a minimal working Go program that triggers that error? Or at least include the query (or a minified version of it) you wrote, and the JSON response from the GraphQL server?

Here's a starting point to make it easier; you just need to replace the query and JSON response:

package main

import (
	"context"
	"fmt"
	"io"
	"net/http"
	"net/http/httptest"

	"github.com/shurcooL/graphql"
)

func main() {
	mux := http.NewServeMux()
	mux.HandleFunc("/graphql", func(w http.ResponseWriter, req *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		io.WriteString(w, `{"data": {"viewer": {"login": "gopher", "bio": "The Go gopher."}}}`)
	})
	client := graphql.NewClient("/graphql", &http.Client{Transport: localRoundTripper{handler: mux}})

	var query struct {
		Viewer struct {
			Login     string
			Biography string `graphql:"bio"`
		}
	}
	err := client.Query(context.Background(), &query, nil)
	fmt.Println("error:", err)
	fmt.Printf("query: %+v\n", query)

	// Output:
	// error: <nil>
	// query: {Viewer:{Login:gopher Biography:The Go gopher.}}
}

// localRoundTripper is an http.RoundTripper that executes HTTP transactions
// by using handler directly, instead of going over an HTTP connection.
type localRoundTripper struct {
	handler http.Handler
}

func (l localRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
	w := httptest.NewRecorder()
	l.handler.ServeHTTP(w, req)
	return w.Result(), nil
}

@adamgoose
Copy link

I'm also running into this issue. I am using Prisma as my GraphQL Server, which provides a scalar Json type. Consider the following schema:

type Query {
  metaObjectType(id:ID!): MetaObjectType
}
type MetaObjectType {
  parentId: String!
  meta: Json!
}

The following query is valid.

query {
  metaObjectType(id:$id) {
    parentId
    meta
  }
}

The following query is invalid, and produces an error: "Field 'meta' of type 'Json' must not have a sub selection."

query {
  metaObjectType(id:$id) {
    parentId
    meta {
      someMetaKey
    }
  }
}

I'd like to define my struct like this:

type MyQuery struct {
  MetaObjectType struct {
    ParentID string
    Meta     json.RawMessage
  } `graphql:"metaObjectType(id:$id)"`
}

However, as reported above, the "no place to unmarshal" error is returned when the response json contains more fields than the provided struct.

My vote is to queries to be specified as json.RawMessage for this use case.

@adamgoose
Copy link

I have gone ahead and introduced the issue into the boilerplate code you provided above.

package main

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/http/httptest"

	"github.com/shurcooL/graphql"
)

func main() {
	mux := http.NewServeMux()
	mux.HandleFunc("/graphql", func(w http.ResponseWriter, req *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		io.WriteString(w, `{"data": {"viewer": {"login": "gopher", "bio": "The Go gopher.", "meta": {"foo": "bar"}}}}`)
	})
	client := graphql.NewClient("/graphql", &http.Client{Transport: localRoundTripper{handler: mux}})

	var query struct {
		Viewer struct {
			Login     string
			Biography string `graphql:"bio"`
			Meta      json.RawMessage
		}
	}
	err := client.Query(context.Background(), &query, nil)
	fmt.Println("error:", err)
	fmt.Printf("query: %+v\n", query)

	// Output:
	// error: <nil>
	// query: {Viewer:{Login:gopher Biography:The Go gopher.}}
}

// localRoundTripper is an http.RoundTripper that executes HTTP transactions
// by using handler directly, instead of going over an HTTP connection.
type localRoundTripper struct {
	handler http.Handler
}

func (l localRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
	w := httptest.NewRecorder()
	l.handler.ServeHTTP(w, req)
	return w.Result(), nil
}

@cameronbrunner
Copy link

cameronbrunner commented May 9, 2019

With the changes from #41:

package main
  
import (
        "context"
        "encoding/json"
        "fmt"
        "io"
        "net/http"
        "net/http/httptest"

        "github.com/shurcooL/graphql"
)

func main() {
        mux := http.NewServeMux()
        mux.HandleFunc("/graphql", func(w http.ResponseWriter, req *http.Request) {
                w.Header().Set("Content-Type", "application/json")
                io.WriteString(w, `{"data": {"viewer": {"login": "gopher", "bio": "The Go gopher.", "meta": {"foo": "bar"}}}}`)
        })
        client := graphql.NewClient("/graphql", &http.Client{Transport: localRoundTripper{handler: mux}})

        var query struct {
                Viewer struct {
                        Login     string
                        Biography string `graphql:"bio"`
                        Meta      json.RawMessage
                }
        }
        err := client.Query(context.Background(), &query, nil)
        fmt.Println("error:", err)
        fmt.Printf("query: %+v\n", query)
        fmt.Printf("raw: %+v\n", string(query.Viewer.Meta))

        // Output:
        // error: <nil>
        // query: {Viewer:{Login:gopher Biography:The Go gopher. Meta:[123 34 102 111 111 34 58 34 98 97 114 34 125]}}
        // raw: {"foo":"bar"}
}

// localRoundTripper is an http.RoundTripper that executes HTTP transactions
// by using handler directly, instead of going over an HTTP connection.
type localRoundTripper struct {
        handler http.Handler
}

func (l localRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
        w := httptest.NewRecorder()
        l.handler.ServeHTTP(w, req)
        return w.Result(), nil
}
cbrunner-mac:graphql cbrunner$ go run cmd/main.go 
error: <nil>
query: {Viewer:{Login:gopher Biography:The Go gopher. Meta:[123 34 102 111 111 34 58 34 98 97 114 34 125]}}
raw: {"foo":"bar"}

@dmitshur
Copy link
Member

Thank you @adamgoose for providing additional information and the reproducible snippet. It has helped a lot, I'm able to understand this issue now. I haven't run into it myself because GitHub API v4 doesn't have a JSON scalar type.

Thanks for working on a PR @cameronbrunner, and sorry about the slow response there. I don't have a lot of bandwidth left to do reviews in this repo unfortunately.

Using json.RawMessage seems reasonable, but I'll want to think if there any other solutions, and then I'll try to find some time for code review. I just wanted to post this update here for now.

@dmitshur dmitshur added API decision NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. and removed WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided. labels Aug 26, 2019
@dmitshur dmitshur changed the title Query JSON field failing support JSON scalar type Aug 26, 2019
@karthikvt26
Copy link

Bumped into this issue. Any update on supporting this?
Thanks

@cor
Copy link

cor commented Jan 29, 2022

Is there a workaround for this? I really need to insert a jsonb into a Hasura database

@cameronbrunner
Copy link

cameronbrunner commented Jan 31, 2022

@cor My #41 branch is still here... https://github.com/Navops/graphql/tree/support-raw-json (the v0.0.2 tag is pointing at this branches current HEAD/tip). You can use that directly, fork it, etc. We do something similar in our project by adding the following line to our go.mod

replace github.com/shurcooL/graphql => github.com/navops/graphql v0.0.2

@brandonbloom
Copy link

This is now supported in my transport-agnostic fork: https://github.com/deref/graphql-go

The specific changes are here: deref/graphql-go@c7885fd...e2b4739

grihabor pushed a commit to grihabor/graphql that referenced this issue Jul 20, 2022
* added method to execute queries already pre-built
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
API decision NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Development

No branches or pull requests

8 participants