Apollo GraphQL returns null when querying a SQL Server table - graphql

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

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}`,
...
})
}

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

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.

GraphQL mutation structure

I am trying to create a Node.js graphql server in Typescript. I am using Express and express-graphql. I have some issues with how to structure my mutation when I want to create a new User.
My goal is to be able to use a mutation like this:
mutation {
user {
create(
data: {
name: "Foo Bar"
}
) {
id,
name
}
}
}
Here is my User types:
import {
GraphQLObjectType,
GraphQLNonNull,
GraphQLBoolean,
GraphQLString,
GraphQLInputObjectType
} from 'graphql';
export const UserType = new GraphQLObjectType({
name: 'User',
description: 'A user of the application',
fields: () => ({
id: {
type: new GraphQLNonNull(GraphQLString),
description: 'The id of the user',
},
name: {
type: new GraphQLNonNull(GraphQLString),
description: 'The name of the user',
}
})
});
export const UserInputType = new GraphQLInputObjectType({
name: 'UserInputType',
description: 'User payload definition',
fields: () => ({
name: { type: new GraphQLNonNull(GraphQLString) }
})
});
Here is my attempt at defining the mutation on the server:
// ../user/user-mutations.ts
export const userMutations = {
user: {
type: new GraphQLObjectType({
name: 'CreateUser',
fields: {
create: {
type: UserType,
args: {
data: {
type: new GraphQLNonNull(UserInputType),
}
},
resolve: async (rootValue, { data }) => {
return Object.assign(data, {
id: '123'
});
}
}
}
})
}
};
My errors/output:
{
"errors": [
{
"message": "Cannot convert undefined or null to object",
"locations": [
{
"line": 36,
"column": 3
}
],
"path": [
"user"
]
}
],
"data": {
"user": null
}
}
Question 1: Is this way of structuring a mutation not optimal? Should I rather do something like:
mutation {
createUser(
name: "Foo Bar"
) {
id,
name
}
}
Question 2: If my first structure is fine, how can I fix the structure of my mutation on the server to create my user and return the values requested?
Edit: Here is my top level schema:
import { userQueries } from '../user/user-queries';
export const queries = {
...userQueries
};
import { userMutations } from '../user/user-mutations';
export const mutations = {
...userMutations
};
const rootQuery = new GraphQLObjectType({
name: 'RootQuery',
fields: queries
});
const rootMutation = new GraphQLObjectType({
name: 'RootMutation',
fields: mutations
});
export const schema = new GraphQLSchema({
query: rootQuery,
mutation: rootMutation
});

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