How to set argument optional in Graphql? - graphql

In my mongodb model, name is required but i want to make it optional in graphql. How can i do this?
updateExercise: {
type: ExerciseType,
args: {
id: {type: new GraphQLNonNull(GraphQLString)},
username: {type: new GraphQLString},
description: {type: new GraphQLString},
duration: {type: new GraphQLInt},
date: {type: new GraphQLString}
},
resolve(parent, args) {
Exercise.findByIdAndUpdate(args.id)
.then(exercise => {
exercise.username = args.username,
exercise.description = args.description,
exercise.duration = args.duration,
exercise.date = args.date
exercise.save()
.then( () => 'Succesfully Updated')
.catch( e => console.log(e) )
})
}
}

You are misusing the findByIdAndUpdate function. It should probably be used in this way:
const SomeType = new GraphQLObjectType({
updateExercise: {
type: ExerciseType,
args: {
id: {type: new GraphQLNonNull(GraphQLString)},
username: {type: GraphQLString},
description: {type: GraphQLString},
duration: {type: GraphQLInt},
date: {type: GraphQLString}
},
resolve(parent, args) {
return Exercise.findByIdAndUpdate(args.id, {
username: args.username || undefined,
description: args.description,
duration: args.duration,
date: args.date
}).then(() => 'Succesfully Updated')
.catch(e => console.log(e))
})
}
}
});
We use a little trick in JS to short-circuit the returned value. This will supply undefined for the username property when args.username is null. If you are in an environment where you are not sure if undefined as been reassigned you can use void 0 instead. If you are using a new TypeScript or EcmaScript version you can use the newer ?? operator instead of ||.

Related

How to change property values for an object nested in an array in graphql?

I've just started to learn GraphQL recently and have decided to implement it in a react based polling app where users can create and vote on polls.
I've created a mongoose model that looks like this https://github.com/luckyrose89/Voting-App/blob/master/backend/models/poll.js.
I'm facing an issue with adding upvotes to a poll option while writing Graphql mutations. So far my schema looks like this:
const AnswerType = new GraphQLObjectType({
name: "Answer",
fields: () => ({
id: { type: GraphQLID },
option: { type: GraphQLString },
votes: { type: GraphQLInt }
})
});
const QuestionType = new GraphQLObjectType({
name: "Question",
fields: () => ({
id: { type: new GraphQLNonNull(GraphQLID) },
question: { type: GraphQLString },
answer: { type: GraphQLList(AnswerType) }
})
});
const AnswerTypeInput = new GraphQLInputObjectType({
name: "AnswerInput",
fields: () => ({
option: { type: GraphQLString },
votes: { type: GraphQLInt }
})
});
const QuestionTypeInput = new GraphQLInputObjectType({
name: "QuestionInput",
fields: () => ({
question: { type: new GraphQLNonNull(GraphQLString) },
answer: { type: new GraphQLNonNull(GraphQLList(AnswerTypeInput)) }
})
});
const Mutation = new GraphQLObjectType({
name: "Mutation",
fields: {
addPoll: {
\\\\ code here
},
deletePoll: {
\\\\\ code here
},
upvotePoll: {
type: QuestionType,
args: { id: { type: new GraphQLNonNull(GraphQLID) } },
resolve(parent, args) {}
}
}
});
So I've defined my types and I can add and delete polls and access a single poll(I've skipped my queries section here). But I don't understand how to access a single poll's AnswerType object without retrieving unnecessary data and use it to write my upVote mutation.
I hope someone can guide me with this

Query with different types in GraphQL

I have a GraphQL userType and EventType and on my userType I have to make a nested query using EventType but I also need to return user information. Since EventType doesn't have fields same as user info so to pass my code on testing I had to manually copy-paste UserType to EventType but I don't want this to solution.
Is there a way to like merge types? I'm using MongoDB as my database so when trying to do a POPULATE the user info comes back but GraphQL making it hard.
So this is what I did on EventType to pass the test. Under "fixme" I copy the UserType:
module.exports = {
EventType: new GraphQLObjectType({
name: 'Event',
fields: () => ({
id: {type: GraphQLID},
organizerId: {type: new GraphQLList(GraphQLID)},
title: {type: GraphQLString},
image: {type: GraphQLString},
description: {type: GraphQLString},
location: {type: GraphQLString},
items: {type: GraphQLInt},
date: {type: GraphQLString},
attendeesId: {type: new GraphQLList(GraphQLID)},
supplies: {type: new GraphQLList(GraphQLString)},
test: {type: GraphQLString},
// FIXME: USER TYPES!
firstName: {type: GraphQLString},
lastName: {type: GraphQLString},
email: {type: GraphQLString},
age: {type: GraphQLInt},
token: {type: GraphQLString},
image: {type: GraphQLString},
phone: {type: GraphQLInt},
address: {type: GraphQLString},
// ! TYPE RELATION
userRelatedToEvent: {
type: UserType,
resolve: async (parent, args) => {
const id = {
id: parent.organizerId
};
return await getCurrentUser(id);
}
}
})
})
};
this is my code on UserType that is doing a Type relation on EventType see resolve prop
module.exports = {
UserType: new GraphQLObjectType({
name: 'User',
fields: () => ({
id: {type: GraphQLID},
firstName: {type: GraphQLString},
lastName: {type: GraphQLString},
email: {type: GraphQLString},
age: {type: GraphQLInt},
token: {type: GraphQLString},
image: {type: GraphQLString},
phone: {type: GraphQLInt},
address: {type: GraphQLString},
eventsId: {type: new GraphQLList(GraphQLID)}, // <-- this will be the query for userRelatedToUser
statusCode: {type: GraphQLInt},
isSuccess: {type: GraphQLBoolean},
msg: {type: GraphQLString},
test: {type: GraphQLString}, // testing query
// errors: { type: GraphQ LString },
eventRelatedToUser: {
type: require('./eventTypeDef').EventType,
resolve: async (parent, args) => {
const event = {
event: parent.eventsId
};
const test = await getEventWithEventId(event); // <-- queries event
const id = {
id: test.attendeesId
};
const users = await getCurrentUser(id); // <-- user info
console.log(users);
return {...users, ...test};
}
}
})
})
};

GraphQL mutator with required args

I am writing a mutation for a GraphQL schema:
const Schema = new GraphQLSchema({
mutation: new GraphQLObjectType({
name: 'Mutation',
fields: () => ({
person: {
type: GraphQLString,
args: {
name: {type: GraphQLString},
school: {type: GraphQLString},
},
resolve: mutatePerson,
},
}),
}),
});
I want to ensure that mutatePerson will only work if both name and school arguments are present. How can I check that?
The GraphQLNonNull type wrapper is used to specify both fields and arguments as non-null. For fields, that means the value of the field in the query results cannot be null. For arguments, that means that the argument cannot be left out or have a value of null. So your code just needs to look more like this:
args: {
name: {
type: new GraphQLNonNull(GraphQLString),
},
school: {
type: new GraphQLNonNull(GraphQLString),
},
},
it is better to do it as follow (in the model) if you want to reject empty Strings like "", it is different from Null, this way you can reject both Null and empty "".
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const buinessSchema = new Schema({
name: { type: String, required: true, unique: true },
address: { type: String, required: true },
phone: { type: String, required: true },
email: { type: String, required: true },
website: { type: String, required: true },
currency: { type: String, required: true },
aboutus: { type: String, required: true },
terms: String,
slogan: String,
logo: { type: String, required: true }
});
module.exports = mongoose.model("Buiness", buinessSchema);

how to reuse resolvers in graphql

I am new to graphql, I was creating following schema with graphql
// promotion type
const PromoType = new GraphQLObjectType({
name: 'Promo',
description: 'Promo object',
fields: () => ({
id: {
type: GraphQLID,
description: 'id of the promo'
},
title: {
type: GraphQLString,
description: 'this is just a test'
},
departments: {
type: new GraphQLList(DepartmentType),
description: 'departments associated with the promo'
}
})
})
and department type
// department type
const DepartmentType = new GraphQLObjectType({
name: 'Department',
description: 'Department object',
fields: () => ({
id: {
type: GraphQLID,
description: 'id of the department'
},
name: {
type: GraphQLString,
description: 'name of the department'
},
createdAt: {
type: GraphQLDate,
description: 'date the promo is created'
},
updatedAt: {
type: GraphQLDate,
description: 'date the promo is last updated'
}
})
});
and the following are the resolvers
// Promos resolver
const promos = {
type: new GraphQLList(PromoType),
resolve: (_, args, context) => {
let promos = getPromos()
let departments = getDepartmentsById(promos.promoId)
return merge(promos, departments)
}
};
//Departments resolver
const departments = {
type: new GraphQLList(DepartmentType),
args: {
promoId: {
type: GraphQLID
}
},
resolve: (_, args, context) => {
return getDepartmentsById(args.promoId)
}
};
the problem is I want to use the resolver of the departments into the resolver of the promos to get the departments.
I might be missing something obvious but is there any way to do this?
This is the way to do it. You want to think of it as graphs, rather than just a single rest endpoint.
To get data for Promo, you need to do it similarly to how I did it here, but for the parent node, if that makes sense. So, in e.g. viewer's resolve you add the query for Promo.
const PromoType = new GraphQLObjectType({
name: 'Promo',
description: 'Promo object',
fields: () => ({
id: {
type: GraphQLID,
description: 'id of the promo',
},
title: {
type: GraphQLString,
description: 'this is just a test',
},
departments: {
type: new GraphQLList(DepartmentType),
description: 'departments associated with the promo',
resolve: (rootValue) => {
return getDepartmentsById(rootValue.promoId);
}
}
})
});

Why won't GraphQL (on Node.js) call my "resolve" method?

I'm trying to implement a very basic GraphQL interface in Node.js, but no matter what I do I can't seem to get the resolve method of my foo type to trigger. When I run the following code in a unit test it runs successfully, but I can see from the (lack of) console output that resolve wasn't called, and as a result I get an empty object back when I call graphql(FooSchema, query).
Can anyone more experienced with GraphQL suggest what I might be doing wrong? I'm completely baffled as to how the whole operation can even complete successfully if GraphQL can't find and call the method that is supposed to return the results ...
const fooType = new GraphQLInterfaceType({
name: `Foo`,
description: `A foo`,
fields: () => ({
id: {
description: `The foo's id`,
type: new GraphQLNonNull(GraphQLInt),
},
title: {
description: `The foo's title`,
type: new GraphQLNonNull(GraphQLString),
}
})
});
const queryType = new GraphQLObjectType({
fields: {
foo: {
args: {
id: {
description: 'ID of the foo',
type: new GraphQLNonNull(GraphQLString)
}
},
resolve: (root, { id }) => {
console.log(12345);
return getFoo(id)
},
type: fooType,
}
},
name: 'Query',
});
export default new GraphQLSchema({
query: queryType,
types: [fooType],
});
// In test:
const query = `
foo {
title
}
`;
const result = graphql(FooSchema, query); // == {}
const fooType = new GraphQLInterfaceType({
name: `Foo`,
description: `A foo`,
fields: () => ({
id: {
description: `The foo's id`,
type: new GraphQLNonNull(GraphQLInt),
},
title: {
description: `The foo's title`,
type: new GraphQLNonNull(GraphQLString),
}
})
});
This is an interface type, however your consumer queryType never implements it. A quick solution should be to change it to this:
const fooType = new GraphQLObjectType({
name: `Foo`,
description: `A foo`,
fields: () => ({
id: {
description: `The foo's id`,
type: new GraphQLNonNull(GraphQLInt),
},
title: {
description: `The foo's title`,
type: new GraphQLNonNull(GraphQLString),
}
})
});
Here's an example that works for me:
const {
GraphQLNonNull,
GraphQLInt,
GraphQLString,
GraphQLObjectType,
GraphQLSchema,
graphql,
} = require('graphql');
const fooType = new GraphQLObjectType({
name: `Foo`,
description: `A foo`,
fields: () => ({
id: {
description: `The foo's id`,
type: new GraphQLNonNull(GraphQLInt),
},
title: {
description: `The foo's title`,
type: new GraphQLNonNull(GraphQLString),
},
}),
});
const queryType = new GraphQLObjectType({
fields: {
foo: {
args: {
id: {
description: 'ID of the foo',
type: new GraphQLNonNull(GraphQLString),
},
},
resolve: (root, { id }) => {
return { id, title: 'some-title' };
},
type: fooType,
},
},
name: 'Query',
});
const schema = new GraphQLSchema({
query: queryType,
types: [fooType],
});
graphql(schema, `{ foo (id:"123") { id, title } }`).then(console.log.bind(console));
This should print:
$ node test.js
{ data: { foo: { id: 123, title: 'some-title' } } }
Here's the docs on the InterfaceType: http://graphql.org/learn/schema/#interfaces

Resources