Graphql query is always returning null - node.js

I am trying to get course data using graphql, but server is always returning null as a response This is my code in file server.js :
var express=require('express');
const { graphqlHTTP } = require('express-graphql')
var {buildSchema}=require('graphql');
//graphql schema
var schema=buildSchema(`
type Query {
course(id: Int!): Course
courses(topic:String!):[Course]
}
type Course {
id: Int
title: String
author: String
description:String
topic:String
url: String
}
`);
var coursesData = [
{
id: 1,
title: 'The Complete Node.js Developer Course',
author: 'Andrew Mead, Rob Percival',
description: 'Learn Node.js by building real-world applications with Node, Express, MongoDB, Mocha, and more!',
topic: 'Node.js',
url: 'https://codingthesmartway.com/courses/nodejs/'
},
{
id: 2,
title: 'Node.js, Express & MongoDB Dev to Deployment',
author: 'Brad Traversy',
description: 'Learn by example building & deploying real-world Node.js applications from absolute scratch',
topic: 'Node.js',
url: 'https://codingthesmartway.com/courses/nodejs-express-mongodb/'
},
{
id: 3,
title: 'JavaScript: Understanding The Weird Parts',
author: 'Anthony Alicea',
description: 'An advanced JavaScript course for everyone! Scope, closures, prototypes, this, build your own framework, and more.',
topic: 'JavaScript',
url: 'https://codingthesmartway.com/courses/understand-javascript/'
}
]
//root resolver
var root= {
course:getCourse,
courses:getCourses
};
var getCourse= function (args){
var id=args.id;
console.log("delila")
return coursesData.filter(course=>{
return course.id==id
})[0]
}
var getCourses = function(args){
if(args.topic){
var topic=args.topic;
return coursesData.filter(course=>
course.topic===topic
);
}
else return coursesData
}
//create an experess server and graphql endpoint
var app=express();
app.use('/graphql', graphqlHTTP({
schema: schema,
rootValue:root,
graphiql:true
}));
app.listen(4000,()=>console.log("delila express graphql server running on localhost 4000"))
When I go to localhost:4000/graphql to get data I am using
query getSingleCourse($courseID: Int !){
course(id:$courseID){
title
author
description
url
topic
}
}
{
"courseID": 3
}
But I am constantly getting result null. Look at image
Anyone idea why is happening this? Server should return course with id 3 but obviously there is something that I am missing

You should define function expression first and then use them. That's the reason.
Function expressions in JavaScript are not hoisted, unlike function declarations. You can't use function expressions before you create them:
See Function expression
E.g.
//...
var getCourse = function (args) {
var id = args.id;
console.log('delila');
return coursesData.filter((course) => {
return course.id == id;
})[0];
};
var getCourses = function (args) {
if (args.topic) {
var topic = args.topic;
return coursesData.filter((course) => course.topic === topic);
} else return coursesData;
};
//root resolver
var root = {
course: getCourse,
courses: getCourses,
};
//...

Related

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.

Node, Mongoose, Redux: GET request failure

I am trying to make the following get request, which is intended to simply return documents from a collection. Once I get the data, it should flow through a reducer into the redux state object. But the get request fails.
var QuestionModel = require('./src/models/fv-questionModel')
mongoose.connect('mongodb://localhost/FVDB')
var app = express();
app.use(compression())
app.use(express.static(path.join(__dirname, 'public')));
app.set('port', process.env.PORT || 8080);
app.get('/api/recent', (request, response) => {
if (error) {
console.log(error)
}
// Get documents and perform callback on recentQuestions data
QuestionModel.find((error, recentQuestions) => {
if (error) {
response.send('unable to retrieve data')
} else {
response.json(recentQuestions)
}
})
})
this request was working until I changed the structure of the data in the collection. Here is my current mongoose schema:
const questionSchema = new mongoose.Schema({
title: String,
options: [{ oid: Number, choice: { name: String, count: Number } }],
qid: Number,
})
const QuestionModel = mongoose.model('Question', questionSchema, 'questionBank')
module.exports = QuestionModel
The previous schema:
const questionSchema = new mongoose.Schema({
title: String,
options: Array,
qid: Number,
})
Here is the Redux action that makes the GET request:
export function recentQuestions() {
let recentQs = axios.get('/api/recent')
return {
type: 'GET_RECENT',
payload: recentQs,
}
}
And the reducer to handle that data:
export default function(state = null, action) {
switch (action.type) {
case 'GET_RECENT':
return action.payload.data
}
return state
}
But when the GET request is made, it returns a '404: Not Found' error. When I navigate my browser to localhost:8080/api/recent I get the message 'cannot GET /api/recent'. The express server itself is working.
I cannot for the life of me figure out why this request is no longer working. I know there are other questions about failed GET requests but none seem to pertain to this issue. Any help would be greatly appreciated.

Mongoose, geospatial query for users

I'm currently working with nodeJS, using express and mongoDB and mongoose for an ORM. When I create a User and save them to the database I would like to query their location and save it. This is what I am currently doing, I have a UserSchema and a location Schema.
My userSchema just has the location stored as a string and in the location Schema itself I have
var locationSchema = new mongoose.Schema({
name: String,
loc: {
type: [Number],
index: '2d'
}
});
mongoose.model('Location', LocationSchema);
And then in my controller, I have the following
import json from '../helpers/json;
import mongoose from 'mongoose';
var User = mongoose.model('User);
module.exports = function() {
var obj = {};
obj.create = function (req, res) {
var user = new User(req.body);
user.roles = ['authenticated']
user.location = getLocation(req);
user.save(function (err) {
if (err) {
return json.bad(err, res);
}
json.good({
record: user,
});
});
};
return obj;
function getLocation (req) {
var limit = req.query.limit || 10;
var maxDistance = req.query.distance || 1;
maxDistance /= 6371;
var coords = [];
coords[0] = req.query.longitude;
coords[1] = req.query.lattitude;
Location.findOne({
loc: {
$near: coords,
$maxDistance: maxDistance
}
}).limit(limit).exec(function (err, location) {
if (err) {
console.log(err);
}
return location.name;
});
}
};
I have also tried using location.find instead of findOne and returning locations[0].name.
The error is thrown says cast to the number failed for value undefined at loc.
Do I need to send the location data to the server from the client side? If so, is there a best method to implement this? I have heard of the HTML5 Geolocation API, but I have never utilized it.
Thank you!
!!! -- UPDATE --- !!
I have started using the Geolocation API on the client side to send this data to the server in the request. I am using angular on the client side like so
(function() {
'use strict';
angular.module('opinionated.authentication')
.controller('SignupController', SignupController);
/* #ngInject */
function SignupController ($state, appUsers, appToast) {
var vm = this;
vm.reset = reset;
vm.create = create;
vm.user = {
name: '',
username: '',
email: '',
password: ''
};
vm.location = {
lattitude: '',
longitude: ''
};
function create = (isValid) {
if (isValid) {
var user = new appUsers.single({
name: vm.user.name,
username: vm.user.username,
email: vm.user.email,
password: vm.user.password,
lattitude: vm.location.lattitude,
longitutde: vm.location.longitude
});
user.$save(function (response) {
if (response.success) {
appToast('Welcome to Opinionated, ' + response.res.record.name);
$state.go('authentication.wizard')
} else {
appToast(response.res.messsage);
}
});
} else {
appToast('Hmm... Something seems to be missing');
}
}
function getPosition() {
navigator.geolocation.getPosition(updatePosition);
}
function updatePosition (position) {
vm.location.lattitude = position.coords.lattitude;
vm.location.longitutde = position.coords.longitude;
}
getPosition();
....
I think it has something to do with how I am getting the coordinates now. My browser prompts me for permission to use my location, so I am at least requesting the data. However, I changed my User Schema to save the lat and long and neither of these values are being saved upon success.
I found my error. I did need to include the Geolocation API to get the users coordinates. I then just saved the coordinates to the database and am using mongo's geo service from there! Everything works fine now.

Ember Data breaks when fetching JSON from Node + Express REST server

I am trying to fetch JSON data from REST server built with Node.js and Express and then use it as a model in my Ember#Route.
The data I am trying to fetch:
var books = [
{ id: 98, author: 'Stanisław Lem', title: 'Solaris' },
{ id: 99, author: 'Andrzej Sapkowski', title: 'Wiedźmin' }
];
The model I use:
App.Book = DS.Model.extend({
id: DS.attr('number'),
author: DS.attr('string'),
title: DS.attr('string')
});
I set up the RESTAdapter this way:
App.ApplicationAdapter = DS.RESTAdapter.extend({
host: 'http://localhost:8080'
});
Mapping:
App.Router.map(function () {
this.resource("books");
});
My Route looks like this:
App.BooksRoute = Ember.Route.extend({
model: function () {
return this.store.find('book');
}
});
I am aware that ember-data follows certain convention when it comes to JSON files.
My server provides JSONs this way:
app.get('/books', function (request, response) {
console.log('In GET function ');
response.json({'books': books})
});
Then, after entering
http://localhost:8080/books
I get
{"books":[{"id":98,"author":"Stanisław Lem","title":"Solaris"},{"id":99,"author":"Andrzej Sapkowski","title":"Wiedźmin"}]}
but when I enter
http://localhost:8080/#/books
ember-data throws long error list that begins with:
"Error while processing route: books" "invalid 'in' operand record._attributes"
"ember$data$lib$system$model$attributes$$getValue#http://localhost:8080/static/ember-data.js:8176:1
ember$data$lib$system$model$attributes$$attr/<#http://localhost:8080/static/ember-data.js:8202:26
computedPropertySet#http://localhost:8080/static/ember.prod.js:11882:15
computedPropertySetWithSuspend#http://localhost:8080/static/ember.prod.js:11842:9
makeCtor/Class#http://localhost:8080/static/ember.prod.js:33887:17
...
and now I don't know what is wrong and how to fix this.
Looks like the mistake I made was in declaring model. ID attribute shouldn't be declared here, correct model looks like this:
App.Book = DS.Model.extend({
author: DS.attr('string'),
title: DS.attr('string')
});

Fetching from Model has not supply the defaults

In my app, I am fetching the data from /home -by home Model. the Model contains the defaults object. But while i fetch the data, I am not able to see the default object in the model.
here is my model :
define(['backbone'], function(Backbone){
"use strict";
socialApp = window.socialApp || {};
socialApp.homeModel = Backbone.Model.extend({
url: "/home",
defaults:{
"category":"Level-1"
}
});
return socialApp.homeModel;
});
here is my view.js :
socialApp.homeView = Backbone.Marionette.ItemView.extend({
tagName:'div',
initialize:function () {
var that = this;
this.model.fetch().done(function(data){
that.render(data) // i am fetching here
});
},
render: function (data) {
console.log(data) //there is no defaults object here...
this.$el.html(homeTemp(data));
}
});
What is wrong here? I am using Nodejs as a server.
here is the console what i am getting:
{
__v: 0
_id: "5416ce23fc0c41ec0f03f672"
email: "afzil#gmail.com"
firstName: "Mohamed"
lastName: "Afzil"
password: "afzil"
username: "afzil"
}
thanks in adavnce.
As i can see in promise 'done' callback you have only fetch results, not model.
please modify your initialize function to this:
initialize: function () {
var that = this;
this.model.fetch({
success: function(model){
that.render(model.toJSON());
}
});
}

Resources