0
votes

So I'm trying to create a User collection in MongoDB and make queries to it using GraphQL and mongoose.

I've created my user schema in the path 'pathToServer\server\models\user.js' and it looks like this:

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const userSchema = new Schema({
    name: {
        firstName: String,
        lastName: String,
    },
    email: String,
    password: String,
})

module.exports = mongoose.model('User', userSchema);

And I've created a GraphQL type, currently I have it in the path 'pathToServer\server\schema\types\user.js' and it looks like this:

const graphql = require('graphql');

const {GraphQLObjectType, GraphQLList, GraphQLInt, GraphQLID, GraphQLString, GraphQLSchema, GraphQLNonNull} = graphql;

const UserType = new GraphQLObjectType({
    name: 'User',
    fields: () => ({
        id: {type: GraphQLID},
        email: {type: GraphQLString},
        name: new GraphQLObjectType({
            firstName: {type: GraphQLString},
            lastName: {type: GraphQLString}
        })
    })
});

module.exports = UserType;

Finally I have the GraphQL schema with the queries and mutation in the path 'pathToServer\server\schema\schema.js' :

const graphql = require('graphql');

const {GraphQLObjectType, GraphQLList, GraphQLInt, GraphQLID, GraphQLString, GraphQLSchema, GraphQLNonNull} = graphql;

const User = require('../models/user');

const UserType = require('./types/user');

const RootQuery = new GraphQLObjectType({
    name: 'RootQueryType',
    fields: {
        user: {
            type: UserType,
            args: {
                id: {
                    type: GraphQLID
                }
            },
            resolve(parent, args){
                return User.findById(args.id);
            }
        },
        users: {
            type: new GraphQLList(UserType),
            resolve(parent, args){
                return User.find({})
            }
        }
    }
})

const Mutation = new GraphQLObjectType({
    name: 'Mutation',
    fields: {
        addUser: {
            type: UserType,
            args: {
                name: {
                    firstName: {type: new GraphQLNonNull(GraphQLString)},
                    lastName: {type: new GraphQLNonNull(GraphQLString)}
                },
                email: {type: new GraphQLNonNull(GraphQLString)},
                password: {type: new GraphQLNonNull(GraphQLString)}
            },
            resolve(parent, args){
                let user = new User({
                    name: args.name,
                    email: args.email,
                    password: args.password,
                });

                return user.save();
            }
        }
    }
})


module.exports = new GraphQLSchema({
    query: RootQuery,
    mutation: Mutation
})

The problem is that it throws me an error whenever I start the server saying:

Error: Must provide name.
    at invariant (pathToServer\server\node_modules\graphql\jsutils\invariant.js:19:11)
    at new GraphQLObjectType (pathToServer\server\node_modules\graphql\type\definition.js:499:66)
    at fields (pathToServer\server\schema\types\user.js:10:15)
    at resolveThunk (pathToServer\server\node_modules\graphql\type\definition.js:370:40)
    at defineFieldMap (pathToServer\server\node_modules\graphql\type\definition.js:532:18)
    at GraphQLObjectType.getFields (pathToServer\server\node_modules\graphql\type\definition.js:506:44)
    at typeMapReducer (pathToServer\server\node_modules\graphql\type\schema.js:232:38)
    at pathToServer\server\node_modules\graphql\type\schema.js:239:20
    at Array.forEach (<anonymous>)
    at typeMapReducer (pathToServer\server\node_modules\graphql\type\schema.js:232:51)
    at Array.reduce (<anonymous>)
    at new GraphQLSchema (pathToServer\server\node_modules\graphql\type\schema.js:122:28)
    at Object.<anonymous> (pathToServer\server\schema\schema.js:79:18)
    at Module._compile (module.js:652:30)
    at Object.Module._extensions..js (module.js:663:10)
    at Module.load (module.js:565:32)

Maybe I don't have the name field correctly defined? I think that it may be treated differently since the name field in my model is an object containing fields firstName and lastName.

Can you take a look, please?

Thanks in advance!

EDIT I've edit the user type from

const UserType = new GraphQLObjectType({
    name: 'User',
    fields: () => ({
        id: {type: GraphQLID},
        email: {type: GraphQLString},
        name: new GraphQLObjectType({
            firstName: {type: GraphQLString},
            lastName: {type: GraphQLString}
        })
    })
});

to

const UserType = new GraphQLObjectType({
    name: 'User',
    fields: () => ({
        id: {type: GraphQLID},
        email: {type: GraphQLString},
        name: {
            firstName: {type: GraphQLString},
            lastName: {type: GraphQLString}
        }
    })
});

Now the server starts, but it gives me this error in graphiql:

{
  "errors": [
    {
      "message": "The type of User.name must be Output Type but got: undefined.\n\nThe type of Mutation.addUser(name:) must be Input Type but got: undefined."
    }
  ]
}
1

1 Answers

2
votes

You were on the right track with your original attempt. Part of the problem is that the type you're passing to the name field of your UserType needs to be fully defined. That is, it needs not only a fields property but also a name property itself. The other issue is that User.name needs to have its type set explicitly as a property. For readability and reuse, I would make your NameType a separate variable:

const NameType = new graphQLObjectType({
  name: 'Name',
  fields: () => ({
    firstName: { type: GraphQLString },
    lastName: { type: GraphQLString },
  }),
})

const UserType = new GraphQLObjectType({
  name: 'User',
  fields: () => ({
    id: { type: GraphQLID },
    email: { type: GraphQLString },
    name: { type: NameType }
  })
})