Coder Social home page Coder Social logo

graphql-go's People

Contributors

0xsalman avatar agnivade avatar dackroyd avatar dependabot[bot] avatar eloyekunle avatar fadi-alkatut avatar gracenoah avatar ivanp avatar ldechoux avatar matiasanaya avatar matthewmueller avatar neelance avatar obeis avatar oscaryuen avatar pavelnikolov avatar pzduniak avatar roaris avatar rudle avatar ryanslade avatar sanae10001 avatar savaki avatar sgy1980de avatar sogocze avatar sqs avatar suntoucha avatar technoweenie avatar tinnywang avatar tonyghita avatar tsholmes avatar zaydek avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

graphql-go's Issues

directives is empty in output of SchemaBuilder.ToJSON

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.

validation for required argument

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 }
    }
  }
}

viewer pattern

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.

Recursive Input Object

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.

Ability to return errors with extra fields

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.

return structured errors

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.

JSON scalar

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.

Use field as resolver instead of method.

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.

validation: interface implements a type

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.

import types of schema A into schema B

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.

panic on unexported field

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

Provide descriptions of objects in schema for tools like graphiql

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]
	}

panic on missing input variable

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)

define schema programmatically

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.

Panics with invalid/nonsensical queries in example

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.

[RFC] Resolver for fields only known at runtime

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:

  • Does a "catchall" method for unknown field sound reasonable to you? My intent is to create a patch suitable for upstream.
  • Am I on the right track? Maybe you have some immediate tips that could save me a lot of time.

... and if you thought about this further:

  • How can we signify the catchall method for the resolver? A special name, or some kind of a notation in the schema?

[*]: A simplified version of what I was trying to achieve with another library is here.

ENUM is being quirky

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?

roadmap

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

define scalar type in schema

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?

input relies on struct fields rather than methods?

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?

Validation test

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

custom scalar type

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
    },
  })
}

Input List Coercion

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 {}

No way to get requested fields inside resolver

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.

panic with wrong input type

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)

SchemaToJSON and custom scalars

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.

Data in input arrays are empty

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.

Expose the Go resolvers for __schema

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.

Documentation

Is there any documentation or guide for resolvers? The starwars example seems pretty convoluted.

Ability to mask or exclude some opentracing variables

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.

Pagination panics in example

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

Query with __typename returns nothing, how to fix it?

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
  }
}

DataLoader

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

Raw errors should not be returned to client

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.

Array as argument fails

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
    }
  }
}

optional input field

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.

Opentracing not tracing graphql traces

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>}

interface resolver

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)
  }
}

How do I use the graphql.Time type?

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?

Proposal: Generate interface for schema resolver like in GRPC for static checkers

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?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.