How to fetch the data from database for resolver in graphql - node.js

I Have Created two File
index.js
const {ApolloServer,gql} = require('apollo-server');
const fs = require('fs');
const path = require('path');
const typedefs = gql`
type Query {
info: String!
ask: [Person!]
}
type Person {
name: String!
age: Int!
}
`;
const resolvers = {
Query: {
info: () => `Hello World from Linux Fan`,
ask: () => {
return [fs.readFileSync(__dirname+path.join('/db.db'),'utf-8')]
}
}
}
const server = new ApolloServer({
typedefs,
resolvers
}).listen().then(({url}) => console.log(url)).catch(err => console.log(err));
and one More File for storing Database
db.db
{
name:"Linux Age",
age: 19
}
But The Problem is everytime I make a query for fetching name and age like
{
info
ask{
name
}
}
There is a problem which exist and say
"Cannot return null for non-nullable field Person.name"
How to Solve ??

According to Node.js documentation (https://nodejs.org/api/fs.html#fs_fs_readfilesync_path_options), fs.readFileSync() returns a String or Buffer. From the schema, however, ask() returns an array of type Person which is an object. The result of fs.readFileSync() should be converted to object before returning:
ask: () => {
const person = JSON.parse(JSON.stringify(
fs.readFileSync(__dirname + path.join('/db.db'), 'utf-8').toString()
));
return [person];
}
Notice that I called JSON.stringify() before parsing it with JSON.parse(). The reason is the file db.db has a javascript object (keys, nanely name and age, without double quotes around them) and not a JSON object (keys with quotes as shown below):
{
"name":"Linux Age",
"age": 19
}
Otherwise, JSON.parse() would have a problem parsing the invalid JSON format:
{
name:"Linux Age",
age: 19
}
In addition, toString() after calling readFileSync() is needed to convert a Buffer to a string:
fs.readFileSync(__dirname + path.join('/db.db'), 'utf-8').toString()

Related

.../node_modules/graphql/error/sytnaxError.js `return new _GraphQLError.GraphQLError(`

I am starting a Apollo/GraphQL backend to a Reactjs Project. I'm still in the early phases (and relatively new to this kind of backend work so please bare with me) and just trying to get everything to a state where I can successfully run node server.js and get the backend spinning. I have been running it, getting an error and fixing it for quite a few rotations now, but I am now getting an error that provides essentially no help on where to look or what exactly I'm looking for. Upon running node server.js I get this response...
/Users/nickfatherbool/code/personal/finance/value_tracker/backend/node_modules/graphql/error/syntaxError.js:15
return new _GraphQLError.GraphQLError(
GraphQLError: Syntax Error: Expected Name, found "}".
at syntaxError (/Users/nickfatherbool/code/personal/finance/value_tracker/backend/node_modules/graphql/error/syntaxError.js:15:10)
I tried using Ctrl + F to find the line return new _GraphQLError.GraphQLError( but I was unable to find anything like that. I'm pretty sure that digging through the node-modules directory would be a waste of time since seldom is that ever the answer, plus I tried deleting the directory and running npm i again, so I doubt there's anything I could fix in there anyway. Currently, my server.js file is constructed as so...
import express from 'express'
import cors from 'cors'
import dotenv from 'dotenv'
import { ApolloServer } from 'apollo-server-express'
import typeDefs from './graphql/typeDefs.js';
import resolvers from './graphql/resolvers/index.js';
import util from 'util'
dotenv.config();
const startApolloServer = async () => {
const app = express()
const server = new ApolloServer({
typeDefs,
resolvers,
context: ({req}) => ({req})
})
const whitelist = [
"http://localhost:3000",
"http://localhost:4000/graphql",
"https://studio.apollographql.com",
]
app.use(cors({ /* credentials: true, */ origin: "*" }));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.get('/', (req, res) => {
res.send('Welcome to SQL');
});
await server.start()
await server.applyMiddleware({ app, path: '/graphql', cors: false });
await app.listen(process.env.PORT, () => console.log(`Server running on ${process.env.PORT}... GraphQL/Apollo at studio.apollographql.com/dev`));
}
startApolloServer()
And I have my prisma.schema and typeDefs.js files all properly set up... I could attach them if needed but I'm pretty sure they're unrelated to the issue at hand. Does anyone have any idea what is wrong, or any advice on where I should look for the answer?
These are the only mutations/queries that have been made thus far...
import bcrypt from 'bcryptjs';
import generateToken from '../../utils/generateToken.js';
import { UserInputError } from 'apollo-server-errors';
import checkGlobalAuth from '../../utils/checkAuthorization/checkGlobalAuth.js';
import db from '../../utils/generatePrisma.js';
import hashPassword from '../../utils/passwordHasher.js';
import { validateRegisterInput } from '../../utils/validators.js';
import { checkExistingUserByEmail, checkExistingUserByPhone } from '../../utils/checkExisting.js';
export default {
Query: {
getUser: async (_, { }, context) => {
const user = await checkGlobalAuth(context)
try {
return await db.user.findUnique({
where: {
id: user.id
},
include: {
stocks: true
}
})
} catch(error){
throw new Error(error)
}
}
},
Mutation: {
user_signUp: async (_, { fullname, email, password, phoneNumber } ) => {
try {
// This creates TWO consts -- valid AND errors based off of validateRegisterInput's returns. Look at
// utils/validators to see what ther validateRegisterInput does
const {
valid, // True or False
errors // Object that has subobjects for potential email / password / fullname errors
} = validateRegisterInput(
email,
password,
fullname
);
// Makes the email in all caps for storage/comparison reasons
email = await email.toUppeCase()
// Checks to make sure all inputs were properly filled
if (!valid) {
throw new userInputError('Errors', {
errors
});
}
// Imported function. Checks duplicate enails
let existingUser = await checkExistingUserByEmail(email)
if (existingUser) {
throw new UserInputError('email is taken', {
errors: {
email: 'Email is already taken!',
},
});
}
// Import function. Checks duplicate phoneNumbers
existingUser = await checkExistingUserByPhone(phoneNumber)
if (existingUser) {
throw new UserInputError('email is taken', {
errors: {
phoneNumber: 'Phone Number is already in use!',
},
});
}
// Imported function. Hashes password
password = await hashPassword(password)
// Creates a User Account
let user = await db.user.create({
data: {
name: fullname,
email: email,
password: password,
phoneNumber: phoneNumber
}
})
// Imported function. Generates session token
token = await generateToken(user.id)
// Returns the created User with a session token
return {...user, token: token}
} catch(error){
console.loig(error)
throw new Error(error)
}
}
}
}
The only other files I have in play are my typeDefs and prisma.schema files, which respectively look as so...
import { gql } from 'apollo-server';
const typeDefs = gql`
scalar Date
scalar JSON
type User{
id: ID
username: String
password: String
email: String
TD_userName: String
TD_password: String
stocks: [Stock]
emailList: [JSON]
buySellList: [JSON]
tradeHistory: [JSON]
}
type Stock{
id: ID
name: String
ticker: String
lastValue: JSON
valueHistory: JSON
growthExpected: Int
growthSoFar: Int
growthRatio: Int
users: [User]
link: String
}
type Query {
}
type Mutation {
}
`
export default typeDefs
And this is the prisma.schema
generator client {
provider = "prisma-client-js"
binaryTargets = ["native"]
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
// BASIC INFORMATION
id Int #id#default(autoincrement())
username String #unique
passsword String
email String
phoneNumber String #unique
// BANKING INFORMATION
TD_userName String #unique
TD_password String
// FUNCTIONAL INFORMATION
emailList Json[]
buySellList Json[]
tradeHistory Json[]
// CONNECTIONS
stocks Stock[]
}
model Stock {
// BASIC INFORMATION
id Int #id#default(autoincrement())
name String #unique
ticker String #unique
// STATISTICAL AND HISTORICAL DATA
lastValue Json
valueHistory Json[]
growthExpected Int
growthSoFar Int
growthRatio Int
// CONNECTIONS
users User[]
link String
}
This did just end up being a stupid sytnax error. I needed to have type Mutation { ... } and type Query{ ... }inside of the typeDef file or else I would get some error letting me know Query and Mutation were defined in the Resolvers but not the schema. Adding those types fixed that error, but since they were empty objects THAT through the syntax error in question.

Graphiql variables not being passed to server

I'm building an Apollo Server. I have one simple endpoint communicating with Mongo. There's a collection of announcements.
export const typeDefs = gql`
type Query {
announcements: [Announcement]
announcementsByAuthor(author: String!): [Announcement]
}
type Announcement {
_id: ID!
msg: String!
author: String!
title: String
}
`;
export const resolvers = {
Query: {
announcements: () => {
return new AnnouncementController().getAnnouncements();
},
announcementsByAuthor: (author: string) => {
console.log('RESOLVER: ', author);
return new AnnouncementController().getAnnouncementsByAuthor(author);
}
},
}
In my graphiql interface, the announcements query works correctly:
{
announcements {
msg
author
}
}
The announcementsByAuthor query does not seem to be accepting the string argument, either from a variable or when hardcoded into the query.
query($author: String!){
announcementsByAuthor(author: $author) {
msg
author
}
}
Variables:
{
"author":"Nate"
}
I've logged out from the resolver, and an empty string is being passed in, instead of the specified value for the author variable. I'm new to graphql and I'm hoping someone can enlighten me as to what I'm sure is a simple oversight.
Try this instead:
announcementsByAuthor: (doc, {author}) => {

How do I give parameters to function in GraphQL

Actually, I'm a newbie to graphQL so I wasn't able to pass parameters rightly in function updateMessage() in graphiQL. I'm trying to update the database using
mutation {
createMessage(input: {
author: "Pawan",
content: "hope is a dangerous thing",
}) {
id,content,author,
}
updateMessage(id:{cfe934d60b9997a4507e},input:{
author: "Pawan",
content: "hope is a dangerous thing",
})
}
but the error is displayed as
{
"errors": [
{
"message": "Syntax Error: Expected :, found }",
"locations": [
{
"line": 8,
"column": 40
}
]
}
]
}
Beside I'm also not able to show fakeDatabase .Can I do that ?
if yes How can I show every time I add a message to the fakeDatabase?
mutation.js
var express = require('express');
var graphqlHTTP = require('express-graphql');
var { buildSchema } = require('graphql');
// Construct a schema, using GraphQL schema language
var schema = buildSchema(`
input MessageInput {
content: String
author: String
}
type Message {
id: ID!
content: String
author: String
}
type Query {
getMessage(id: ID!): Message
}
type Mutation {
createMessage(input: MessageInput): Message
updateMessage(id: ID!, input: MessageInput): Message
}
`);
// If Message had any complex fields, we'd put them on this object.
class Message {
constructor(id, {content, author}) {
this.id = id;
this.content = content;
this.author = author;
}
}
// Maps username to content
var fakeDatabase = {};
var root = {
getMessage: function ({id}) {
if (!fakeDatabase[id]) {
throw new Error('no message exists with id ' + id);
}
return new Message(id, fakeDatabase[id]);
},
createMessage: function ({input}) {
// Create a random id for our "database".
var id = require('crypto').randomBytes(10).toString('hex');
fakeDatabase[id] = input;
return new Message(id, input);
},
updateMessage: function ({id, input}) {
if (!fakeDatabase[id]) {
throw new Error('no message exists with id ' + id);
}
// This replaces all old data, but some apps might want partial update.
fakeDatabase[id] = input;
return new Message(id, input);
},
};
var app = express();
app.use('/graphql', graphqlHTTP({
schema: schema,
rootValue: root,
graphiql: true,
}));
console.log(fakeDatabase)
app.listen(4000, () => {
console.log('Running a GraphQL API server at localhost:4000/graphql');
});
On your mutation updateMessage try updating the parameters and send $id as a string instead of an object, like:
updateMessage(id:"cfe934d60b9997a4507e",input:{
author: "Pawan",
content: "hope is a dangerous thing",
})
The issue is that mutation updateMessage requires an ID and MessageInput, but you're sending Object and MessageInput.

Implementing pagination with Mongoose and graphql-yoga

I am experimenting with graphql and have created a simple server using graphql-yoga. My Mongoose product model queries my database and both resolvers return data as expected. So far it all works and I am very happy with how easy that was. However, I have one problem. I am trying to add a way to paginate the results from graphQL.
What did I try?
1) Adding a limit parameter to the Query type.
2) Accessing the parameter through args in the resolver
Expected behaviour
I can use the args.limit parameter in my resolver and use it to alter the Mongoose function
Actual behaviour
I can't read the arg object.
Full code below. How do I reach this goal?
import { GraphQLServer } from 'graphql-yoga'
import mongoose from "mongoose"
import {products} from "./models/products.js"
const connection = mongoose.connect('mongodb://myDB')
const prepare = (o) => {
o._id = o._id.toString()
return o
}
const typeDefs = `
type Product {
_id: String
name: String
description: String
main_image: String
images: [String]
}
type Query {
product(_id: String): Product
products(limit: Int): [Product]
}
`
const resolvers = {
Query: {
product: async (_id) => {
return (await products.findOne(_id))
},
products: async (args) => {
console.log(args.name)
return (await products.find({}).limit(args.limit))
},
},
}
const server = new GraphQLServer({
typeDefs,
resolvers
})
server.start(() => console.log('Server is running on localhost:4000'))
The arguments for a field are the second parameter passed to the resolver; the first parameter is the value the parent field resolved to (or the root value in the case of queries/mutations). So your resolvers should look more like this:
product: (root, { _id }) => {
return products.findOne(_id)
}

How should I write a resolver while using apollo graphql server backed by neo4j database?

I am using neo4j dB and I have set up apollo graphql server (using graphql-server-express). Lets say my schema has 3 types namely "Country", "State" and "People" where 1 country can have multiple states and 1 state can have multiple people.
//Sample schema.js
import { makeExecutableSchema } from 'graphql-tools';
import resolvers from './resolvers';
const typeDefs = `
type Country {
id: Int!
name: String
state: [State]
people: [People]
}
type State {
id: Int!
name: String
countryID: CountryID
people: [People]
}
type People {
id: Int!
name: String
SSN: String
stateid:StateID
countryid:CountryID
}
type Query {
Countries: [Country]
States: [State]
Peoples: [People]
}
schema {
query: Query
}
`;
export default makeExecutableSchema({
typeDefs: typeDefs,
resolvers,
});
So, how should I write my resolver function in resolver.js file such that it would help me to fetch the data properly from any of the above types ?
I tried to use the following query in resolver.js file (to query the Neo4j database using Cypher query language), but got the type error and i am unable to fix it.
//Sample resolver.js file.
let neo4j = require('neo4j-driver').v1;
let driver = neo4j.driver("bolt://localhost", neo4j.auth.basic("neo4j",
"******"));
const resolver = {
Query: {
Countries(_, params) {
let session = driver.session();
let query = "MATCH (country:Country) RETURN country;"
return session.run(query, params)
.then( result => { return result.records.map(record => { return
record.get("country").properties })})
},
},
State:{
state(State) {
let session = driver.session(),
params = {countryid: Country.id},
query = `
MATCH (s:State-[:PRESENT]->(c:Country)
WHERE s.countryid = $countryid
RETURN s;
`
return session.run(query, params)
.then( result => { return result.records.map(record => { return
record.get("state").properties })})
},
},
};
export default resolver;

Resources