GraphQL- conditionally determine the type of a field in a schema - graphql

I have the following mongoose schema:
const MessageSchema = new Schema({
author: {
account:{
type:String,
enum:['employee','admin'],
},
id: String,
}
//other fields
})
Then in my graphql-schemas file, I have the following schema types:
const MessageType = new GraphQLObjectType({
name: 'Message',
fields: () => ({
account: {
type: AuthorType,
//resolve method
},
id: {type: GraphQLString},
})
})
const AuthorType= new GraphQLObjectType({
name: 'Author',
fields: () => ({
account: {
type://This will either be AdminType or EmployeeType depending on the value of account in db (employee or admin),
//resolve method code goes here
}
})
})
As indicated in the comments of AuthorType, I need the account field to resolve to Admin or Employee depending on the value of the account field in the database.
How do I conditionally determine the type of a field in a schema on the fly?

Instead of determining the type on the fly, I restructured my code as shown below:
const MessageType = new GraphQLObjectType({
name: 'Message',
fields: () => ({
id:{type:GraphQLString},
author: {
type: AuthorType,
async resolve(parent, args) {
if (parent.author.account === 'guard') {
return await queries.findEmployeeByEmployeeId(parent.author.id).then(guard => {
return {
username: `${guard.first_name} ${guard.last_name}`,
profile_picture: guard.profile_picture
}
})
} else if (parent.author.account === 'admin') {
return {
username: 'Administrator',
profile_picture: 'default.jpg'
}
}
}
},
//other fields
})
})
const AuthorType = new GraphQLObjectType({
name: 'Author',
fields: () => ({
username: {type: GraphQLString},
profile_picture: {type: GraphQLString},
})
})
Since all I need from the AuthorType is the author's username and profile picture, both employee and administrator have these fields, which I pass to AuthorType.
In MessageType, I apply the logic to determine account type in the resolve method of author, then construct custom object out of the logic, to match AuthorType.

Related

Graphql multiple arguments in field

I'm using GraphQL.
I'm able to pass one argument in a field. But I would like to know how to pass multiple arguments to a field.
This is my code:
GraphlQL Object type: Price availability
const priceAvailability = new GraphQLObjectType({
name: "priceAvailability",
description: "Check price and availability of article",
fields: () => ({
articleID: {
type: GraphQLString
},
priceType:{
type:GraphQLString
},
stockAvailability: {
type: StockAvailabilityType,
resolve(parentValue, args) {
// stuff to get the price and availability
return (data = getStockAvailability.getStockAvailability(
parentValue.isbn, parentValue.omgeving
));
}
}
})
});
The root query
const RootQuery = new GraphQLObjectType({
name: "RootQuery",
fields: () => ({
price: {
type: new GraphQLList(priceAvailability),
args: [{
articleID: {
type: new GraphQLList(GraphQLString),
description:
'List with articles. Example: ["artid1","artid2"]'
},
priceType: {
type: new GraphQLList(GraphQLString) ,
description:
'PriceType. Example: "SalePrice","CurrentPrice"'
}]
},
resolve: function(_, { articleID , priceType}) {
var data = [];
// code to return data here
return data;
}
}
})
});
Schema
module.exports = new GraphQLSchema({
query: RootQuery
});
This is the query I use in GraphiQL to test:
{
query: price(articleID:"ART03903", priceType:"SalePrice" ){
stockAvailability {
QuantityAvailable24hrs
QuantityAvailable48hrs
}
}
}
I can get the articleID via parentValue.articleID, but I have issues with getting parentValue.priceType.
Also GraphiQL tells me that priceType does not exists:
Unknown argument “priceType”. On field “price” of type “RootQuery”
args for a field takes an object instead of an array. Try:
args: {
articleID: {
type: new GraphQLList(GraphQLString),
description: 'List with articles. Example: ["artid1","artid2"]'
},
priceType: {
type: new GraphQLList(GraphQLString) ,
description: 'PriceType. Example: "SalePrice","CurrentPrice"'
},
}

Dynamic GraphQLObjectType

I'm trying to create a dynamic GraphQLObjectType with graphQl, something like this:
export const Project = (data) => {
return new GraphQLObjectType({
name: 'Project',
fields: () => ({
id: {
type: GraphQLString
},
type: {
type: GraphQLString
},
author: {
type: User,
resolve: (root, args, req) => {
...
}
}
})
})
};
I call this model on my query in this way:
getProjectById: {
type: Project(structure),
args: {
id: { type: GraphQLString }
},
resolve(source, args, req) {
const projectService = new ProjectService(req);
return projectService.getProjectById(args.id)
}
}
the problem is that doing this I get this error:
Schema must contain unique named types but contains multiple types
named "Project"
where is the error? do you have some advice? many thanks
The call Project(structure) in turn calls new GraphQLObjectType({name: 'Project',...}) . If you invoke Project(structure) more than once, you try to declare multiple GraphQLObjectTypes with the same name (which makes no sense).
If you would create/declare GraphQLObjectType dynamically, you have to generate a unique name property. E.g. like this:
// assuming data.name is unique
export const Project = (data) => {
return new GraphQLObjectType({
name: `Project${data.name}`,
...
})
}

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);
}
}
})
});

Apollo GraphQL returns null when querying a SQL Server table

I have this table in the SQL Server database: the table name is small_customer:
customerid| first_name | last_name | starting_date |
--------- | -----------| --------- | --------------|
this is code in CustomerModel.js in which I connect to the SQL Server database and Sequelize the types:
const CustomerModel= Conn.define('small_customer',{
customerid: {type: Sequelize.INTEGER},
first_name: {type: Sequelize.STRING},
last_name: {type: Sequelize.STRING},
starting_date: {type:Sequelize.DATEONLY},
});
const Customer= Conn.models.small_customers;
export default Customer;
This is the Query.js :
import { CustomerModel, CustomerType, CustomerArgs} from './models/customer';
export default new GraphQLObjectType({
name: 'Query',
fields: () => {
return {
customer : {
type: CustomerType,
args: CustomerArgs,
resolve(root,args){
return new Promise((resolve, reject) => {
return resolve(Customer.find({ where: args }));
}); } }}}});
I have defined CustomerType.js:
export default new GraphQLObjectType({
name: 'Customer',
fields: () => {
return {
customerid: {type:GraphQLInt},
first_name: {type: GraphQLString},
last_name : {type: GraphQLString},
starting_date: {type: GraphQLDate},
}}});
When I write the query in order to select customer data based on the customerid and firstname, i have this error that
it Cannot read property 'find' of undefined
here is the example of my query and the result in GraphiQL:
Cannot read property 'find' of undefined
means that Customer has undefined type and your are performing the find Operation on the undefined as Customer.find({ where: args })
Import CustomerModel in Query.js
import { Customer } from './models/CustomerModel';
// i haven't used babel so require, if only schema is defined in CustomerModel
// const Customer = require('./models/CustomerModel');
import { CustomerModel, CustomerType, CustomerArgs } from './models/customer';
export default new GraphQLObjectType({
name: 'Query',
fields: () => {
return {
customer: {
type: CustomerType,
args: CustomerArgs,
resolve(root, args) {
return new Promise((resolve, reject) => {
return resolve(Customer.find({ where: args }));
});
}
}
}
}
});

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