I've been working with reactjs a fair bit and thought I'd start playing around with graphql and relay. I've hit an error that I can't get to the bottom of, so I wondered if anyone on here may have encountered the same. Any pointers or ideas would be welcomed.
The error I am getting is
Error: GraphQL validation/transform error ``Object has no method 'find'`` in file `/Users/chris/Documents/App/site/js/main.js`.
So I have a GraphQL server running and everything works fine I can query the backend database (I'm using mongodb) and the following query produces the correct results through the graphql ui
{
store{
items{
_id
title
sub
}
}
}
produces the following output which is correct
{
"data": {
"store": {
"items": [
{
"_id": "56e2c71d150040c491c73b26",
"title": "Test Item One",
"sub": "sub title here"
}
]
}
}
}
So I think its safe to assume the the graphql server is fine and the problem must be with my implementation of relay or the babelRelayPlugin.js
The following is the main.js file with the render method simplified.
import React from 'react';
import Relay from 'react-relay';
class Main extends React.Component {
render(){
return (
<div>
<p>Test</p>
</div>
);
}
}
Main = Relay.createContainer(Main, {
fragments:{
store: () => Relay.QL`
fragment on Store {
items {
title,
}
}
`
}
});
export default Main;
The following is the App.js file
import React from 'react';
import ReactDOM from 'react-dom';
import Relay from 'react-relay';
import Main from './main'
//React.render(<Main />, document.getElementById('react-main-mount'));
class HomeRoute extends Relay.Route {
static routeName = 'Home';
static queries = {
store:(Component) => Relay.QL`
query MainQuery {
store { ${Component.getFragment('store')}}
}`
}
};
ReactDOM.render(<Relay.RootContainer
Component={Main}
route={new HomeRoute()}
/>,
document.getElementById('react-main-mount')
);
For completeness here is the schema.js I'm using.
import { GraphQLSchema,
GraphQLObjectType,
GraphQLList,
GraphQLInt,
GraphQLString
} from 'graphql';
// Schema allows us to use node feature to link the schema to the database
let Schema = (db) => {
let store = {};
let storeType = new GraphQLObjectType({
name:'Store',
fields:() => ({
items: {
type: new GraphQLList(itemType),
resolve:() => db.collection("Item").find({}).toArray()
}
})
});
let itemType = new GraphQLObjectType({
name: 'Item',
fields:() =>({
_id:{type: GraphQLString},
title: {type: GraphQLString},
sub:{type:GraphQLString},
type:{type:GraphQLString},
comments:{type:GraphQLInt}
})
});
let schema = new GraphQLSchema({
query: new GraphQLObjectType({
name:'Query',
fields: () => ({
store: {
type: storeType,
resolve: () => store
}
})
}),
});
return schema;
};
export default Schema;
which is converted to JSON on by the server shown here
let app = express();
app.use(express.static('site')); // public folder
console.log("Starting Server");
//mongo url is the server
(async () => {
try{
let db = await MongoClient.connect("mongodb://localhost:27017/App");
let schema = Schema(db);
app.use('/graphql', GraphQLHTTP({
schema,
graphiql:true
}));
app.listen(3000, () => console.log('listening on port 3000'));
// Generate Schema
let json = await graphql(schema, introspectionQuery);
fs.writeFile('./database/schema.json', JSON.stringify(json,null,2), err => {
if(err) throw err;
console.log("JSON schema created");
});
}catch(e){
console.log(e);
}
})();
And the babelRelayPlugin.js is below
var getBabelRelayPlugin = require('babel-relay-plugin');
var schemaData = require('./database/schema.json').data;
module.exports = getBabelRelayPlugin(schemaData);
And Webpack.config
module.exports = {
entry:'./site/js/app.js',
output:{
path: __dirname + "/site",
filename: "bundle.js"
},
module:{
loaders:[
{test:/\.js$/, exclude:/node_modules/, loader: 'babel-loader',
query: {presets: ['react', 'es2015', 'stage-0'],
plugins: ['./babelRelayPlugin']
}
}
]
}
}
UPDATE: So I've had a little play around and the problem lies in the main.js RelayQL statement
Main = Relay.createContainer(Main, {
fragments:{
store: () => Relay.QL`
fragment on Store {
items {
title,
}
}
`
}
});
I commented out the code in app.js and replaced it with the following code as a test to see if basic a basic relay query worked and it did by returning the correct output to the console
ReactDOM.render(<Main />, document.getElementById('react-main-mount'));
console.log(Relay.QL`query store { store{ items {title}}}`);
So as I mentioned above the issue must be I suspect with the really statement in main.js, now the question is why?
For total completeness I have included the full error stack trace below
-- Relay Transform Error -- main --
File: /Users/chris/Documents/App/site/js/main.js
Error: TypeError: Object has no method 'find'
at new RelayQLFragment (/Users/chris/Documents/App/node_modules/babel-relay-plugin/lib/RelayQLAST.js:143:49)
at RelayQLTransformer.processDocumentText (/Users/chris/Documents/App/node_modules/babel-relay-plugin/lib/RelayQLTransformer.js:156:16)
at RelayQLTransformer.transform (/Users/chris/Documents/App/node_modules/babel-relay-plugin/lib/RelayQLTransformer.js:67:29)
at PluginPass.TaggedTemplateExpression (/Users/chris/Documents/App/node_modules/babel-relay-plugin/lib/getBabelRelayPlugin.js:124:36)
at newFn (/Users/chris/Documents/App/node_modules/babel-traverse/lib/visitors.js:262:19)
at NodePath._call (/Users/chris/Documents/App/node_modules/babel-traverse/lib/path/context.js:63:18)
at NodePath.call (/Users/chris/Documents/App/node_modules/babel-traverse/lib/path/context.js:47:17)
at NodePath.visit (/Users/chris/Documents/App/node_modules/babel-traverse/lib/path/context.js:93:12)
at TraversalContext.visitQueue (/Users/chris/Documents/App/node_modules/babel-traverse/lib/context.js:146:16)
at TraversalContext.visitSingle (/Users/chris/Documents/App/node_modules/babel-traverse/lib/context.js:115:19)
at TraversalContext.visit (/Users/chris/Documents/App/node_modules/babel-traverse/lib/context.js:178:19)
at Function.traverse.node (/Users/chris/Documents/App/node_modules/babel-traverse/lib/index.js:135:17)
at NodePath.visit (/Users/chris/Documents/App/node_modules/babel-traverse/lib/path/context.js:103:22)
at TraversalContext.visitQueue (/Users/chris/Documents/App/node_modules/babel-traverse/lib/context.js:146:16)
at TraversalContext.visitMultiple (/Users/chris/Documents/App/node_modules/babel-traverse/lib/context.js:110:17)
at TraversalContext.visit (/Users/chris/Documents/App/node_modules/babel-traverse/lib/context.js:176:19)
at Function.traverse.node (/Users/chris/Documents/App/node_modules/babel-traverse/lib/index.js:135:17)
at NodePath.visit (/Users/chris/Documents/App/node_modules/babel-traverse/lib/path/context.js:103:22)
at TraversalContext.visitQueue (/Users/chris/Documents/App/node_modules/babel-traverse/lib/context.js:146:16)
at TraversalContext.visitSingle (/Users/chris/Documents/App/node_modules/babel-traverse/lib/context.js:115:19)
at TraversalContext.visit (/Users/chris/Documents/App/node_modules/babel-traverse/lib/context.js:178:19)
at Function.traverse.node (/Users/chris/Documents/App/node_modules/babel-traverse/lib/index.js:135:17)
at NodePath.visit (/Users/chris/Documents/App/node_modules/babel-traverse/lib/path/context.js:103:22)
at TraversalContext.visitQueue (/Users/chris/Documents/App/node_modules/babel-traverse/lib/context.js:146:16)
at TraversalContext.visitSingle (/Users/chris/Documents/App/node_modules/babel-traverse/lib/context.js:115:19)
at TraversalContext.visit (/Users/chris/Documents/App/node_modules/babel-traverse/lib/context.js:178:19)
at Function.traverse.node (/Users/chris/Documents/App/node_modules/babel-traverse/lib/index.js:135:17)
at NodePath.visit (/Users/chris/Documents/App/node_modules/babel-traverse/lib/path/context.js:103:22)
at TraversalContext.visitQueue (/Users/chris/Documents/App/node_modules/babel-traverse/lib/context.js:146:16)
at TraversalContext.visitMultiple (/Users/chris/Documents/App/node_modules/babel-traverse/lib/context.js:110:17)
In your HomeRoute:
class HomeRoute extends Relay.Route {
static routeName = 'Home';
static queries = {
store:(Component) => Relay.QL`
query MainQuery {
store { ${Component.getFragment('store')}}
}`
}
};
Have you tried just:
static queries = {
store:() => Relay.QL`
query MainQuery {
store
}`
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With