I used join-monster to convert graphql query into SQL query to fetch date from postgres. I have implemented a small example with the help of join-monster docs to achieve it. But when i try to run the graphql query I get error '"Must call joinMonster in a resolver on a field where the type is decorated with "sqlTable"."'
Can someone please point out what exactly i am missing. Below is my schema.js code
const graphql = require('graphql');
var _ = require('lodash');
const { Client } = require('pg');
const joinMonster = require('join-monster').default;
const knex = require('knex');
const client = new Client({
user: 'postgres',
host: 'l662.us-east-1.rds.amazonaws.com',
database: 'graphqldb',
password: 'Password01',
port: 5432,
});
client.connect();
var q = "SELECT * FROM graphql_user_details";
client.query(q, function(err, results){
if(err) throw err;
console.log("results are",results);
client.end();
});
const {
GraphQLObjectType,
GraphQLID,
GraphQLString,
GraphQLInt,
GraphQLList,
GraphQLSchema
} = graphql
const User = new GraphQLObjectType({
name: 'User',
sqlTable: 'graphql_user_details',
uniqueKey: 'id',
fields: () => ({
id: {
type: GraphQLInt
},
name: {
description: 'A user\'s first and last name',
type: GraphQLString,
extensions: {
joinMonster: {
// if the column name is different, it must be specified
sqlColumn: 'name'
}
}
},
age: {
description: 'A user\'s age',
type: GraphQLInt,
extensions: {
joinMonster: {
// if the column name is different, it must be specified
sqlColumn: 'age'
}
}
}
})
})
const QueryRoot = new GraphQLObjectType({
name: 'Query',
fields: () => ({
user: {
type: User,
args: {id:{type: GraphQLInt}},
// how to write the WHERE condition
where: (usersTable, args, context) => {
if (args.id) return `${usersTable}.id = ${args.id}`
},
resolve: (parent, args, context, resolveInfo) => {
return joinMonster(resolveInfo, {}, sql => {
// knex is a query library for SQL databases
return knex.raw(sql)
})
}
}
})
})
module.exports = new GraphQLSchema({
query: QueryRoot
})
Related
I am new to learning web dev using node.js and express.js. When I test my code in Postman the server crashes and gives me this error this.$__.validationError = new ValidationError(this).
I am creating backend server connected to MongoDB and the mongoose package.
Routes
const express = require('express')
const router = express.Router()
const {
create
} = require('./../controllers/courseControllers')
const {verifyAdmin, verify} = require('./../auth')
router.post('/create', verifyAdmin, async (req, res) => {
// console.log(req.body)
try{
create(req.body).then(result => res.send(result))
}catch(err){
res.status(500).json(err)
}
})
Controllers
const Course = require('../models/Course');
//CREATE A COURSE
module.exports.create = async (reqBody) => {
const {courseName, description, price} = reqBody
let newCourse = new Course({
courseName: courseName,
description: description,
price: price
})
// console.log(newCourse)
return await newCourse.save().then((result, err) => result ? result : err)
}
Schema
const mongoose = require('mongoose');
const courseSchema = new mongoose.Schema({
courseName: {
type: String,
required: [true, `Course name is required`],
unique: true
},
description: {
type: String,
required: [true, `Course description is required`]
},
price: {
type: Number,
required: [true, `Price is required`]
},
isOffered: {
type: Boolean,
default: true
},
enrollees: [
{
userId: {
type: String,
required: [true, `userId is required`]
},
enrolledOn: {
type: Date,
default: new Date()
}
}
]
}, {timestamps: true})
module.exports = mongoose.model("Course", courseSchema);
Given the information you provided, i can say that you are missing the enrollees parameter on creation whitin the controller, as enrollees has been set to required, i hope its usefull for you, if not let me know.
I want to find each of the elements in the array by their id and send it with the post request to create a new post. Right now when I create a new post only passes the first index of the array and if I use find() it passes all of the social schemas regardless if it is in the body of the request. I hope this makes sense if it doesn't please let me know. I hope someone can help.
Below is the mongoose schema for the qrcode post also using Joi
const Joi = require("joi");
const mongoose = require("mongoose");
const { themeSchema } = require("./Theme");
const { userSchema } = require("./User");
const { socialSchema } = require("./Social");
const QrCode = mongoose.model(
"QrCode",
new mongoose.Schema({
user: {
type: userSchema,
required: true,
},
name: {
type: String,
maxLength: 255,
required: true,
trim: true,
},
theme: {
type: themeSchema,
required: true,
},
// Social Media Links
social: [
{
type: socialSchema,
required: true,
},
],
})
);
function ValidateQrCode(qrCode) {
const schema = {
userId: Joi.objectId(),
name: Joi.string().max(255).required(),
themeId: Joi.objectId().required(),
socialId: Joi.array().required(),
};
return Joi.validate(qrCode, schema);
}
module.exports.QrCode = QrCode;
module.exports.validate = ValidateQrCode;
this is the post route to create a new qrcode
router.post("/", auth, async (req, res) => {
const { error } = validate(req.body);
if (error) res.status(400).send(error.details[0].message);
const theme = await Theme.findById(req.body.themeId);
if (!theme) return res.status(400).send("Invalid theme.");
const user = await User.findById(req.user._id);
if (!user) return res.status(400).send("Invalid theme.");
const social = await Social.findById(req.body.socialId);
if (!social) return res.status(400).send("Invalid social.");
const qrCode = new QrCode({
user: user,
name: req.body.name,
theme: theme,
social: social,
});
await qrCode.save();
res.send(qrCode);
});
In the body of my Postman request I am inputting the info below
{
"name": "Friends",
"themeId": "60f89e0c659ff827ddcce384",
"socialId": [
"60f89e43659ff827ddcce386",
"60f89e5c659ff827ddcce388"
]
}
To fetch data using ids, you can use below mongodb query simply,
db.collection.find( { _id : { $in : ["1", "2"] } } );
In mongoose,
model.find({
'_id': { $in: [
mongoose.Types.ObjectId('1'),
mongoose.Types.ObjectId('2'),
mongoose.Types.ObjectId('3')
]}
}, function(err, docs){
console.log(docs);
});
Or
await Model.find({ '_id': { $in: ids } });
I'm not sure which part I might be doing wrong. I was hoping to get some advice.
The query I am using in GraphiQL is:
query getUser($id:Int!) {
user(id:$id) {
id
email
}
}
For the backend I am using NodeJS. I am also declaring the user type as:
const UserType = new GraphQLObjectType({
name: 'User',
fields: () => ({
id: { type: GraphQLID },
email: { type: GraphQLString }
})
});
My root query is:
const RootQuery = new GraphQLObjectType({
name: 'RootQueryType',
fields: {
user: {
type: UserType,
args: { id: { type: GraphQLInt } },
resolve(parentValue, args) {
const query = `SELECT * FROM users WHERE id=$1`;
const values = [ args.id ];
dbQuery.query(query, values).then(({ rows }) => {
console.log(rows[0]);
return rows[0];
});
}
}
}
});
const schema = new GraphQLSchema({ query: RootQuery });
app.use(
'/api/v1/graphql',
graphqlHTTP({
schema: schema,
graphiql: true
})
);
What I get in return is:
{
"data": {
"user": null
}
}
I was hoping to know what I might be doing wrong that is resulting in null being returned instead of the data that I am querying from the database.
Thank you for all the help.
It will be much more clear if you use with await
const RootQuery = new GraphQLObjectType({
name: 'RootQueryType',
fields: {
user: {
type: UserType,
args: { id: { type: GraphQLInt } },
resolve: async(parentValue, args) {
const query = `SELECT * FROM users WHERE id=$1`;
const values = [ args.id ];
const rows = await dbQuery.query(query, values);
return rows[0];
}
}
}
});
When using a promise and returning anything inside the promise will only return the result to the promise that is executed. It will not be returning as a whole to the parent function.
You can also return the whole promise function like below
return dbQuery.query(query, values)
I try to create a new researcher but I just go into catch, and I do not get any errors. I am new using sequelize, I need a lot of help for this problem, my complete code in git: https://github.com/chanudinho/RevYou-BackEnd.
I can't explain it better, please if you need to download the project and test it. Sorry for my english =x
researcherController.js
const Researcher = require('../../sequelize/models/researcher');
const createResearcher= async (req, res) => {
try{
Researcher.create({name: 'name', email: 'email', password: 'password'});
return res.status(201).send('sucesso');
}catch (err){
return res.status(500).send('error');
}
}
models/researcher.js
module.exports = (sequelize, DataTypes) => {
const Researcher = sequelize.define('Researcher', {
name: DataTypes.STRING,
email: DataTypes.STRING,
password: DataTypes.STRING
});
return Researcher;
};
migrations/20190114200431-create-researcher
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Researcher', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
name: {
allowNull: false,
type: Sequelize.STRING
},
email: {
allowNull: false,
type: Sequelize.STRING
},
password:{
allowNull: false,
type: Sequelize.STRING
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Researcher');
}
};
models/index.js
const fs = require('fs');
const path = require('path');
const Sequelize = require('sequelize');
const config = require('../../config/database.js');
const db = {};
const sequelize = new Sequelize(config);
fs
.readdirSync(__dirname)
.filter(file => (file.indexOf('.') !== 0) && (file !== path.basename(__filename)) && (file.slice(-3) === '.js'))
.forEach((file) => {
const model = sequelize.import(path.join(__dirname, file));
db[model.name] = model;
});
Object.keys(db).forEach((modelName) => {
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db;
The problem is that you are importing the model file and this is not right, your index.js within model maps all model files by adding the sequelize instance and the datatypes. You should always import the index.
If you import the model index and give a console.log() in it will see that you have the object of your model and the instance of the sequelize.
const db = require('../../sequelize/models/index');
console.log(db)
Inside the exit will have something like this: Example:
Researcher: Researcher,
sequelize:
Sequelize { ....
To access your model you can do the following. By using destructuring assignment, you extract the model from within the index.
Result
const { Researcher } = require('../../sequelize/models/index')
const createResearcher= async (req, res) => {
try{
await Researcher.create({name: 'name', email: 'email', password: 'password'});
return res.status(201).send('sucesso')
}catch (err){
return res.status(500).send('error');
}
}
Whenever you create a new file inside the model folder, it will be mapped by index.js and added inside the matrix and using destructuring you can access or use the matrix key itself.
const db = require('../../sequelize/models/index')
const createResearcher= async (req, res) => {
try{
await db.Researcher.create({name: 'name', email: 'email', password: 'password'});
return res.status(201).send('sucesso')
}catch (err){
return res.status(500).send('error');
}
}
This question already has answers here:
Why does a GraphQL query return null?
(6 answers)
Closed 3 years ago.
I am trying to retrieve data from an API using GraphQL and Express. For some reason, I am only getting null as a result. I am new to GraphQL so, I am unsure why it is not working. Am I missing a configuration?
Thank you in advance.
The API URL is:
https://api.tfl.gov.uk/bikepoint
server.js
const express = require('express');
const expressGraphQL = require('express-graphql')
const schema = require('./schema/schema')
const app = express();
app.use('/graphql', expressGraphQL({
schema,
graphiql: true,
}))
app.listen(4000, () => {
console.log("Listening")
});
schema.js
const graphql = require('graphql')
const axios = require('axios')
const {
GraphQLObjectType,
GraphQLString,
GraphQLInt,
GraphQLSchema
} = graphql;
const BikepointType = new GraphQLObjectType({
name: 'Bikepoint',
fields: {
id: { type: GraphQLString},
url: { type: GraphQLString},
commonName: { type: GraphQLString},
placeType: { type: GraphQLString}
}
})
const RootQuery = new GraphQLObjectType({
name: 'RootQuery',
fields: {
bikepoint: {
type: BikepointType,
args: { id: { type: GraphQLString } },
resolve( parentValue, args ) {
return axios.get(`https://api.tfl.gov.uk/bikepoint`)
.then( resp => resp.data );
}
}
}
});
module.exports = new GraphQLSchema({
query: RootQuery
});
I forgot to add the args.id.
Solution:
axios.get(`https://api.tfl.gov.uk/bikepoint/${args.id}`)