Multiple Filters On Express-GraphQL - javascript

I'm using express-graphql and node-fetch in my application. I am trying to use graphql with my api call to grab data. Currently I am doing
const QueryType = new GraphQLObjectType({
name: "Query",
fields: () => ({
acctsFromRelation: {
type: new GraphQLList(AcctType),
args: {
id: {type: GraphQLString},
status: {type: GraphQLString}
},
resolve: (root, args) => getOpIds(args)
}
})
});
The AcctType is as follows
const AcctType = new GraphQLObjectType({
name: "acct",
fields: () => ({
id: {type: GraphQLString},
name: {type: GraphQLString},
clientType: {type: GraphQLString},
accountStatus: {type: GraphQLString,
args: {
status: {type: GraphQLString}
}},
primaryContact: {type: contactType},
billingAddress: {type: billingType}
})
});
I'm trying to do something like this:
{ acctsFromRelation (id: "2") {
id
name
accountStatus (status: "active")
primaryContact {
firstName
lastName
phone
email
}
billingAddress {
address1
address2
city
state
postalCode
country
}
}
}
where i obtain all accounts with id of 2 and accountStatus of active.
GetOpIds is as follows:
function getOpIds (ids) {
return fetch(API CALL THAT GIVES IDS)
.then(res => res.json())
.then(json => json.map((element) => getAccountByUrl(element.id)))
.catch(err => err)
}
and getAccountByUrl looks like this
function getAccountByUrl (ids) {
return fetch(URL THAT LOOKS UP 1 ID at a TIME)
.then(res => res.json())
.then(json => json)
.catch(err => err)
}

You can try this directly from the code
const query = `query AcctsFromRelation($id: ID, $status: String){acctsFromRelation(id: $id, status: $status)}`;
const variables = { id: id, status: status };
return new Promise((resolve, reject) => {
request("/graphql", query, variables).then(data => {
resolve(data.acctsFromRelation);
});
});

Related

Cannot query field \"addWorkout\" on type \"Mutation\

I am fairly new to GraphQL, my previous question was regarding some reference error I was getting which I eventually resolved, however, now I am getting this error. It seems that I cannot add a workout as it doesn't recognize that it is a mutation field within the schema.
I keep getting the error of
Cannot query field \"addWorkout\" on type \"Mutation\
Anyway, on app.js, this is my code
const express = require("express")
const app = express();
const userSchema = require("./graph-schema/userQueries")
const workoutSchema = require("./graph-schema/workoutQueries")
const mealSchema = require("./graph-schema/mealQueries")
const mongoose = require("mongoose")
const {mergeSchemas} = require("graphql-tools")
//connect to mongoDB atlase database
mongoose.connect("mongodb+srv://Zubair97:superman2008#cluster0-epauj.mongodb.net/test?retryWrites=true&w=majority")
mongoose.connection.once("open", () => {
console.log("Connected to database")
})
const combinedSchemas = mergeSchemas({
schemas: [
userSchema,
mealSchema,
workoutSchema
],
})
//this module allows express to communicate with graphql ;
//we use it as a single endpoint
const graphqlHTTP = require("express-graphql")
app.use("/graphql" , graphqlHTTP({
schema: combinedSchemas,
graphiql: true
}))
app.listen(4000, () => {
console.log(`Listening on port 4000`)
})
The workout queries and mutations are defined in a file called workoutQueries.js, which I have exported, you can see that I have addWorkout defined in the resolvers
const graphql = require("graphql")
const {WorkoutType} = require("./schema")
const Workout = require("../models/Workout.js")
const {GraphQLObjectType, GraphQLID, GraphQLString, GraphQLSchema, GraphQLInt, GraphQLList} = graphql;
const WorkoutQuery = new GraphQLObjectType({
name: "WorkoutQuery",
fields: () => ({
workout: {
type: WorkoutType,
args: {id: {type: GraphQLID}},
resolve(parent, args){
//returns the workout instance from the database
return Workout.findById(args.id)
}
},
workouts: {
type: new GraphQLList(WorkoutType),
resolve(parent, args){
//returns all workouts from the databse
return Workout.find({})
}
}
})
})
const WorkoutMutation = new GraphQLObjectType({
name: "WorkoutMutation",
addWorkout: {
type: WorkoutType,
args: {
name: {type: GraphQLString},
reps: {type: GraphQLInt},
sets: {type: GraphQLInt},
burnedCalories: {type: GraphQLInt},
userId: {type: GraphQLID},
},
resolve(parent, args){
let workout = new Workout({
name: args.name,
reps: args.reps,
sets: args.sets,
burnedCalories: args.burnedCalories,
userId: args.userId
})
return workout.save();
}
},
})
module.exports = new GraphQLSchema({
query: WorkoutQuery,
mutation: WorkoutMutation
})
Also, this issue is occurring even if I try to add a meal, the queries and mutations are defined at a file called mealQueries.js, which I have exported
const graphql = require("graphql")
const {MealType, NutritionType} = require("./schema")
const Meal = require("../models/Meal.js")
const {GraphQLObjectType, GraphQLID, GraphQLString, GraphQLSchema, GraphQLInt, GraphQLList} = graphql;
const MealQuery = new GraphQLObjectType({
name: "MealQueries",
fields: () => ({
meal: {
type: MealType,
args: {id: {type: GraphQLID}},
resolve(parent, args){
return Meal.findById(args.id)
}
},
meals: {
type: new GraphQLList(MealType),
resolve(parent, args){
return Meal.find({})
}
}
})
})
const MealMutation = new GraphQLObjectType({
name: "MealMutation",
addMeal: {
type: MealType,
args: {
name: {type: GraphQLString},
servings: {type: GraphQLInt},
calories: {type: GraphQLInt},
nutrition: {type: NutritionType},
userId: {type: GraphQLID}
},
resolve(parent, args){
let meal = new Meal({
userId: args.userId,
name: args.name,
servings: args.servings,
calories: args.calories,
nutrition: {
carbohydrates: args.nutrition.carbohydrates,
fats: args.nutrition.fats,
proteins: args.nutrition.proteins
}
})
return meal.save();
}
}
})
module.exports = new GraphQLSchema({
query: MealQuery,
mutation: MealMutation
})
I have no issue in creating a user and authenticating a user, the queries and mutation for that are defined in userQueries.js
const graphql = require("graphql")
const User = require("../models/User.js")
const bcrypt = require("bcrypt")
const jwt = require("jsonwebtoken")
const {AuthType, UserType} = require("./schema")
const {GraphQLObjectType, GraphQLID, GraphQLString, GraphQLSchema, GraphQLInt, GraphQLList} = graphql;
const UserQuery = new GraphQLObjectType({
name: "UserQuery",
fields: () => ({
user: {
type: UserType,
args: {id: {type: GraphQLID}},
resolve(parent, args){
//returns the user from the database
return User.findById(args.id)
}
},
login: {
type: AuthType,
args: {email: {type: GraphQLString}, password: {type: GraphQLString}},
resolve(parent, {email, password}){
return User.findOne({email: email}).then((user) => {
const isEqual = bcrypt.compare(password, user.password)
if (!isEqual) {
throw new Error('Password is incorrect!');
}
const token = jwt.sign({
userId: user.id,
email: user.email},
"a_super_secret",
{expiresIn: "1h"}
)
return {token: token, userId: user.id}
})
}
}
})
})
const UserMutation = new GraphQLObjectType({
name: "Mutation",
fields: {
addUser: {
type: UserType,
args: {
name: {type: GraphQLString},
email: {type: GraphQLString},
password: {type: GraphQLString}
},
async resolve(parent, args){
const existingUser = await User.findOne({email: args.email})
if (!existingUser){
const error = new Error("User already exists");
}
const encryptedPassword = await bcrypt.hash(args.password, 12)
let user = new User({
name: args.name,
email: args.email,
password: encryptedPassword
})
const createdUser = user.save();
return createdUser
}
}
}
})
module.exports = new GraphQLSchema({
query: UserQuery,
mutation: UserMutation,
})
I have also defined the UserType, AuthType, MealType, NutritionType and WorkoutType in a file called schema.js
const graphql = require("graphql")
const Workout = require("../models/Workout.js")
const User = require("../models/User.js")
const Meal = require("../models/Meal")
const {GraphQLObjectType, GraphQLID, GraphQLString, GraphQLSchema, GraphQLInt, GraphQLList} = graphql;
//describes what attributes and its types, a User has in each query
const UserType = new GraphQLObjectType({
name: "User",
fields: () => ({
id: {type: GraphQLID},
name: {type: GraphQLString},
email: {type: GraphQLString},
password: {type: GraphQLString},
workouts: {
type: new GraphQLList(WorkoutType),
resolve(parent, args){
//returns all the workouts created by a user
return Workout.findById({userId: parent.id})
}
},
meals: {
type: new GraphQLList(MealType),
resolve(parent, args){
//returns all the meals created by a user
return Meal.findById({userId: parent.id})
}
}
})
})
const NutritionType = new GraphQLObjectType({
name: "Nutrition",
fields: () => ({
carbohydrates: {type: GraphQLInt},
fats: {type: GraphQLInt},
proteins: {type: GraphQLInt}
})
})
const WorkoutType = new GraphQLObjectType({
name: "Workout",
fields: () => ({
id: {type: GraphQLID},
name: {type: GraphQLString},
reps: {type: GraphQLInt},
burnedCalories: {type: GraphQLInt},
sets: {type: GraphQLInt},
user: {
type: UserType,
resolve(parent, args){
//returns the user from the database that created the workout instance
return User.findById(parent.userId)
}
}
})
})
const AuthType = new GraphQLObjectType({
name: "Authentication",
fields: () => ({
token: {type: GraphQLString},
userId: {type: GraphQLString}
})
})
const MealType = new GraphQLObjectType({
name: "Meal",
fields: () => ({
id: {type: GraphQLID},
calories: {type: GraphQLInt},
servings: {type: GraphQLInt},
nutrition: {type: NutritionType},
user: {
type: UserType,
resolve(parent, args){
//returns the user from the database that created the meal instance
return User.findById(parent.userId)
}
}
})
})
module.exports = {
AuthType,
WorkoutType,
UserType,
MealType,
NutritionType
}
I suspect the error I am getting is due to mergeSchema object from graphql-tools, maybe it cannot merge the GraphQLSchema types properly? I am not sure. Any help is appreciated!
mergeSchemas is intended to be used with schema stitching. It should not be used just to modularize your single schema, which is what you're trying to do here.
You should only create a single GraphQLSchema object, a single GraphQLObjectType for your query root type and a single GraphQLObjectType for your mutation root type. If you want the fields for a specific type, like your Mutation type, to be spread across multiple modules, then you should export just those fields, not an entire type or schema.
module.exports = {
queries: {
workout: { ... },
workouts: { ... },
},
mutations: {
addWorkout: { ... },
},
}
Whatever file you create your schema in can then import these fields from multiple modules and combine them into an individual schema.
const query = new GraphQLObjectType({
name: 'Query',
fields: () => ({
...require('moduleA').queries,
...require('moduleB').queries,
...require('moduleC').queries,
}),
})
const mutation = new GraphQLObjectType({ ... })
const schema = new GraphQLSchema({ query, mutation })

Firebase SnapShot.val() returns null when trying to access data in vuex

I'm Creating an Application where student, staff and non-teaching staff can access.
my Form Data looks like this:
formData: {
name: "",
email: "",
password: "",
select: null
},
options: ["Student", "Staff", "Non-Teaching Staff"],
Of course in Vuex store i can register user with:
registerUsers({}, payload) {
firebaseAuth.createUserWithEmailAndPassword(payload.email, payload.password)
.then(res => {
const userId = firebaseAuth.currentUser.uid;
console.log(res)
Notify.create({
message: 'Regsitration Successful!.',
color: 'primary',
classes: 'quick'
})
//set student
firebaseDb.ref(`users/'${userId}`).set({
name: payload.name,
email: payload.email,
select: payload.select
});
})
.catch(err => {
console.log(err)
Notify.create({
message: `${err.message}`,
classes: 'quick',
color: 'negative'
})
})
I can also loginUsers with:
loginUsers({}, payload) {
firebaseAuth.signInWithEmailAndPassword(payload.email, payload.password)
.then(res => {
console.log(res);
Notify.create({
message: 'Success!',
classes: 'quick',
color: 'positive'
})
})
.catch(err => {
console.log();
Notify.create({
message: `${err.message}`,
classes: 'quick',
color: 'negative'
})
})
},
The Probems comes from this :
handleAuthStateChange() {
firebaseAuth.onAuthStateChanged(user => {
if (user) {
//set Student
const studentId = firebaseAuth.currentUser.uid;
console.log(studentId)
firebaseDb.ref(`users/${studentId}`).once('value', snapshot => {
console.log(snapshot.val())
})
}
})
},
The Snapshot.val() return null in the console.
What i'm i writing wrong please.
It seems that, by calling firebaseDb.ref(`users/'${userId}`).set({...}) you are creating your user under a node
users/'userId
with a single quote (').
And you try to read the node
users/userId
which does not exists, if the assumption that you mistakenly added a single quote is right.
In addition note that you don't need to do
firebaseAuth.createUserWithEmailAndPassword(payload.email, payload.password)
.then(res => {
const userId = firebaseAuth.currentUser.uid;
//...
because createUserWithEmailAndPassword() returns a UserCredential. So you can do:
firebaseAuth.createUserWithEmailAndPassword(payload.email, payload.password)
.then(res => {
const userId = res.user.uid;
//...
and also that you can do:
handleAuthStateChange() {
firebaseAuth.onAuthStateChanged(user => {
if (user) {
const studentId = user.uid;
//......

Search for particular results with a certain string in GraphQL

I want to search with my query getFoodType to return results based on whether the foodType of particular restaurant/takeaway is a "Chicken","Pizza" etc
Like this foodType: "Chicken"
I've tried using arguments and mongoDB filters (it's a MongoDB server) but no luck.
Schema
const EaterySchema = new Schema({
name: {
type: String,
required: true
},
address: {
type: String,
required: true
},
foodType: {
type: String,
required: true
}
});
My Schema Types
type Eatery {
id: String!
name: String!
address: String!
foodType: String!
}
type Query {
eatery(id: String!): Eatery
eateries: [Eatery]
getFoodType(foodType: String): [Eatery]
}
My Resolver
getFoodType: () => {
return new Promise((resolve, reject) => {
Eatery.find({})
.populate()
.exec((err, res) => {
err ? reject(err) : resolve(res);
});
});
},
Current Query in Apollo Playground
{
getFoodType (foodType: "Chicken") {
id
name
address
foodType
}
}
I essentially want to return all the results with "Chicken" as a the foodType. Something like foodType: "Chicken".
First, you need to get the value of the foodType to be queried in Resolver
const resolvers = {
Query: {
getFoodType: (_, args) => {
const { foodType } = args
...
},
},
}
Then use foodType when querying
Eatery.find({ foodType })
Finally need to return the result
new Promise((resolve, reject) => {
return Eatery.find({ foodType })
.populate()
.exec((err, res) => {
err ? reject(err) : resolve(res)
})
})
Complete example
const resolvers = {
Query: {
getFoodType: (_, args) => {
const { foodType } = args
return new Promise((resolve, reject) => {
return Eatery.find({ foodType })
.populate()
.exec((err, res) => {
err ? reject(err) : resolve(res)
})
})
},
},
}
Use the async/await
const resolvers = {
Query: {
getFoodType: async (_, { foodType }) => {
try {
const eaterys = await Eatery.find({ foodType }).populate()
return eaterys
} catch (e) {
// Handling errors
}
},
},
}

How do I fetch a model object by a nested value?

I'm new to GraphQL so I'm doing my first query and I'm trying to query for a nested key, email
Here is my schema
const UserLogin = new GraphQLObjectType({
name: 'UserLoginType',
fields: () => ({
login: { type: GraphQLString },
email: { type: GraphQLString },
}),
});
exports.UserType = new GraphQLObjectType({
name: 'UserType',
fields: () => ({
id: NotNullStringType,
name: { type: GraphQLString },
state: { type: GraphQLString },
login: { type: UserLogin },
}),
});
And what I'm trying to do is build a query that takes an email and searches for the UserType.login.email value and return the first value that matches that email or null.
Thanks!
Edit: In my redux/actions.js file I added:
export const fetchLoginsByEmail = (userEmail) => {
return createGraphqlAction(
{
query: `
query fetchUserByEmail($userEmail: String!) {
fetchUserByEmail(email: $userEmail) {
login {
email
}
state
name
id
}
}
`,
variables: {
userEmail,
}
},
FETCH_LOGINS_BY_EMAIL,
);
};
And in my query.js file I have this in my model.exports object:
fetchUserByEmail: {
type: UserType,
resolve: async (source, args, { user, loginId }) => {
if (!user) {
return null;
}
return serailize({
...user,
login: await getLogin(loginId),
});
},
},
It looks like you're missing the arguments parameter for your query resolver.
Update your query.js into something like:
fetchUserByEmail: {
type: UserType,
args: {
email { type: GraphQLString }
},
resolve: async (source, args, { user, loginId }) => {
// You can now use args.email here and filter your results with it
console.log(args.email);
if (!user) {
return null;
}
return serailize({
...user,
login: await getLogin(loginId),
});
},
},

GraphQL: Rootquery returns null [duplicate]

This question already has answers here:
Why does a GraphQL query return null?
(6 answers)
Closed 3 years ago.
I want to have a rootquery that returns every row within my table. But currently when I call that rootquery I only receive null. But one of my rootquery that only returns one row with a specific id does work. So where i am going wrong?
Rootquery's:
This one works
aanvraag:{
type: AanvraagType,
args:{id: {type: GraphQLID}},
resolve(parentValue, args){
const query = `SELECT * FROM aanvraag where id=${args.id}`;
return db.conn.one(query)
.then(data => {
return data;
})
.catch(err => {
return 'Error is: ', err
});
}
},
This one doesn't work
aanvragen:{
type: AanvraagType,
resolve(parentValue, args){
const query = 'SELECT * from aanvraag';
return db.conn.many(query)
.then(data => {
return data;
})
.catch(err => {
return 'Error is: ', err
});
}
}
This is the whole file if someone needs it:
const graphql = require('graphql');
const pgp = require('pg-promise')();
const axios = require('axios');
const db = {}
var cn = {
host: 'localhost', // server name or IP address;
port: 5432,
database: 'admin',
user: 'admin',
password: 'admin123'
};
db.conn = pgp(cn);
const {
GraphQLObjectType,
GraphQLID,
GraphQLString,
GraphQLSchema
} = graphql;
const TeamlidType = new GraphQLObjectType({
name: 'Teamlid',
fields: {
id: { type: GraphQLID },
email: { type: GraphQLString },
naam: { type: GraphQLString }
}
})
const ProjectType = new GraphQLObjectType({
name: 'Project',
fields:{
id: {type: GraphQLID},
naam: { type: GraphQLString },
type: { type: GraphQLString },
lead_naam: { type: GraphQLString },
lead_email: { type: GraphQLString },
teamlid:{
type: TeamlidType,
resolve(parentValue, args){
console.log(parentValue.id);
const query = `SELECT * FROM teamlid WHERE project_id=${parentValue.id}`;
return db.conn.many(query)
.then(data => {
return data;
})
.catch(err => {
return 'The error is', err;
});
}
}
}
})
const AanvraagType = new GraphQLObjectType({
name: 'Aanvraag',
fields:{
id: {type: GraphQLID},
naam: { type: GraphQLString },
email: { type: GraphQLString },
divisie: { type: GraphQLString },
afdeling: { type: GraphQLString },
team: { type: GraphQLString },
project:{
type: ProjectType,
resolve(parentValue, args){
const query = `SELECT * FROM project WHERE aanvraag_id=${parentValue.id}`;
return db.conn.one(query)
.then(data => {
return data;
})
.catch(err => {
return 'The error is', err;
});
}
}
}
})
const RootQuery = new GraphQLObjectType({
name: 'RootQueryType',
fields: {
teamlid: {
type: TeamlidType,
args: { id: { type: GraphQLID } },
resolve(parentValue, args) {
const query = `SELECT * FROM teamlid WHERE id=${args.id}`;
return db.conn.one(query)
.then(data => {
return data;
})
.catch(err => {
return 'The error is', err;
});
}
},
aanvraag:{
type: AanvraagType,
args:{id: {type: GraphQLID}},
resolve(parentValue, args){
const query = `SELECT * FROM aanvraag where id=${args.id}`;
return db.conn.one(query)
.then(data => {
return data;
})
.catch(err => {
return 'Error is: ', err
});
}
},
project:{
type: ProjectType,
args:{id: {type: GraphQLID}},
resolve(parentValue, args){
const query = `SELECT * FROM project where id=${args.id}`;
return db.conn.one(query)
.then(data => {
return data;
})
.catch(err => {
return 'Error is: ', err
});
}
},
aanvragen:{
type: AanvraagType,
resolve(parentValue, args){
const query = 'SELECT * from aanvraag';
return db.conn.many(query)
.then(data => {
return data;
})
.catch(err => {
return 'Error is: ', err
});
}
}
}
})
module.exports = new GraphQLSchema({
query: RootQuery,
mutation
})
So I already found my answer. I had to wrap 'aanvraag' in an GraphQLList. So this would work:
aanvragen:{
type: GraphQLList(AanvraagType),
resolve(){
const query = 'SELECT * from aanvraag';
return db.conn.many(query)
.then(data => {
return data;
})
.catch(err => {
return 'Error is: ', err
});
}
}
I am new to GrapQL but i hope this will help someone in the future.

Categories

Resources