0

I'm having real trouble figuring out the way that Graphene Django should be used with react-router-relay. Let's say I can use the following GraphQL query fine via the GraphiQL console on my Django server:

query {
  allThreads {
    edges {
      node {
        id
      }
    }
  }
}

This is presumably Graphene's alternative to the commmon viewer wrapper used because Relay doesn't support connections on root queries. So I understand that allThreads is really a node (of type ThreadNodeConnection), and has an edges connections that I can query.

The trouble is I can't figure out how to use this with Relay, and specifically react-router-relay. I have a React view with a fragment on it like this (with a child Thread component elsewhere):

fragments: {
      store: () => Relay.QL`
        fragment on Query {
          allThreads (first:300) {
            edges {
              node {
                // child's fragment included here
              }
            },
          }
        }
      `,
    },

Webpack checks this against my live schema and likes it. Then I create the following in my index.js for router:

const ViewerQueries = {
  store: () => Relay.QL`query { allThreads(first:300) }`
};

ReactDOM.render(
  <Router
    forceFetch
    environment={Relay.Store}
    render={applyRouterMiddleware(useRelay)}
    history={browserHistory}
  >
    <Route path='/' component={ThreadList} queries={ViewerQueries} />
  </Router>
  , document.getElementById('container')
)

Already I'm feeling a little unsure because I figure I'm doing ViewerQueries wrong, but it's hard to know because everyone else uses this to accommodate their viewer wrapper on their GraphQL connections, but Graphene has a different wrapper on each connection, so this might only work for my single route, but that's okay for now. Webpack likes it against the schema again. But when I load the page, I get a 'bad request' and the error that:

"Fragment F1 cannot be spread here as objects of type ThreadNodeConnection can never be of type Query"

To be honest, that's about where I couldn't proceed, because I'm clearly not understanding something about either how Graphene Django constructs the schema, or how the GraphQL fragments should be written, or how the Route query should be written. Trouble is I can't figure out which of these things is wrong, and there don't seem to be any resources out there around people using these particular combinations of technologies.

For completeness, my Graphene Django schema setup is (slightly simplified):

project/threads/schema.py:

class ThreadNode(DjangoObjectType):
    class Meta:
        model = Thread
        interfaces = (relay.Node, )

...

class Query(graphene.AbstractType):
    all_threads = DjangoFilterConnectionField(ThreadNode)
    thread = relay.Node.Field(ThreadNode, id=graphene.Int())

    def resolve_all_threads(self, args, context, info):
        return Thread.objects.select_related('author__profile').all()

    def resolve_thread(self, args, context, info):
        id = args.get('id')

        if id is not None:
            return Thread.objects.get(pk=id)

        return None

project/schema.py:

class Query(project.threads.schema.Query, graphene.ObjectType):
    pass

schema = graphene.Schema(query=Query)

If anyone has used this particular combination before and has any advice, that'd be amazing.

Chris
  • 57,622
  • 19
  • 111
  • 137
Matthew Johnston
  • 4,409
  • 2
  • 20
  • 27
  • This is not really about graphene. What you are trying to do is use a connection field as a root field. This is not supported in Relay 1, but should be in Relay 2. Full explanation is here: https://github.com/facebook/relay/issues/112 – Yacine Filali Mar 28 '17 at 03:25
  • I don't think that's true and I mention that in the question. Graphene skirts the connection-as-root issue by wrapping all connections, so the connection becomes a node with an edges connection available on it. – Matthew Johnston Mar 28 '17 at 08:06
  • I noticed the line "fragment on Query". Have you tried fragment on ThreadNodeConnection as the error suggests? – Yacine Filali Apr 01 '17 at 06:23

1 Answers1

1

I had this same issue and after a long search i finally found this answer https://github.com/facebook/relay/issues/1558#issuecomment-297010663

Since relay 1 don't support connections as root query. you should ad a viewer as a node interface to wrap your query. So in your server main query (project/schema.py) you should add the following code:

class Query(project.threads.schema.Query, graphene.ObjectType):
   viewer = graphene.Field(lambda: Query)
   id = graphene.ID(required=True)

   def resolve_viewer(self, args, context, info):
    return info.parent_type

   def resolve_id(self, args, context, info):
      return 1

   class Meta:
      interfaces = (graphene.relay.Node,)

Now in you graphiql you can format your query like this:

query {
  viewer{
  allThreads(first:10) {
    edges {
      node {
        id
      }
    }
  }
}
}

In client side you can create your container like this:

export default Relay.createContainer(ThreadList, {
    fragments: {
        viewer: () => Relay.QL`
     fragment on Query {
          id
          allThreads(first:10){
            edges{
              node{
               id
               }
            }
          }
      }
    `,
    },
});

I hope this can help you

reinierpd
  • 11
  • 3