Graphql - call query in graphqlplayground from connected DB - graphql

I'm just starting with graphql and having a few problems calling a basic query in the playground.
I have a server.js
const mongoose = require('mongoose');
require('dotenv').config({ path: 'variables.env' })
const { ApolloServer } = require('apollo-server')
//Monogoose schemas
const Recipe = require('./models/Recipe');
const { typeDefs } = require('./schema');
const { resolvers } = require('./resolvers')
const server = new ApolloServer({
typeDefs,
resolvers
})
// Connect to DB
mongoose
.connect(process.env.MONGO_URI, { autoIndex: false })
.then(() => {
console.log('DB connected')
})
.catch(err => console.error(err))
server.listen().then(({ url }) => {
console.log(`server listening on ${url}`)
})
a schema.js
const gql = require('graphql-tag');
exports.typeDefs = gql`
type Recipe{
_id: ID
name: String!
category: String!
description: String!
instructions: String!
createdDate: String
likes: Int
username: String
}
type Query {
getAllRecipes: [Recipe]
}
`
a resolvers.js
exports.resolvers = {
Query: {
getAllRecipes: async (root, args, { Recipe }) => {
const allRecipes = await Recipe.find()
return allRecipes
}
},
and a mongoose schema
const mongoose = require('mongoose');
const Schema = mongoose.Schema
const RecipeSchema = new Schema({
name: {
type: String,
required: true
},
category: {
type: String,
required: true
},
description: {
type: String,
required: true
},
instructions: {
type: String,
required: true
},
createdDate: {
type: Date,
default: Date.now
},
likes: {
type: Number,
default: 0
},
username: {
type: String
}
})
module.exports = mongoose.model('Recipe', RecipeSchema)
The server and connection to the DB work and when I open the playground the schema is shown. I have data in the DB
When I run query:
query{
getAllRecipes{
name
}
}
I get an error "Cannot read property 'find' of undefined",
Can anyone see what I'm doing wrong here.

On your resolvers.js file you're expecting Recipe to come from the context argument, but you did not add it anywhere from what I can tell from your snippets.
During the initialization of your ApolloServer instance, you can pass a context property that will be injected on all resolvers:
...
const server = new ApolloServer({
typeDefs,
resolvers,
context: {
Recipe,
},
});
The context property can also be a function that returns an object at the end, in case you want something more elaborated.
For more details on the option and also on others you can pass, see: https://www.apollographql.com/docs/apollo-server/api/apollo-server/.

Related

Querying Schema in GraphiQL Sandbox

I am learning graph via a tutorial for work. I think the tutorial is a little out of date but its got some good info so I am trying to keep with it. However my queries dont seem to work the way the video is showing them. Can someone take a look and tell me whats wrong here?
Here is my Schema:
const graphql = require('graphql');
const _ = require('lodash')
const {
GraphQLObjectType,
GraphQLString,
GraphQLInt,
GraphQLSchema
} = graphql
const users = [
{ id: '23', firstName: 'Matt', age: 33 },
{ id: '47', firstName: 'Alexis', age: 28 }
]
const UserType = new GraphQLObjectType({
name: 'User',
fields: {
id: { type: GraphQLString } ,
firstName: { type: GraphQLString },
age: { type: GraphQLInt }
}
});
const RootQuery = new GraphQLObjectType({
name: "RootQueryType",
fields: {
user: {
type: UserType,
args: { id: { type: GraphQLString } },
resovle(parentValue, args) {
return _.find(users, { id: args.id } );
}
}
}
});
module.exports = new GraphQLSchema({
query: RootQuery
});
Here is my query in GraphiQL:
To cover all bases, here is the server.js
const express = require('express');
const expressGraphQL = require('express-graphql').graphqlHTTP;
const schema = require('./schema/schema');
const app = express();
app.use('/graphql', expressGraphQL({
schema,
graphiql: true
}));
app.listen(4000, () => {
console.log('Listening');
});

How to run a mutation in ApolloServer using the GraphQL Playground?

I'm using node.js, express and apollo-server-express. With the following code:
const express = require('express');
const { ApolloServer, gql } = require('apollo-server-express');
const typeDefs = gql`
type Book { title: String author: String }
type Query { books: [Book] }
type Mutation { change_title(new_title: String): Book }
`;
const books = [
{ title: 'The Awakening', author: 'Kate Chopin', },
{ title: 'City of Glass', author: 'Paul Auster', },
];
const resolvers = {
Query: { books: () => books, },
Mutation: {
change_title: (parent, args) => {
books[0].title = args.new_title
return books[0]
}
}
};
const server = new ApolloServer({ typeDefs, resolvers, });
const app = express();
server.applyMiddleware({ app });
app.listen({ port: 4000 }, () =>
console.log(`Server ready at http://localhost:4000${server.graphqlPath}`)
);
When I enter the mutation in the GraphQL Playground, like so:
{
change_title(new_title: "Something") {
title
}
}
I get the following error: "Cannot query field "change_title" on type "Query"."
My goal is to be able to run mutations. If I should be doing it another way or if there's eror, please let me know. Thanks!
GraphQL playground treats all types as queries unless otherwise specified.
mutation {
change_title(new_title: "Something") {
title
}
}

Running Subscriptions on GraphiQL using express-graphql, graphql, graphql-subscriptions and graphql-subscriptions-ws

I'm fairly new to GraphQL and currently familiarizing myself by making a quiz application using React on the front-end.
At the moment, I'm busy with my back-end. After successfully setting up queries and mutations, I am finding it difficult to get subscriptions working. When using GraphiQL, I am getting null as an output instead of "Your subscription data will appear here..."
Queries and the mutation for adding the quiz works.
The entry point of my server, app.js:
const express = require("express");
const mongoose = require("mongoose");
const { graphqlHTTP } = require("express-graphql");
const schema = require("./graphql/schema");
const cors = require("cors");
const port = 4000;
//Subscriptions
const { createServer } = require("http");
const { SubscriptionServer } = require("subscriptions-transport-ws");
const { execute, subscribe } = require("graphql");
const subscriptionsEndpoint = `ws://localhost:${port}/subscriptions`;
const app = express();
app.use(cors());
mongoose.connect("mongodb://localhost/quizify", {
useNewUrlParser: true,
useCreateIndex: true,
useUnifiedTopology: true,
useFindAndModify: false
});
mongoose.connection.once("open", () => console.log("connected to database"));
app.use("/graphql", graphqlHTTP({
schema,
graphiql: true,
subscriptionsEndpoint,
}));
const webServer = createServer(app);
webServer.listen(port, () => {
console.log(`GraphQL is now running on http://localhost:${port}`);
//Set up the WebSocket for handling GraphQL subscriptions.
new SubscriptionServer({
execute,
subscribe,
schema
}, {
server: webServer,
path: '/subscriptions',
});
});
Below is from the schema definitions, schema.js:
const { graphqlHTTP } = require("express-graphql");
const graphql = require("graphql");
const { PubSub } = require("graphql-subscriptions");
const pubsub = new PubSub();
//Import of Mongoose Schemas:
const Quiz = require("../models/quiz");
const {
GraphQLObjectType,
GraphQLList,
GraphQLSchema,
GraphQLNonNull,
GraphQLID,
GraphQLString,
GraphQLBoolean
} = graphql;
const QuizType = new GraphQLObjectType({
name: "Quiz",
fields: () => ({
id: { type: GraphQLID },
title: { type: GraphQLString },
questions: {
type: new GraphQLList(QuestionType),
resolve(parent, args) {
return Question.find({ quizId: parent.id });
}
},
creator: {
type: UserType,
resolve(parent, args) {
return User.findById(parent.creatorId);
}
}
})
});
const NEW_QUIZ_ADDED = "new_quiz_added";
const Subscription = new GraphQLObjectType({
name: "Subscription",
fields: {
quizAdded: {
type: QuizType,
subscribe: () => {
pubsub.asyncIterator(NEW_QUIZ_ADDED);
},
},
}
});
const Mutation = new GraphQLObjectType({
name: "Mutation",
fields: {
createQuiz: {
type: QuizType,
args: {
title: { type: new GraphQLNonNull(GraphQLString) },
creatorId: { type: new GraphQLNonNull(GraphQLID) }
},
resolve(parent, args) {
const newQuiz = new Quiz({ //Quiz imported from Mongoose schema.
title: args.title,
creatorId: args.creatorId,
});
pubsub.publish(NEW_QUIZ_ADDED, { quizAdded }); //NEW_QUIZ_ADDED - a constant defined above for easier referencing.
return newQuiz.save();
}
},
},
});
module.exports = new GraphQLSchema({
query: RootQuery,
mutation: Mutation,
subscription: Subscription,
});
I've looked around, however I'm not finding an method that works for this kind of site. I know it might sound like a simple problem. Any assistance would be greatly appreciated!

"TypeError: Cannot read property 'getAllParts' of undefined at allParts ..\\resolvers.js:6:62)",

I am having trouble figuring out why the object whos property is getting called is undefined. I am using graphql, apollo-server, and the following Data Source type https://github.com/cvburgess/SQLDataSource.
I've searched several posts but nothing I found helped.
I know that is has to do with something not being passed correctly. I just dont understand why it's not being passed correctly.
resolvers.js
const resolvers = {
Query: {
//getPart: (_,{itemnum},{dataSources}) => dataSources.partAPI.getPart({itemnum: itemnum}),
allParts: (_,__,{dataSources}) => dataSources.partAPI.getAllParts(),
},
};
module.exports = resolvers
and here is the rest of my code
Index.js
const { ApolloServer } = require('apollo-server');
const typeDefs = require('./schema');
const resolvers = require ('./resolvers')
const PartAPI = require ('./datasources/part');
const knexConfig = {
client: "sqlite3",
connection: {
/* CONNECTION INFO */
filename: "./TEAM_material.db3"
}
};
const db = new PartAPI(knexConfig);
const server = new ApolloServer({
typeDefs,
resolvers,
dataSources: () => ({db}),
introspection: true,
});
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
Schema.js
const { gql } = require('apollo-server')
const typeDefs = gql`
#Types
type Part {
itemnum: String!
desc: String!
vendor: String!
manuf: String!
venlist: Float!
price: Float!
teamlist: Float!
teamsell: Float!
unitypart: String!
pkgqty: Int!
ioType: String!
preferred: Boolean!
filterlvl1: String!
filterlvl2: String!
filterlvl3: String!
filterlvl4: String!
ipwiretype: String!
opwiretype: String!
obsolete: Boolean!
}
#Queries
type Query {
getPart(itemnum: String!): Part
allParts: [Part!]!
}
`;
module.exports = typeDefs
part.js
const { SQLDataSource } = require("datasource-sql");
const MINUTE = 60;
class PartAPI extends SQLDataSource {
async getPart({itemnum}){
return this.knex.select("*").from("part").where('itemnum', itemnum).cache(60);
}
async getAllParts(){
return this.knex.select("*").from("part").cache(MINUTE);
}
}
module.exports = PartAPI;
#Daniel Rearden. Thank you for the help. From what you said, I was able to deduce that I need to pass this into the APolloServer constructor instead.
const server = new ApolloServer({
typeDefs,
resolvers,
dataSources: () => ({
partAPI: new PartAPI(knexConfig),
}),
introspection: true,
});

Error: Expected [object Object] to be a GraphQL type

This code was working until I added the Resources part into the code. It is similar to the other two so I am not sure why isn't it working.
Thanks in advance
Update:-
After using the debugger, I came to understand that the problem is in the RootQueryType.js and files associated with it as the error pops up when I am trying to export the schema and exactly at the query:RootQueryType place but still can't pinpoint at the error.
Update:-
I have put the schema.js file too in the end
resourceType.js
const graphql = require("graphql");
const UserType = require("./userType");
const User = require("../models/User");
const Project = require("../models/Project");
const Resource = require("../models/Resource");
const ProjectType = require("./projectType");
const {
GraphQLObjectType,
GraphQLString,
GraphQLList,
} = graphql;
const ResourceType = new GraphQLObjectType({
name: "ResourceType",
fields: () => ({
id: { type: GraphQLString },
title: { type: GraphQLString },
url: { type: GraphQLString },
project:{
type:ProjectType,
resolve(parentValues,args){
return Project.findById(parentValues.id).populate("resources")
}
}
})
});
module.exports=ResourceType;
RootQueryType.js
const mongoose = require('mongoose');
const graphql = require('graphql');
const { GraphQLObjectType, GraphQLList, GraphQLID, GraphQLNonNull } = graphql;
const ProjectType = require('./../types/projectType');
const UserType = require('./../types/userType');
const Project=require("../models/Project");
const User=require("../models/User");
const RootQuery=new GraphQLObjectType({
name:"RootQueryType",
fields: () => ({
projects:{
type:new GraphQLList(ProjectType),
resolve(parentValues,args,request){
return Project.find().populate("contributors").populate("resources");
}
},
project:{
type:ProjectType,
args:{id:{type:new GraphQLNonNull(GraphQLID)}},
resolve(parentValue,args,request){
return Project.findById(args.id).populate("contributors").populate("resources");
}
},
users:{
type:new GraphQLList(UserType),
resolve(parentValues,args,request){
return User.find().populate("projects");
}
},
user:{
type:UserType,
args:{id:{type:new GraphQLNonNull(GraphQLID)}},
resolve(parentValue,args,request){
return User.findById(args.id).populate("projects")
}
},
})
})
module.exports = RootQuery;
Mutation.js
const mongoose = require("mongoose");
const ProjectType = require("./../types/projectType");
const UserType = require("./../types/userType");
const graphql = require("graphql");
const {
GraphQLObjectType,
GraphQLList,
GraphQLID,
GraphQLNonNull,
GraphQLString
} = graphql;
const Project = require("../models/Project");
const User = require("../models/User");
const mutation = new GraphQLObjectType({
name: "mutation",
fields: () => ({
addUser: {
type: UserType,
args: {
name: { type: new GraphQLNonNull(GraphQLString) },
username: { type: new GraphQLNonNull(GraphQLString) },
password: { type: new GraphQLNonNull(GraphQLString) },
email: { type: new GraphQLNonNull(GraphQLString) },
githubProfile: { type: new GraphQLNonNull(GraphQLString) }
},
resolve(parentValues, args, request) {
return User.create(args);
}
},
addProject: {
type: ProjectType,
args: {
name: { type: new GraphQLNonNull(GraphQLString) },
description: { type: new GraphQLNonNull(GraphQLString) },
image: { type:GraphQLString },
// contributor:{ type: new GraphQLNonNull(new GraphQLList(GraphQLID))
contributor:{ type: new GraphQLNonNull(GraphQLID)
},
},
resolve(parentValues, args, request) {
return Project.create(args);
}
}
})
});
module.exports = mutation;
I am positive it isnt the problem with other types because they were working earlier and I only added the .populate("resources") property to the resolve function of both of them. But just in case I am adding the code for them too.
userType.js
const graphql = require("graphql");
const ProjectType = require("./projectType");
const { GraphQLObjectType, GraphQLString, GraphQLList } = graphql;
const UserType = new GraphQLObjectType({
name: "User",
fields: () => ({
id: { type: GraphQLString },
name: { type: GraphQLString },
githubProfile: { type: GraphQLString },
username: { type: GraphQLString },
password: { type: GraphQLString },
email: { type: GraphQLString },
projects: {
type: new GraphQLList(ProjectType),
resolve(parentValues, args) {
return User.findById(parentValues.id).populate("projects");
}
}
})
});
module.exports = UserType;
and the other is
projectType.js
const graphql = require("graphql");
const UserType = require("./userType");
const ResourceType = require("./resourceType");
const User = require("../models/User");
const Project = require("../models/Project");
const {
GraphQLObjectType,
GraphQLString,
GraphQLList,
} = graphql;
const ProjectType = new GraphQLObjectType({
name: "ProjectType",
fields: () => ({
id: { type: GraphQLString },
name: { type: GraphQLString },
description: { type: GraphQLString },
image: { type: GraphQLString },
contributors: {
type: new GraphQLList(UserType),
resolve(parentValues, args, request) {
return Project.findContributors(parentValues.id);
}
},
resources:{
type: new GraphQLList(ResourceType),
resolve(parentValues, args, request) {
return Project.findResources(parentValues.id);
}
}
})
});
module.exports=ProjectType;
schema.js
const graphql = require("graphql");
const RootQuery = require("./RootQueryType");
const Mutation = require("./Mutation");
const { GraphQLSchema } = graphql;
console.log(RootQuery,Mutation);
module.exports = new GraphQLSchema({
query: RootQuery,
mutation: Mutation
});
Update:- I have removed the resources files and I am still getting the same error so it must be between user and project types
Update:-I finally tracked down the bug to being in the type files of both project and user type and it is being caused by the new GraphQLList, I still havent solved the error but removing it seems to make the error go away, no idea why.
Finally solved the problem, it was as #cito said, because of circular dependencies that was the cause of the error, that is as my UserType is dependent on ProjectType and likewise and hence I was getting this error, this was solved by
const graphql = require("graphql");
const User = require("../models/User");
const Project = require("../models/Project");
const {
GraphQLObjectType,
GraphQLString,
GraphQLList,
} = graphql;
const ProjectType = new GraphQLObjectType({
name: "ProjectType",
fields: () => ({
id: { type: GraphQLString },
name: { type: GraphQLString },
description: { type: GraphQLString },
image: { type: GraphQLString },
contributors: {
type: new GraphQLList(UserType),
resolve(parentValues, args, request) {
return Project.findContributors(parentValues.id);
}
},
resources:{
type: new GraphQLList(ResourceType),
resolve(parentValues, args, request) {
return Project.findResources(parentValues.id);
}
}
})
});
module.exports=ProjectType;
// This is here to prevent circular dependencies problem which will lead to the formation of infinite loop
const UserType = require("./userType");
const ResourceType = require("./resourceType");
that is requiring the files at the bottom
Your problem is the cyclic dependency between the userType and projectType module. Therefore the const value is still an empty object when it is passed to GraphQLList.
As a solution, you can move all the types into one module. Or, when exporting your classes, set them as properties of module.exports. This will work since you defined the fields properly as thunks.
By the way, you don't need the new when creating a GraphQLList or GraphQLNonNull wrapper. But that's not why you're getting the error.
Another way to go is:
resources:{
// require directly without creating a new variable
type: new GraphQLList(require("./resourceType")),
resolve(parentValues, args, request) {
return Project.findResources(parentValues.id);
}
}
I solved the problem. Just have both objectType in the same file.
I works

Resources