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

Recursive schema definition potentially causing an infinite loop #38

Closed
Bockit opened this issue Jan 6, 2016 · 13 comments
Closed

Recursive schema definition potentially causing an infinite loop #38

Bockit opened this issue Jan 6, 2016 · 13 comments

Comments

@Bockit
Copy link

Bockit commented Jan 6, 2016

Hi. Firstly, thanks for all the work on graphql-elixir and plug-graphql.

I'm having trouble with a circular schema definition. Using plug_graphql in phoenix and the server freezes up no matter the query when the circular definitions are in play.

  • Recurring
  • Transaction
  • Tag

Relations are:

  • Tags many to many Recurring
  • Tags many to many Transaction

https://github.com/Bockit/budget/tree/master/apps/api-server/web/graphql is the graphql schema I have for this model. The root query provides a singular and list type query for each model. Each model has a resolve tag for its relations.

Before I added the relations to the Tag schema, things were great but once I added the recurrings and transactions relations to the Tag schema all requests freeze up in what appears to be an infinite loop. Even if you don't request any of the relation fields.

If you comment out the tags field on Transaction, and the recurrings field on Tag (breaking the circle) then you can do the following and it works as expected:

$ curl "http://127.0.0.1:4000/api?query=\{recurring(id:11)\{amount,tags\{tag,transactions\{amount\}\}\}\}"
{
  "data": {
    "recurring": {
      "tags": [
        {
          "transactions": [
            {
              "amount": 24.53
            }
          ],
          "tag": "Utilities"
        },
        {
          "transactions": [
            {
              "amount": 60.0
            }
          ],
          "tag": "Development"
        }
      ],
      "amount": 50.0
    }
  }
}

If this is confusing I can make a simpler, proof-of-concept reproduction tomorrow. If I'm correct and this is causing an infinite loop with a circular reference as described then a simple schema with 2 object types that both refer back to each other should cause the same effect.

Thanks for your time.

@joshprice
Copy link
Member

Thanks for the bug report! I'll see if can reproduce this and let you know if I have any questions.

@Bockit
Copy link
Author

Bockit commented Jan 7, 2016

@joshprice I put together a reproduction as a test and it passes so it looks like things are good. I think the infinite loop is me calling schema, calling schema, calling schema, calling schema in my definitions.

If you want the test in here I can make it a PR, otherwise I'll drop the branch. Either way, I think this issue is closable. Sorry if you wasted any time on it!

@Bockit Bockit closed this as completed Jan 7, 2016
@joshprice
Copy link
Member

Hadn't had a chance to look at it yet, but glad you got to the bottom of it. A PR with that recursion test in would be fantastic thanks!

@Bockit
Copy link
Author

Bockit commented Jan 7, 2016

Turns out my test wasn't a circular dep, if I went any levels deeper it wouldn't work because elixir isn't mutable and my last reference to fruit in basket doesn't have a basket field.

Basically something like this that I would do in node isn't something I can do in elixir.

var a = {}
var b = {}
b.a = a
a.b = b

console.log(a.b.a.b.a.b.a.b === b) // true

Which in a long story short is to say in the end it's not testing anything you aren't already testing :)

Just had a chat about it in #general in the elixir slack. The tip about recursive traversal algorithms is intriguing but seeing as the use case I have for it can be solved by using my own recursion for how deep I define the schema I'm going to go with that and the recursive algorithm traversal is probably way out of scope for this library.

markolson pushed a commit to markolson/graphql-elixir that referenced this issue Jan 7, 2016
As reported in Issue graphql-elixir#38, Schemas weren't able to recursively refer to
one another. By quoting the offending references and only evaling them
during Execution, we can resolve everything on-demand.
@markolson
Copy link
Member

So, I saw this Issue just before starting to travel, and ended up coming with a solution ( #39 ) analogous to the js reference implementation of graphql. Where they wrap the fields in an anonymous function to delay execution, I think we can quote ours.

markolson added a commit to markolson/graphql-elixir that referenced this issue Jan 9, 2016
As reported in Issue graphql-elixir#38, Schemas weren't able to recursively refer to
one another. By quoting the offending references and only evaling them
during Execution, we can resolve everything on-demand.
@Bockit
Copy link
Author

Bockit commented Jan 10, 2016

Thanks @markolson, really great!

markolson pushed a commit to markolson/graphql-elixir that referenced this issue Jan 12, 2016
As reported in Issue graphql-elixir#38, Schemas weren't able to recursively refer to
one another. By quoting the offending references and only evaling them
during Execution, we can resolve everything on-demand.
@ashleyw
Copy link

ashleyw commented Apr 18, 2016

I'm using @markolson's fix (#39), however with graphql-relay, running GraphQL.Relay.generate_schema_json! throws this error:

[debug] Updating GraphQL schema.json
** (FunctionClauseError) no function clause matching in GraphQL.Type.CompositeType.do_get_fields/1
    (graphql) lib/graphql/type/composite_type.ex:33: GraphQL.Type.CompositeType.do_get_fields({:%{}, [], [max_score: {:%{}, [], [type: {:%, [], [{:__aliases__, [alias: false], [:GraphQL, :Type, :Float]}, {:%{}, [], []}]}, resolve: {:fn, [], [{:->, [], [[{:_, [], VideoSchema}, {:_, [], VideoSchema}, {:_, [], VideoSchema}], 1]}]}]}, videos: {:%{}, [], [type: {{:., [], [Access, :get]}, [], [{:video_connection, [], VideoSchema}, :connection_type]}, args: {{:., [], [{:__aliases__, [alias: GraphQL.Relay.Connection], [:Connection]}, :args]}, [], []}, resolve: {:fn, [], [{:->, [], [[{:videos, [], VideoSchema}, {:args, [], VideoSchema}, {:_ctx, [], VideoSchema}], {:__block__, [], [{{:., [], [{:__aliases__, [alias: false], [:IO]}, :inspect]}, [], [{:args, [], VideoSchema}]}, {:=, [], [{:cursor_count, [], VideoSchema}, {:try, [], [[do: {{:., [], [{:__aliases__, [alias: GraphQL.Relay.Connection.List], [:Connection, :List]}, :cursor_to_offset]}, [], [{:||, [context: VideoSchema, import: Kernel], [{{:., [], [Access, :get]}, [], [{:args, [], VideoSchema}, :after]}, {{:., [], [Access, :get]}, [], [{:args, [], VideoSchema}, :before]}]}]}, rescue: [{:->, [], [[{:__aliases__, [alias: false], [:FunctionClauseError]}], 0]}]]]}]}, {:=, [], [{:count, [], VideoSchema}, {:+, [context: VideoSchema, import: Kernel], [{:+, [context: VideoSchema, import: Kernel], [{:cursor_count, [], VideoSchema}, {{:., [], [Access, :get]}, [], [{:args, [], VideoSchema}, :first]}]}, 1]}]}, {{:., [], [{:__aliases__, [alias: GraphQL.Relay.Connection.List], [:Connection, :List]}, :resolve]}, [], [{:videos, [], VideoSchema}, {:args, [], VideoSchema}]}]}]}]}]}]})
    (graphql) lib/graphql/type/schema.ex:56: GraphQL.Schema.reduce_types/2
    (stdlib) lists.erl:1262: :lists.foldl/3
    (graphql) lib/graphql/type/schema.ex:57: GraphQL.Schema.reduce_types/2
    (stdlib) lists.erl:1262: :lists.foldl/3
    (graphql) lib/graphql/type/schema.ex:57: GraphQL.Schema.reduce_types/2
    (graphql) lib/graphql/type/schema.ex:31: GraphQL.Schema.reduce_types/1
    (graphql) lib/graphql/type/schema.ex:26: GraphQL.Schema.type_from_ast/2
    (graphql) lib/graphql/lang/ast/type_info_visitor.ex:100: GraphQL.Lang.AST.Visitor.GraphQL.Lang.AST.TypeInfoVisitor.enter/3
    (graphql) lib/graphql/lang/ast/composite_visitor.ex:71: GraphQL.Lang.AST.Visitor.GraphQL.Lang.AST.CompositeVisitor.call_in_order/5
    (graphql) lib/graphql/lang/ast/reducer.ex:33: GraphQL.Lang.AST.Reducer.visit/3
    (graphql) lib/graphql/lang/ast/reducer.ex:21: GraphQL.Lang.AST.Reducer.visit/3
    (graphql) lib/graphql/lang/ast/reducer.ex:51: GraphQL.Lang.AST.Reducer.visit_each_child/3
    (graphql) lib/graphql/lang/ast/reducer.ex:36: GraphQL.Lang.AST.Reducer.visit/3
    (graphql) lib/graphql/lang/ast/reducer.ex:16: GraphQL.Lang.AST.Reducer.reduce/3
    (graphql) lib/graphql/validation/validator.ex:29: GraphQL.Validation.Validator.validate_with_rules/3
    (graphql) lib/graphql.ex:44: GraphQL.execute_with_optional_validation/6
    lib/graphql_relay.ex:28: GraphQL.Relay.introspection/0
    lib/graphql_relay.ex:23: GraphQL.Relay.generate_schema_json!/0
    (stdlib) erl_eval.erl:670: :erl_eval.do_apply/6

I'm not sure whether this is an issue with graphql-elixir or graphql-relay?

EDIT: I get the error when starting the server too, so I don't think it's related to graphql-relay.

@joshprice
Copy link
Member

Thanks for the bug report.

Not sure which branch you mean, but please try using the latest GraphQL
release. Also it would be great to see your schema to help debug this.

On Mon, Apr 18, 2016 at 3:19 PM, Ashley Williams notifications@github.com
wrote:

I'm using @markolson https://github.com/markolson's branch with this
fix, however when using graphql-relay, running
GraphQL.Relay.generate_schema_json! throws this error:

[debug] Updating GraphQL schema.json
** (FunctionClauseError) no function clause matching in GraphQL.Type.CompositeType.do_get_fields/1
(graphql) lib/graphql/type/composite_type.ex:33: GraphQL.Type.CompositeType.do_get_fields({:%{}, [], [max_score: {:%{}, [], [type: {:%, [], [{:aliases, [alias: false], [:GraphQL, :Type, :Float]}, {:%{}, [], []}]}, resolve: {:fn, [], [{:->, [], [[{:, [], VideoSchema}, {:, [], VideoSchema}, {:_, [], VideoSchema}], 1]}]}]}, videos: {:%{}, [], [type: {{:., [], [Access, :get]}, [], [{:video_connection, [], VideoSchema}, :connection_type]}, args: {{:., [], [{:aliases, [alias: GraphQL.Relay.Connection], [:Connection]}, :args]}, [], []}, resolve: {:fn, [], [{:->, [], [[{:videos, [], VideoSchema}, {:args, [], VideoSchema}, {:_ctx, [], VideoSchema}], {:block, [], [{{:., [], [{:aliases, [alias: false], [:IO]}, :inspect]}, [], [{:args, [], VideoSchema}]}, {:=, [], [{:cursor_count, [], VideoSchema}, {:try, [], [[do: {{:., [], [{:aliases, [alias: GraphQL.Relay.Connection.List], [:Connection, :List]}, :cursor_to_offset]}, [], [{:||, [context: VideoSchema, imp
ort: Ker
nel], [{{:., [], [Access, :get]}, [], [{:args, [], VideoSchema}, :after]}, {{:., [], [Access, :get]}, [], [{:args, [], VideoSchema}, :before]}]}]}, rescue: [{:->, [], [[{:aliases, [alias: false], [:FunctionClauseError]}], 0]}]]]}]}, {:=, [], [{:count, [], VideoSchema}, {:+, [context: VideoSchema, import: Kernel], [{:+, [context: VideoSchema, import: Kernel], [{:cursor_count, [], VideoSchema}, {{:., [], [Access, :get]}, [], [{:args, [], VideoSchema}, :first]}]}, 1]}]}, {{:., [], [{:aliases, [alias: GraphQL.Relay.Connection.List], [:Connection, :List]}, :resolve]}, [], [{:videos, [], VideoSchema}, {:args, [], VideoSchema}]}]}]}]}]}]})
(graphql) lib/graphql/type/schema.ex:56: GraphQL.Schema.reduce_types/2
(stdlib) lists.erl:1262: :lists.foldl/3
(graphql) lib/graphql/type/schema.ex:57: GraphQL.Schema.reduce_types/2
(stdlib) lists.erl:1262: :lists.foldl/3
(graphql) lib/graphql/type/schema.ex:57: GraphQL.Schema.reduce_types/2
(graphql) lib/graphql/type/schema.ex:31: GraphQL.Schema.reduce_types/1
(graphql) lib/graphql/type/schema.ex:26: GraphQL.Schema.type_from_ast/2
(graphql) lib/graphql/lang/ast/type_info_visitor.ex:100: GraphQL.Lang.AST.Visitor.GraphQL.Lang.AST.TypeInfoVisitor.enter/3
(graphql) lib/graphql/lang/ast/composite_visitor.ex:71: GraphQL.Lang.AST.Visitor.GraphQL.Lang.AST.CompositeVisitor.call_in_order/5
(graphql) lib/graphql/lang/ast/reducer.ex:33: GraphQL.Lang.AST.Reducer.visit/3
(graphql) lib/graphql/lang/ast/reducer.ex:21: GraphQL.Lang.AST.Reducer.visit/3
(graphql) lib/graphql/lang/ast/reducer.ex:51: GraphQL.Lang.AST.Reducer.visit_each_child/3
(graphql) lib/graphql/lang/ast/reducer.ex:36: GraphQL.Lang.AST.Reducer.visit/3
(graphql) lib/graphql/lang/ast/reducer.ex:16: GraphQL.Lang.AST.Reducer.reduce/3
(graphql) lib/graphql/validation/validator.ex:29: GraphQL.Validation.Validator.validate_with_rules/3
(graphql) lib/graphql.ex:44: GraphQL.execute_with_optional_validation/6
lib/graphql_relay.ex:28: GraphQL.Relay.introspection/0
lib/graphql_relay.ex:23: GraphQL.Relay.generate_schema_json!/0
(stdlib) erl_eval.erl:670: :erl_eval.do_apply/6

I'm not sure whether this is an issue with graphql-elixir or graphql-relay
?


You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub
#38 (comment)

@ashleyw
Copy link

ashleyw commented Apr 18, 2016

This is using the master branch. I think this is the relevant schema:


  def node_interface do
    Node.define_interface(fn(obj) ->
      case obj do
        %{videos: _videos} ->
          video_list
        _ ->
          video
      end
    end)
  end

  def video_connection do
   %{
     name: "Video",
     node_type: video,
     edge_fields: %{},
     connection_fields: %{},
     resolve_node: nil,
     resolve_cursor: nil
   } |> Connection.new
  end

  def video do
    %GraphQL.Type.ObjectType{
      name: "Video",
      description: "A Video",
      fields: quote do %{
        id: Node.global_id_field("video"),
        more_like_this: %{
          type: %GraphQL.Type.List{ ofType: video }
          args: %{
            count: %{type: %GraphQL.Type.Int{}}
          },
          resolve: fn _, _, _ -> end
        }
      } end,
      interfaces: [node_interface]
    }
  end

Thanks!

@joshprice
Copy link
Member

joshprice commented Apr 18, 2016

So the quote fix is deprecated since we support referencing types as modules (see https://github.com/graphql-elixir/graphql/blob/master/test/support/star_wars/schema.exs for an example).

Update: this is definitely a schema issue, and I suspect the quoting might be causing this.

@ashleyw
Copy link

ashleyw commented Apr 18, 2016

Ah — thanks!

Although I think there may still be an issue. type: %{type: VideoList} doesn't work, yet type: %List{ofType: Video} does. Is that intended? Or am I doing something wrong? :)

  defmodule VideoList do
    def video_connection do
     %{
       name: "Video",
       node_type: Video,
       edge_fields: %{},
       connection_fields: %{},
       resolve_node: nil,
       resolve_cursor: nil
     } |> Connection.new
    end

    def type do
      %ObjectType{
        name: "Videos",
        description: "List of Videos",
        fields: %{
          videos: %{
            type: video_connection[:connection_type],
            args: Connection.args,
            resolve: fn(videos, args, _ctx) ->
              cursor_count = try do
                Connection.List.cursor_to_offset(args[:after] || args[:before])
              rescue
                FunctionClauseError -> 0
              end
              count = cursor_count + args[:first] + 1
              Connection.List.resolve(videos, args)
            end
          }
        }
      }
    end
  end

  defmodule Video do
    def type do
      %ObjectType{
        name: "Video",
        description: "A YouTube video",
        fields: %{
          id: Node.global_id_field("video"),
          more_like_this: %{
            type: %{type: VideoList},
            resolve: fn _, _, _ -> end
          }
        }
      }
    end
  end
[debug] Updating GraphQL schema.json
** (FunctionClauseError) no function clause matching in GraphQL.Schema.reduce_types/2
    (graphql) lib/graphql/type/schema.ex:36: GraphQL.Schema.reduce_types(%{"Channel" => %GraphQL.Type.ObjectType{description: "YouTube channel", fields: %{title: %{type: %GraphQL.Type.String{description: "The `String` scalar type represents textual data, represented as UTF-8\ncharacter sequences. The String type is most often used by GraphQL to\nrepresent free-form human-readable text.\n", name: "String"}}, video_list: %{type: VideoSchema.VideoList}}, interfaces: [], isTypeOf: nil, name: "Channel"}, "Float" => %GraphQL.Type.Float{description: "The `Float` scalar type represents signed double-precision fractional\nvalues as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).\n", name: "Float"}, "ID" => %GraphQL.Type.ID{description: "The `ID` scalar type represents a unique identifier, often used to\nrefetch an object or as key for a cache. The ID type appears in a JSON\nresponse as a String; however, it is not intended to be human-readable.\nWhen expected as an input type, any string (such as `\"4\"`) or integer\n(such as `4`) input value will be accepted as an ID.\n", name: "ID"}, "Int" => %GraphQL.Type.Int{description: "The `Int` scalar type represents non-fractional signed whole numeric\nvalues. Int can represent values between -(2^53 - 1) and 2^53 - 1 since\nrepresented in JSON as double-precision floating point numbers specified\nby [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).\n", name: "Int"}, "Query" => %GraphQL.Type.ObjectType{description: "", fields: %{channel: %{args: %{id: %{type: %GraphQL.Type.String{description: "The `String` scalar type represents textual data, represented as UTF-8\ncharacter sequences. The String type is most often used by GraphQL to\nrepresent free-form human-readable text.\n", name: "String"}}}, resolve: &VideoSchema.show_channel/3, type: VideoSchema.Channel}, mostPopular: %{resolve: #Function<0.116378938/3 in VideoSchema.schema/0>, type: VideoSchema.VideoList}, search: %{args: %{query: %{type: %GraphQL.Type.String{description: "The `String` scalar type represents textual data, represented as UTF-8\ncharacter sequences. The String type is most often used by GraphQL to\nrepresent free-form human-readable text.\n", name: "String"}}}, resolve: #Function<1.116378938/3 in VideoSchema.schema/0>, type: VideoSchema.Search}, video: %{args: %{yt_id: %{type: %GraphQL.Type.String{description: "The `String` scalar type represents textual data, represented as UTF-8\ncharacter sequences. The String type is most often used by GraphQL to\nrepresent free-form human-readable text.\n", name: "String"}}}, resolve: &VideoSchema.show_video/3, type: VideoSchema.Video}, viewer: %{resolve: #Function<2.116378938/3 in VideoSchema.schema/0>, type: VideoSchema.Viewer}}, interfaces: [], isTypeOf: nil, name: "Query"}, "String" => %GraphQL.Type.String{description: "The `String` scalar type represents textual data, represented as UTF-8\ncharacter sequences. The String type is most often used by GraphQL to\nrepresent free-form human-readable text.\n", name: "String"}, "Video" => %GraphQL.Type.ObjectType{description: "A YouTube video", fields: %{id: %{description: "The ID of an object", name: "id", resolve: #Function<1.110845899/3 in GraphQL.Relay.Node.global_id_field/1>, type: %GraphQL.Type.NonNull{ofType: %GraphQL.Type.ID{description: "The `ID` scalar type represents a unique identifier, often used to\nrefetch an object or as key for a cache. The ID type appears in a JSON\nresponse as a String; however, it is not intended to be human-readable.\nWhen expected as an input type, any string (such as `\"4\"`) or integer\n(such as `4`) input value will be accepted as an ID.\n", name: "ID"}}}, more_like_this: %{resolve: #Function<0.119064294/3 in VideoSchema.Video.type/0>, type: %{type: VideoSchema.VideoList}}}, interfaces: [], isTypeOf: nil, name: "Video"}, "VideoConnection" => %GraphQL.Type.ObjectType{description: "A connection to a list of items.", fields: %{edges: %{description: "Information to aid in pagination.", type: %GraphQL.Type.List{ofType: %GraphQL.Type.ObjectType{description: "An edge in a connection.", fields: %{cursor: %{description: "A cursor for use in pagination", resolve: nil, type: %GraphQL.Type.NonNull{ofType: %GraphQL.Type.String{description: "The `String` scalar type represents textual data, represented as UTF-8\ncharacter sequences. The String type is most often used by GraphQL to\nrepresent free-form human-readable text.\n", name: "String"}}}, node: %{description: "The item at the end of the edge", resolve: nil, type: VideoSchema.Video}}, interfaces: [], isTypeOf: nil, name: "VideoEdge"}}}, pageInfo: %{description: "Information to aid in pagination.", type: %GraphQL.Type.NonNull{ofType: %GraphQL.Type.ObjectType{description: "Information about pagination in a connection.", fields: %{endCursor: %{description: "When paginating forwards, the cursor to continue.", type: %GraphQL.Type.String{description: "The `String` scalar type represents textual data, represented as UTF-8\ncharacter sequences. The String type is most often used by GraphQL to\nrepresent free-form human-readable text.\n", name: "String"}}, hasNextPage: %{description: "When paginating forwards, are there more items?", type: %GraphQL.Type.NonNull{ofType: %GraphQL.Type.Boolean{description: "The `Boolean` scalar type represents `true` or `false`.\n", name: "Boolean"}}}, hasPreviousPage: %{description: "When paginating backwards, are there more items?", type: %GraphQL.Type.NonNull{ofType: %GraphQL.Type.Boolean{description: "The `Boolean` scalar type represents `true` or `false`.\n", name: "Boolean"}}}, startCursor: %{description: "When paginating backwards, the cursor to continue.", type: %GraphQL.Type.String{description: "The `String` scalar type represents textual data, represented as UTF-8\ncharacter sequences. The String type is most often used by GraphQL to\nrepresent free-form human-readable text.\n", name: "String"}}}, interfaces: [], isTypeOf: nil, name: "PageInfo"}}}}, interfaces: [], isTypeOf: nil, name: "VideoConnection"}, "VideoEdge" => %GraphQL.Type.ObjectType{description: "An edge in a connection.", fields: %{cursor: %{description: "A cursor for use in pagination", resolve: nil, type: %GraphQL.Type.NonNull{ofType: %GraphQL.Type.String{description: "The `String` scalar type represents textual data, represented as UTF-8\ncharacter sequences. The String type is most often used by GraphQL to\nrepresent free-form human-readable text.\n", name: "String"}}}, node: %{description: "The item at the end of the edge", resolve: nil, type: VideoSchema.Video}}, interfaces: [], isTypeOf: nil, name: "VideoEdge"}, "Videos" => %GraphQL.Type.ObjectType{description: "List of Videos", fields: %{max_score: %{resolve: #Function<0.47853847/3 in VideoSchema.VideoList.type/0>, type: %GraphQL.Type.Float{description: "The `Float` scalar type represents signed double-precision fractional\nvalues as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).\n", name: "Float"}}, videos: %{args: %{after: %{type: %GraphQL.Type.String{description: "The `String` scalar type represents textual data, represented as UTF-8\ncharacter sequences. The String type is most often used by GraphQL to\nrepresent free-form human-readable text.\n", name: "String"}}, before: %{type: %GraphQL.Type.String{description: "The `String` scalar type represents textual data, represented as UTF-8\ncharacter sequences. The String type is most often used by GraphQL to\nrepresent free-form human-readable text.\n", name: "String"}}, first: %{type: %GraphQL.Type.Int{description: "The `Int` scalar type represents non-fractional signed whole numeric\nvalues. Int can represent values between -(2^53 - 1) and 2^53 - 1 since\nrepresented in JSON as double-precision floating point numbers specified\nby [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).\n", name: "Int"}}, last: %{type: %GraphQL.Type.Int{description: "The `Int` scalar type represents non-fractional signed whole numeric\nvalues. Int can represent values between -(2^53 - 1) and 2^53 - 1 since\nrepresented in JSON as double-precision floating point numbers specified\nby [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).\n", name: "Int"}}}, resolve: #Function<1.47853847/3 in VideoSchema.VideoList.type/0>, type: %GraphQL.Type.ObjectType{description: "A connection to a list of items.", fields: %{edges: %{description: "Information to aid in pagination.", type: %GraphQL.Type.List{ofType: %GraphQL.Type.ObjectType{description: "An edge in a connection.", fields: %{cursor: %{description: "A cursor for use in pagination", resolve: nil, type: %GraphQL.Type.NonNull{ofType: %GraphQL.Type.String{description: "The `String` scalar type represents textual data, represented as UTF-8\ncharacter sequences. The String type is most often used by GraphQL to\nrepresent free-form human-readable text.\n", name: "String"}}}, node: %{description: "The item at the end of the edge", resolve: nil, type: VideoSchema.Video}}, interfaces: [], isTypeOf: nil, name: "VideoEdge"}}}, pageInfo: %{description: "Information to aid in pagination.", type: %GraphQL.Type.NonNull{ofType: %GraphQL.Type.ObjectType{description: "Information about pagination in a connection.", fields: %{endCursor: %{description: "When paginating forwards, the cursor to continue.", type: %GraphQL.Type.String{description: "The `String` scalar type represents textual data, represented as UTF-8\ncharacter sequences. The String type is most often used by GraphQL to\nrepresent free-form human-readable text.\n", name: "String"}}, hasNextPage: %{description: "When paginating forwards, are there more items?", type: %GraphQL.Type.NonNull{ofType: %GraphQL.Type.Boolean{description: "The `Boolean` scalar type represents `true` or `false`.\n", name: "Boolean"}}}, hasPreviousPage: %{description: "When paginating backwards, are there more items?", type: %GraphQL.Type.NonNull{ofType: %GraphQL.Type.Boolean{description: "The `Boolean` scalar type represents `true` or `false`.\n", name: "Boolean"}}}, startCursor: %{description: "When paginating backwards, the cursor to continue.", type: %GraphQL.Type.String{description: "The `String` scalar type represents textual data, represented as UTF-8\ncharacter sequences. The String type is most often used by GraphQL to\nrepresent free-form human-readable text.\n", name: "String"}}}, interfaces: [], isTypeOf: nil, name: "PageInfo"}}}}, interfaces: [], isTypeOf: nil, name: "VideoConnection"}}}, interfaces: [], isTypeOf: nil, name: "Videos"}}, %{type: VideoSchema.VideoList})

@joshprice
Copy link
Member

joshprice commented Apr 18, 2016

The second argument that function looks wrong: %{type: VideoSchema.VideoList} should be just VideoSchema.VideoList I suspect.

So change type: %{type: VideoList} to type: VideoList.

If that is still broken please open a new issue as this isn't related to the original issue. Or ping me in the GraphQL or Elixir slacks.

@ashleyw
Copy link

ashleyw commented Apr 18, 2016

@joshprice You're right, it should just be type: VideoList, not type: {type: VideoList}. Thank you for your help! 😊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants