graph-gophers / graphql-go Goto Github PK
View Code? Open in Web Editor NEWGraphQL server with a focus on ease of use
License: BSD 2-Clause "Simplified" License
GraphQL server with a focus on ease of use
License: BSD 2-Clause "Simplified" License
Is this line correct? I feel like you meant to inject the internal github package? Its currently breaking my build.
https://github.com/neelance/graphql-go/blob/master/internal/exec/packer.go#L11
Hi,
the directive section of introspection is empty.
"directives": [],
"mutationType": {
"name": "Mutation"
},
"queryType": {
"name": "Query"
},
Not sure why the standard directives, include
and skip
is not included even though it is supported as seen in the tests. this blocks the use with relay.
Thanks.
Hi,
I noticed there is no validation error if a required argument is not provided. For example, if the schema is
widgets(first: Int, id: String!): WidgetConnection
then, below query doesn't give any error
{
widgets(first: 10) {
edges {
node { id, name }
}
}
}
Hello,
a common pattern in relay is viewer type, which models the current user and all graphql queries are fields of it. I am facing a difficulty as most of the creation mutation returns viewer on the payload as part of fat query. This creates a circular reference, as viewer contains all the query resolvers. Any thoughts on how can I split the resolvers in modules (which works fine for me, except the viewer pattern), and still allow mutation of entities access to viewer.
thanks,
bsr.
What I'm trying to do
I'm writing a service (no Relay), where users can generate custom filters that they can later apply on our dataset. These filters can be nested recursively. The idea is to be able to create filters that can compose other filters, whether from the same input or from existing filters. So we can filter our data for ((A || B) && (C || D))
, or other compositions.
How do I write the go glue for the following graphql schema? (the mutation code)
schema.graphql
type Query {
boolFilter(id: ID!): BoolFilter
}
type Mutation {
createBoolFilter(input: BoolFilterInput!): BoolFilter
}
type BoolFilter {
id: ID!
# many more, but only need id to make sure it's working
}
enum Operator {
AND
OR
NOT
XOR
}
type BoolFilterInput {
operator: Operator!
newFilters: [BoolFilterInput!] # termination case, stops recursing when newFilters is null
existingFiltersIDs: [ID!]
choiceIDs: [ID!]
}
Here's what I have so far.
boolFilter.go
type BoolFilterInput struct {
Operator string
NewFilters *[]*BoolFilterInput
ExistingFilterIDs *[]string
ChoiceIDs *[]string
}
resolvers.go
type Resolver struct {db: *sql.DB}
func (r *Resolver) CreateBoolFilter(args *struct { Input *BoolFilterInput } *BoolFilterResolver {
tx, _ := r.db.Begin()
id, _ := createNewBoolFilter(*newFilter, tx)
_ = tx.Exec("INSERT ...", ...)
_ = tx.Commit()
return &BoolFilterResolver {db: r.db, id.String()}
}
func createNewBoolFilter(input BoolFilterInput, tx *sql.Tx) (uuid.UUID, error) {
id := uuid.NewV1()
var relevantIDs []uuid.UUID
// ...
if input.NewFilters != nil {
for _, newFilter := range input.NewFilters {
if newFilter != nil {
id, _ := createNewBoolFilter(*newFilter, tx)
relevantIDs = append(relevantIDs, id)
}
}
}
_, _ := tx.Exec("INSERT ... id & operator...", ...)
for _, relevantID := range relevantIDs {
_, _ := tx.Exec("INSERT ... id & relevantID", ...)
}
return id, nil
}
What's happening
The compiler is telling me contradictory things.
Depending on whether the type of NewFilters
in BoolFilterInput
is *[]*BoolFilterInput
, *[]BoolFilterInput
, or []BoolFilterInput
, it will tell me it's expecting a pointer to a struct
or a slice
. (It also wants ExistingFilterIDs
and ChoiceIDs
to be []string
even though both lists can be nullable, so my understanding is that both should be *[]string
.
Just wanted to share a library introduced recently.
https://github.com/samsarahq/thunder
I am still exploring, and not sure anything we can learn from it.
According to the spec, errors must contain a message
key. However, the developer can add other fields if he wants.
In my case, for each error, I want to return both a message
which is developer friendly, and an error_code
such as USERNAME_UNAVAILABLE
. It would be nice if returning errors with extra user defined fields is possible.
Suppose I am sending a mutation with a collection of fields, and I need to validate them (i.e. check that string is an email, integer is valid age, string is valid phone number, string is valid credit card, etc).
Ideally, I would like to be able to returned a structured error when there were errors, something along the lines of:
{
errors: {
'email': 'Invalid email address'
'contact.phone': 'Invalid phone number',
'payment.creditcardnumber': 'This looks like an american express, not accepted here'
...
}
}
Producing the json above is quite simple (depends on what validation library you use for your inputs, there are plenty of them out there). However, reading the examples its not clear to me that graphql-go it is possible to write a resolver that returns such a structured error.
Hi,
I am trying to receive JSON input, and define a scalar type like
var JSON = &graphql.ScalarConfig{
ReflectType: reflect.TypeOf(json.RawMessage{}),
CoerceInput: func(input interface{}) (interface{}, error) {
switch input := input.(type) {
case string:
j := json.RawMessage([]byte(input))
return &j, nil
default:
return nil, fmt.Errorf("wrong type")
}
},
}
When I use it, gets the following error
2016/11/17 20:23:14 graphql: graphql: panic occured: reflect.Set: value of type *string is not assignable to type *json.RawMessage
goroutine 54 [running]:
github.com/neelance/graphql-go/internal/exec.(*request).handlePanic(0xc4202b4600)
/Users/bsr/.../external/src/github.com/neelance/graphql-go/internal/exec/exec.go:393 +0x123
panic(0x57a380, 0xc420345ef0)
/usr/local/go/src/runtime/panic.go:458 +0x243
reflect.Value.assignTo(0x5629e0, 0xc420345ee0, 0x16, 0x66308e, 0xb, 0x5b1d00, 0x0, 0x16, 0x5629e0, 0xc420345ee0)
/usr/local/go/src/reflect/value.go:2163 +0x35c
reflect.Value.Set(0x5b1d00, 0xc4202b4bf0, 0x196, 0x5629e0, 0xc420345ee0, 0x16)
/usr/local/go/src/reflect/value.go:1333 +0xa4
github.com/neelance/graphql-go/internal/exec.(*structPacker).pack(0xc42046e640, 0x5ab660, 0xc4204dfb38, 0x57a380, 0xc420198580, 0x9349e0)
INFO 2016-11-18 01:23:14,549 module.py:788] default: "POST /graphql HTTP/1.1" 200 138
/Users/bsr/.../external/src/github.com/neelance/graphql-go/internal/exec/exec.go:751 +0x2b3
how should I change the scalar definition.
thanks.
Would it be possible to use a struct field as a resolver instead of always using methods? Most of my methods are just simple getters so it would be convenient to allow resolver to default to field. Then I could implement method only when I need special logic.
Hello,
I had this code, and which didn't raise any error at server.
interface Node {
id: ID!
}
type Viewer implements Node {
# id: ID!
widgets(first: Int, q: String): WidgetConnection!
}
but, graphiql raised an error .
Error: "Node" expects field "id" but "Viewer" does not provide it.
at invariant (http://localhost:8082/index.js:25961:12)
at http://localhost:8082/index.js:26453:30
at Array.forEach (native)
at assertObjectImplementsInterface (http://localhost:8082/index.js:26448:31)
at http://localhost:8082/index.js:26326:19
at Array.forEach (native)
at http://localhost:8082/index.js:26325:31
at Array.forEach (native)
at new GraphQLSchema (http://localhost:8082/index.js:26322:33)
at buildClientSchema (http://localhost:8082/index.js:33920:11)
This also good to catch at schema build time.
thanks.
Thank you for more idiomatic graphql option for go.
I am currently using https://github.com/graphql-go/graphql, though it is incredibly verbose, I could structure the schema so it is kept at module level.
I see one thread in graphql-js
regarding the same, in which lee says
graphql/graphql-js#223
If you're using the schema language to build a schema than you need to first combine it into a single string before calling buildSchema. That typically is a nice developer experience for small to medium sized schema, though for more complex schema we recommend building the schema programmatically. Even in this case you still need to collect all the types to assemble the schema. A similar operation to collecting all the strings before calling buildSchema
I wonder what is the best approach you propose with this library. Any plan for incrementally building the schema by registering the graphql schema and resolve functions for isolated modules ?
thanks again for providing this library.
I got a panic, where the schema is built without error. Ideally this error should reported during parse time. I am still hunting it down, but proper error message would report which struct has unexported field. I hope you can identify the location with the stack trace.
2016/11/18 15:52:27 graphql: graphql: panic occured: reflect: reflect.Value.Set using value obtained using unexported field
goroutine 10 [running]:
github.com/neelance/graphql-go/internal/exec.(*request).handlePanic(0xc4201d4a00)
/Users/bsr/.../external/src/github.com/neelance/graphql-go/internal/exec/exec.go:392 +0x123
panic(0x57b880, 0xc420103760)
/usr/local/go/src/runtime/panic.go:458 +0x243
reflect.flag.mustBeAssignable(0x1b6)
/usr/local/go/src/reflect/value.go:225 +0x1a2
reflect.Value.Set(0x5552a0, 0xc420024300, 0x1b6, 0x5552a0, 0xc42047ed50, 0x16)
/usr/local/go/src/reflect/value.go:1327 +0x2f
github.com/neelance/graphql-go/internal/exec.(*structPacker).pack(0xc42046d000, 0x5acc60, 0xc4200452f0, 0x5acc60, 0xc42047ec60, 0x936a20)
/Users/bsr/.../external/src/github.com/neelance/graphql-go/internal/exec/exec.go:749 +0x2b3
github.com/neelance/graphql-go/internal/exec.(*fieldExec).execField2(0xc42046aff0, 0x933400, 0xc42047ecf0, 0xc4201d4a00, 0xc4201d4900, 0x5c0860, 0x983ae8, 0x16, 0x936a20, 0xc42048e
This is just an enhancement idea but I think it would be awesome to parse the comments above each type declaration (and field) and make them available to tools like graphiql so that we can have self documenting apis.
# A humanoid creature from the Star Wars universe
type Human implements Character {
# The ID of the human
id: ID!
# What this human calls themselves
name: String!
# Height in the preferred unit, default is meters
height(unit: LengthUnit = METER): Float!
# Mass in kilograms, or null if unknown
mass: Float
# This human's friends, or an empty list if they have none
friends: [Character]
# The friends of the human exposed as a connection with edges
friendsConnection(first: Int, after: ID): FriendsConnection!
# The movies this human appears in
appearsIn: [Episode!]!
# A list of starships this person has piloted, or an empty list if none
starships: [Starship]
}
It would be good to have some indication of what version of the GraphQL spec this implementation is currently aligned with. The current version is [email protected].
It would be great to detect the mistake during initial parse than at run time.
type Mutation {
updateHuman(ClientMutationId: String!, input: UpdateHumanInput!): updateHumanPayload
}
mutation M($in: UpdateHumanInput!) {
updateHuman(clientMutationId: "1",input: $in ) {
...
}
}
above gives the panic, as clientMutationId
should be ClientMutationId
below works
mutation M($in: UpdateHumanInput!) {
updateHuman(ClientMutationId: "1",input: $in ) {
...
}
}
stack
2016/11/18 18:04:46 graphql: graphql: panic occured: runtime error: invalid memory address or nil pointer dereference
goroutine 36 [running]:
github.com/neelance/graphql-go/internal/exec.(*request).handlePanic(0xc4201a18c0)
/Users/bsr/.../external/src/github.com/neelance/graphql-go/internal/exec/exec.go:392 +0x123
panic(0x5b1760, 0xc420012060)
/usr/local/go/src/runtime/panic.go:458 +0x243
github.com/neelance/graphql-go/internal/exec.(*fieldExec).execField2(0xc4204513b0, 0x934400, 0xc4201c5ad0, 0xc4201a18c0, 0xc4201a17c0, 0x5c0960, 0x984ae8, 0x16, 0x937a20, 0xc420472c80, ...)
/Users/bsr/.../external/src/github.com/neelance/graphql-go/internal/exec/exec.go:664 +0x1f9
github.com/neelance/graphql-go/internal/exec.(*fieldExec).execField(0xc4204513b0, 0x934400, 0xc4201c59b0, 0xc4201a18c0, 0xc4201a17c0, 0x5c0960, 0x984ae8, 0x16, 0xc4201872c0)
/Users/bsr/.../external/src/github.com/neelance/graphql-go/internal/exec/exec.go:640 +0x3b2
github.com/neelance/graphql-go/internal/exec.(*objectExec).execSelectionSet.func2()
/Users/bsr/.../external/src/github.com/neelance/graphql-go/internal/exec/exec.go:573 +0x3f4
github.com/neelance/graphql-go/internal/exec.(*objectExec).execSelectionSet.func1(0xc42019d540)
/Users/bsr/.../external/src/github.com/neelance/graphql-go/internal/exec/exec.go:524 +0xc0
INFO 2016-11-18 23:04:46,763 module.py:788] default: "POST /graphql HTTP/1.1" 200 125
github.com/neelance/graphql-go/internal/exec.(*objectExec).execSelectionSet(0xc4204568a0, 0x934400, 0xc4201c59b0, 0xc4201a18c0, 0xc420187260, 0x5c0960, 0x984ae8, 0x16, 0xc4201872c0, 0x54701)
Hi,
akin to how custom scalars can be defined, is it possible to define graphql types programmatically. One use case is to generate schema definition through code generation, say with the resolver struct and some struct tags. This may be related to #1 , but it may also help with modularization if a resolver also can set along with type registration. What do you think?
Thanks,
bsr.
I'm new to GraphQL and working toward setting up a server in Go. Was playing around with the example server and find that the server panics with some invalid or nonsensical queries. I would expect either a parsing error or more graceful failure.
Problem queries:
{
character(id: "1000") {
id
name
friends
}
}
{
character(id: "1000")
}
Note that adding matched braces after friends or character causes it to run without issue.
Hi, Richard,
First of all, thank you so much for working on this library. I find the very nice and clean.
I am working on enriching an existing GraphQL API with extra fields at runtime. E.g. let's say Character
at some point gets a surname, the application is notified, and adds an optional surname
field to the GraphQL schema, and is able to resolve it for characters with surnames. All that without code generation or restarting the server*.
In this library, a resolver must have one method for each field of the GraphQL type it resolves. This is super convenient -- well done! -- when all fields are known; however, as I do not know the field, I cannot create a method in advance, so that would mean a catch-all method for an unknown field. That would probably happen here. Questions:
... and if you thought about this further:
[*]: A simplified version of what I was trying to achieve with another library is here.
I may give a full example later to help you reproduce this but my current code isn't open-source.
I have an ENUM
type Bar
that is also an argument for a GraphQL mutation of a custom type Foo
.
schema looks like this:
type Mutation {
createFoo(blurb: String!, bar: Bar): Foo
}
enum Bar {
Bar1
Bar2
...
BarN
}
root resolver like this:
type Resolver struct {
db *sql.DB
}
func (r *Resolver) CreateFoo(args *struct{ Blurb, Bar string }) *FooResolver { ... }
type resolver like this:
type FooResolver struct {
db *sql.DB
id uuid.UUID
}
func (r *FooResolver) Bar() *string {
...
return &barString
}
Side note, would prefer
func (r *FooResolver) Bar() string { ... return barString }
or better
func (r *FooResolver) Bar() Bar { ... return bar }
but that doesn't compile on different errors
moving back to the main timeline
If I try to compile that, it fails with an error: Failed to parse raw schema: method "CreateFoo" of *main.Resolver: field "Bar": wrong type, expected *string
No problem, I'll adapt the Resolver.CreateFoo(...)
method like so:
func (r *Resolver) CreateFoo(args *struct{
Blurb string
Bar *string
}) *FooResolver { ... }
Then, when I run a query, I get this response:
{
"data": {
"createFoo": null
},
"errors": [
{
"message": "could not unmarshal \"Bar1\" (string) into *string: incompatible type"
}
]
}
By commenting out these lines and going back to my original code, it compiles and handles the mutation and the queries. What am I missing or is there a bug in the ENUM reflection?
Hello,
It would be great to see how feature compliant is this library with the graphql spec. Is it possible to maintain an issue or project to get an idea of when one can use certain feature.
thanks.
bsr
Currently error messages can get very long with a lot of "Error on X: Error on Y: Error on Z: ...". It should be "Error on X->Y->Z: ..." instead.
/cc @nicot
I use custom scalar, and it needed to be defined to use with other javascript backend.
scalar Time
scalar JSON
Otherwise, it gives error along the lines of, unreferenced type Time
, etc.
but, graphql-go
gives error
ERROR: graphql: syntax error: unexpected "scalar", expecting "schema", "type", "enum", "interface", "union" or "input" (line 7, column 9)
can we allow scalar
to be valid type?
I changed the reviewInput to have a method Stars()
instead of the field Stars
.
diff --git a/example/starwars/starwars.go b/example/starwars/starwars.go
index 23eb068..0bd6de6 100644
--- a/example/starwars/starwars.go
+++ b/example/starwars/starwars.go
@@ -357,7 +357,7 @@ func (r *Resolver) CreateReview(args *struct {
Review *reviewInput
}) *reviewResolver {
review := &review{
- stars: args.Review.Stars,
+ stars: args.Review.Stars(),
commentary: args.Review.Commentary,
}
reviews[args.Episode] = append(reviews[args.Episode], review)
@@ -646,6 +646,10 @@ func (r *pageInfoResolver) HasNextPage() bool {
}
type reviewInput struct {
- Stars int32
+ the_stars int32
Commentary *string
}
+
+func (r *reviewInput) Stars() int32 {
+ return r.the_stars
+}
panic: method "CreateReview" of *starwars.Resolver: missing argument "stars"
goroutine 1 [running]:
panic(0x2b9d60, 0xc420143c00)
/usr/local/Cellar/go/1.7/libexec/src/runtime/panic.go:500 +0x1a1
main.init.1()
/Users/dan/go/src/github.com/neelance/graphql-go/example/starwars/server/server.go:18 +0xc2
main.init()
/Users/dan/go/src/github.com/neelance/graphql-go/example/starwars/server/server.go:89 +0x47
Is this the expected behavior for input structs?
Hi!
Good work :)))
I checked http://graphql.org/learn/validation/ on starwars and find failed cases:
{
hero {
...NameAndAppearancesAndFriends
}
}
fragment NameAndAppearancesAndFriends on Character {
name
appearsIn
friends {
...NameAndAppearancesAndFriends
}
}
server didn't check recursion and go to infinity loop
{
hero {
name {
firstCharacterOfName
}
}
}
expected - "Field "name" must not have a selection since type "String!" has no subfields."
will be best if you include that tests - https://github.com/graphql/graphql-js/blob/master/src/__tests__/starWarsValidation-test.js
Is it possible to define and register a custom scalar type.
http://graphql.org/graphql-js/type/#graphqlscalartype
In graphql-go, I do it like,
var Time *graphql.Scalar
func init() {
Time = graphql.NewScalar(graphql.ScalarConfig{
Name: "DateTime",
Description: `Scalar type representing a date and time with offset, serialized as a string
in ISO-8601 date format.\n\ne.g. "2016-05-05T20:16:06Z"`,
// Serialize: gets invoked when serializing the result to send it back to a client.
// adapted from time.MarshalJSON https://golang.org/src/time/time.go?s=26891:26934#L918
Serialize: func(value interface{}) interface{} {
t, ok := value.(time.Time)
if !ok {
panic("TODO")
}
return formatTime(t)
},
// parseValue: gets invoked to parse client input that was passed through variables.
// value is a a plain type
ParseValue: func(value interface{}) interface{} {
str, ok := value.(string)
if !ok {
panic("TODO")
}
t, err := parseDate(str)
pkg.Check(err)
return t
},
// parseLiteral: gets invoked to parse client input that was passed inline in the query.
// value is ast.Value
ParseLiteral: func(valueAST ast.Value) interface{} {
switch valueAST := valueAST.(type) {
case *ast.StringValue:
t, err := parseDate(valueAST.Value)
if err != nil {
panic("TODO")
}
return t
}
return nil
},
})
}
I stumbled across this conversation for a question for graphQL-relay, where they point out that the
GraphQL Spec details that list inputs should be able to handle a single value of the type that can be used in the list. I have been attempting this, for a input of [String!]
but am getting the following error
graphql: graphql: panic occured: interface conversion: interface is string, not []interface {}
Problem:
Inefficient microservice/database queries.
If I need to return 100 orders with their clients, I have to make 101 requests to microservices (1 for batch of orders, 100 for their clients (one per each order)).
Scheme (simplified):
type Query {
orders: [Order]
}
type Order {
id: ID
client: Client
}
type Client {
id: ID
name: String
}
Query:
query GetOrders {
orders {
client {
name
}
}
}
Resolvers:
func (r *Resolver) Orders() []*orderResolver {
data, err := Request(orderService, "Order.List", &Args{}) // returns batch
...
return // batch of 100 order resolvers
}
// 100 client resolvers - 100 requests
func (r *orderResolver) Client() *clientResolver {
data, err := Request(clientService, "Client.Get",&Args{) // returns one
...
return // a client resolver
}
Instead, I'd like to know (in the order resolver) that the field with clients has been requested.
So I could make one batch request at the order resolver level.
Something like this:
func (r *Resolver) Orders(ctx context.Context) []*orderResolver {
data, err := Request(orderService, "Order.List", &Args{}) // returns batch
if ctx.Value("fields")... {
clients, err := Request(clientService, "Client.List",&Args{) // batch
}
...
return // batch of 100 order resolvers witch clients inside
}
So I get 2 request.
Hi,
When I use a wrong input argument, it panics. It works with {"name": ["abc"] }
, but panics with {"name": "abc" }
. A proper error would be better.
2016/11/29 18:00:45 CRITICAL: panic: interface conversion: interface is string, not []interface {}
goroutine 24 [running]:
...
github.com/neelance/graphql-go/internal/exec.coerceValue(0x0, 0x8b8840, 0xc4205154f0, 0x51bd20, 0xc4205143c0, 0xc42050d001, 0xc4205143d4, 0x1, 0xc4204142f8)
/Users/.../external/src/github.com/neelance/graphql-go/internal/exec/exec.go:649 +0x18c
github.com/neelance/graphql-go/internal/exec.coerceMap(0x0, 0xc4202d3058, 0xc42050c600, 0xc4202d3040, 0x0, 0x0)
/Users/.../external/src/github.com/neelance/graphql-go/internal/exec/exec.go:621 +0x144
github.com/neelance/graphql-go/internal/exec.ExecuteRequest(0x8c15c0, 0xc42050d290, 0xc4204387c0, 0xc420515440, 0xc4205143d4, 0x1, 0xc42050c600, 0x8c4aa0, 0xc4201dd900, 0xea2000, ...)
/Users/.../external/src/github.com/neelance/graphql-go/internal/exec/exec.go:323 +0x9c
github.com/neelance/graphql-go.(*Schema).Exec(0xc420536d00, 0x8c15c0, 0xc42050cc00, 0xc4202b8500, 0x4d8, 0xc4205143d4, 0x1, 0xc42050c600, 0x0)
INFO 2016-11-29 23:00:45,399 module.py:788] default: "POST /graphql HTTP/1.1" 500 -
/Users/.../external/src/github.com/neelance/graphql-go/graphql.go:125 +0x3cd
main.(*Handler).ServeHTTP(0xc42051b518, 0x8be100, 0xc420526420, 0xc42025c0f0)
Hi,
SchemaToJSON takes schema string, and unaware of custom scalars. I get this error.
ERROR: type "Time" not found
I will try to use exec.IntrospectSchema
directly, but it may better SchemaToJSON
take graphql.Schema
instead of string.
thanks.
This is what the relevant part of my schema looks like:
input MyInputType {
test1: String!
test2: String!
}
# The Input object sent when saving Events
input MyInput {
test: String!
myArray: [MyInputType!]!
}
My resolver looks like this:
type myInput struct {
Test string
MyArray []*myInputType
}
type myInputType struct {
Test1 string
Test2 string
}
func (r *Resolver) DoStuff(args *struct {
Input *myInput
}) (*myPayload, error) {
for _, e := range args.Input.MyArray {
fmt.Println(e.Test1)
fmt.Println(e.Test2)
}
// Do actually resolving here
}
From the fmt.Println
, the contents of e.Test
and e.Test2
is always ""
. I have confirmed at the entry point of the server that the values are actually sent correctly and can see those values there. It is when running schema.Exec
, that the values are empty in the resolver.
I'd like to be able to introspect a schema that is defined in the graphql schema language.
b, err := ioutil.ReadFile("schema.graphql")
if err != nil {
log.Fatalln("Unable to read schema file", err)
}
schema, err := graphql.ParseSchema(string(b), &Resolver{})
if err != nil {
log.Fatalln(err)
}
// TODO: ability to introspect schema
Being able to iterate over the schema after it's been parsed would help in writing code generators for resolvers.
I've been fuzzing with go-fuzz, and it found this (apparent) hang: https://gist.github.com/titanous/56d6628389b88a8a50966f30517b0c21
I'm happy to dig into this more and fix it, but I thought I'd open an issue early as I'm not yet familiar with the codebase.
Is there any documentation or guide for resolvers? The starwars example seems pretty convoluted.
When using opentracing, it will tag the variables being used for the request under graphql.variables
. This is great for tracing and debugging, however, sometimes the information in a variable might be sensitive, for example, a password or perhaps even a credit card number.
It would be nice to be able to mask or exclude (in my case masking would be more useful) some of the variables, so that we can retain the ability to debug, but not have those pieces of information logged.
The panic seems to happen when the last node is requested from the connection
diff --git a/graphql_test.go b/graphql_test.go
index 7b64c6e..8853a63 100644
--- a/graphql_test.go
+++ b/graphql_test.go
@@ -666,6 +666,23 @@ func TestConnections(t *testing.T) {
}
}
}
+ },
+ moreFriends: hero {
+ name
+ friendsConnection(first: 1, after: "Y3Vyc29yMg==") {
+ totalCount
+ pageInfo {
+ startCursor
+ endCursor
+ hasNextPage
+ }
+ edges {
+ cursor
+ node {
+ name
+ }
+ }
+ }
}
}
`,
@@ -689,6 +706,25 @@ func TestConnections(t *testing.T) {
}
]
}
+ },
+ "moreFriends": {
+ "name": "R2-D2",
+ "friendsConnection": {
+ "totalCount": 3,
+ "pageInfo": {
+ "startCursor": "Y3Vyc29yMw==",
+ "endCursor": "Y3Vyc29yMw==",
+ "hasNextPage": false
+ },
+ "edges": [
+ {
+ "cursor": "Y3Vyc29yMw==",
+ "node": {
+ "name": "Leia Organa"
+ }
+ }
+ ]
+ }
}
}
`,
2016/11/07 12:26:15 graphql: graphql: panic occured: runtime error: makeslice: len out of range
goroutine 89 [running]:
github.com/neelance/graphql-go/internal/exec.(*request).handlePanic(0xc4201d8840)
/Users/dan/go/src/github.com/neelance/graphql-go/internal/exec/exec.go:384 +0x123
panic(0x2ce460, 0xc4201ecab0)
/usr/local/Cellar/go/1.7/libexec/src/runtime/panic.go:458 +0x243
github.com/neelance/graphql-go/example/starwars.(*friendsConnectionResolver).Edges(0xc4201f2c00, 0x0)
/Users/dan/go/src/github.com/neelance/graphql-go/example/starwars/starwars.go:591 +0x65
Alternatively it would be possible to automatically synthesize the pointer when the resolver gets called, but currently I feel like supporting this does not have any proper purpose and it would just allow resolvers to be less nice.
/cc @nicot
I use Apollo client that automatically adds "__typename" field for each query. It is necessary for the internal optimisations and caching.
In your example this query works perfectly
{
hero {
__typename
id
}
}
But this still returns nothing
{
human(id: "1000") {
__typename
id
}
}
When I have a custom type like graphql.Time
I get an error on startup saying type "Time" not found
.
I think it is because Time doesn't exsist in this list: https://github.com/neelance/graphql-go/blob/master/internal/schema/schema.go#L111-L117
Is there a function or method to add a custom type to that list?
Commonly associated with GraphQL is a data fetching tool that Facebook has called Data Loader. Its a tool that can be used in resolvers to batch (and cache) requests for data to a backend.
I have taken a stab and implementing the DataLoader interface in Golang and would love feedback.
I don't want to pollute this repo with that discussion so please leave feedback in the issues section of my repo: https://github.com/nicksrandall/dataloader
Right now, some errors get sent to the client, which include details that may not be desirable to reveal publicly. Need a way to capture errors and handle them outside of this library.
Looking at the graphql spec, this is no indication that this is officially supported or not but I have a use case where I would like to pass an array as an argument to a resolver. Currently, I'm getting a TODO panic error when I do this:
https://github.com/neelance/graphql-go/blob/3b7efd5cb6e73337e26a67ca05750b6e1b02320e/internal/exec/exec.go#L315
As far as I can tell, that type switch needs to be able to handle a *common.List
item.
Here is my use case:
{
approvals(status: [PENDING, APPROVED]) {
type
title
amount
attachments
submitter {
firstName
lastName
title
}
}
}
Hello,
When using input arguments, it appears the optional fields are also required, else get a validation error.
To reproduce, comment out this line from the tests,
--- FAIL: TestMutation (0.00s)
--- FAIL: TestMutation/2 (0.00s)
testing.go:35: graphql: graphql: missing "commentary"
commentary is optional
input ReviewInput {
# 0-5 stars
stars: Int!
# Comment about the movie, optional
commentary: String
}
thanks.
I have a JSON grpc server backed by this graphql library. The grpc server is instrumented using the grpc-opentracing
package and I am using zipkin as the tracer. In the zipkin ui, I can see all the traces for the GRPC span, but I do not see any child graphql spans.
At the moment, I have only tested my mutations and have not tested any queries yet. The resolvers look like this:
func (r *Resolver) DoSomething(args *struct {
Input *DoSomethingInput
}) (*doSomethingPayload, error) {
}
I've added the following to https://github.com/neelance/graphql-go/blob/master/graphql.go#L86:
sp := opentracing.SpanFromContext(ctx)
fmt.Println(sp)
It does find a span, but I see nothing in the zipkin ui:
&{0xc4203fc310 <nil> {0 0} {{{0 21600196140346085} 1322274615697199075 true map[] <nil> 8 true} /eventstore.GraphQL/Query {63621715428 560669386 0x22de200} -1 map[span.kind:server component:gRPC] []} 0 <nil>}
It would be really cool if relay.Handler
can be updated to support the best practices outlined here: http://graphql.org/learn/serving-over-http/
For example, it would be nice to support both GET
and POST
and deal with different Content-Type
s.
I think the handler from graphql-go
can be used as a reference as it is pretty complete: https://github.com/graphql-go/handler/blob/master/handler.go
Hello,
I am trying to implement Node
interface as per the relay spec. @saward gave an example, and as I see in the starwars example, I need to implement To*
methods for all types which implements the interface. This makes the interface grow with the number of type implements it, and not able to split the resolver into multiple packages due to circular reference.
I wonder is it possible to check the method set of the concrete type, instead of the interface. In the below code, Node
method of root resolver returns type resolver which implements NodeResolver
interface (a single method), but has other methods to resolve the concrete type.
thank you,
bsr.
var Schema = `
schema {
query: Query
}
interface Node {
id: ID!
}
type Query {
node(id: ID!): Node
}
type Human implements Node {
id: ID!
}
type Droid implements Node {
id: ID!
}
`
type NodeResolver interface {
ID() graphql.ID
}
type Resolver struct{}
func (r *Resolver) Node(ctx context.Context, args *struct{ ID graphql.ID }) (NodeResolver, error) {
tp := getTypeFromID(args.ID)
switch tp {
case "human":
return &HumanResolver{getHumanOnID(string(args.ID))}
case "droid":
return &DroidResolver{getDroidOnID(string(args.ID))}
default:
return nil, fmt.Errorf("no fetcher for %s", tp)
}
}
I noticed that with the latest changes, AddCustomScalarType()
was removed.
My schema has a type like so:
type TestType {
created: Time!
}
When I parse the schema, it complains: type "Time" not found
. I also set the return type of my resolvers to graphql.Time
.
How do I fix this?
Now you made check resolvers by reflections on the fly. My suggest generate some code with interface by schema file for static check resolver impl on compilation step:
$ ls -l
schema.gql
schema.go // <- go generate graphql
schema.gql.go // generated file with interface of resolver, enum and other helpers %)))
what you think about it?
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.