Ember Data breaks when fetching JSON from Node + Express REST server - node.js

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

Related

Axios react node post request is giving a 422 (Unprocessable Entity)

I am trying to save the desired book to my MongoDB database when I press the saved button I get a 422 error I pass in the data as an object but for some reason, the data doesn't appear in the response back from the server The data is being passed to the Axios call but for some reason, the data property always returns an empty object,
The save handler
const handleSave = (event) => {
event.preventDefault();
let save = books.filter((book) => book.id === event.target.id);
// console.log(save);
// const da/ta = ;
// console.log(data);
API.saveBook({
title: save[0].title,
authors: save[0].author,
description: save[0].description,
image: save[0].image,
})
.then((res) => {
alert("book saved");
console.log(res);
// console.log(data);
})
.catch((err) => {
// console.log(data);
console.log("book not saved");
console.log(err.response);
});
};
This is the book model and the heroku link where you can see what is being logged out
const bookSchema = new Schema({
title: { type: String, required: true },
authors: [{ type: String, required: true }],
description: { type: String, required: true },
image: { type: String },
date: { type: Date, default: Date.now },
});
Heroku Link
github
I have console.logs in my inspect so you can check those out to see the response im getting back
I have cloned this repository and tested on both your Heroku link and locally, and cannot recreate the error locally. I suspect something to do with the MongoDB server rather than a code issue. I recommend you test creating a record in the live/Heroku-attached MongoDB server using an alternative method.
Thanks,
Will Walsh
Looks like volumeInfo.description is undefined for some books. The API returns a 422 error since description is required but is not present in the request payload. You could pass a default description if the book doesn't have one.
result = {
// ...
title: result.volumeInfo.title,
description: result.volumeInfo.description || "This book doesn't have a description",
// ...
}
Or you could remove the required validation for the description field if it's not an issue.
I would recommend you rename author to authors in the result object for clarity.
result = {
// ...
authors: result.volumeInfo.authors,
// ...
}

Graphql query is always returning null

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,
};
//...

How to fix the issue with Node Js backend only executing the first controller?

In my Book review site in the search option the user can search for books either by author name or the genre. For those I have separate functions in the search.service.ts below. There are separate controllers in the backend too. But while searching, it only executes the first controller, it doesn't execute the second controller even though the route is directing towards it.
Here is search.service.ts functions,
getPostsByAuthor(author: string) {
this.http.get<{message: string, posts: any, maxPosts: number }>(BACKEND_URL + 'api/search/' + author)
.pipe(map((postData) => {
console.log(postData);
return { posts: postData.posts.map((post) => {
return {
title: post.title,
content: post.content,
author: post.author,
genre: post.genre,
id: post._id,
imagePath: post.imagePath,
creator: post.creator
};
}),
maxPosts: postData.maxPosts};
}))
.subscribe(transformedPostsData => {
this.posts = transformedPostsData.posts;
return this.posts;
});
}
getPostsByGenre(genre: string) {
this.http.get<{message: string, posts: any, maxPosts: number }>(BACKEND_URL + 'api/search/' + genre)
.pipe(map((postData) => {
console.log('Genre_');
console.log(postData);
return { posts: postData.posts.map((post) => {
return {
title: post.title,
content: post.content,
author: post.author,
genre: post.genre,
id: post._id,
imagePath: post.imagePath,
creator: post.creator
};
}),
maxPosts: postData.maxPosts};
}))
.subscribe(transformedPostsData => {
this.posts = transformedPostsData.posts;
return this.posts;
});
}
The route in app.js,
app.use('/api/search', searchRoutes);
The search.js in the route folder,
const express = require('express');
const router = express.Router();
const SearchController = require('../controllers/search');
router.get("/:author", SearchController.getPostsByAuthor);
router.get("/:Genre", SearchController.getPostsByGenre);
module.exports = router;
Here are the controllers consecutively given,
const Post = require('../models/post');
const User = require('../models/user');
exports.getPostsByAuthor = (req, res, next) => {
let maxPosts = 10;
Post.find({ author: req.params.author }).then(posts => {
if(posts) {
res.status(200).json({
posts,
message: "Post was successful",
max: maxPosts
});
} else {
res.status(500).alert('Not Found, double check the spelling').json({
message: "Failed to get User Post"
});
}
});
}
exports.getPostsByGenre = (req, res, next) => {
let maxPosts = 10;
Post.find({ genre: req.params.genre }).then(posts => {
if(posts) {
res.status(200).json({
posts,
message: "Post weirdo successful",
max: maxPosts
});
} else {
res.status(500).json({
message: "Failed to get User Post"
});
}
});
}
It always runs the first one that means getPostsByAuthor, it never runs the second one.
I have checked by changing order, when I did put the getPostsByGenre in the first position then that was run and getPostsByAuthor did not run as it was placed second in order.
The controller placed in the first position in order, returns data perfectly, that means the route is reaching the controller file.
I'm not getting what's the issue. Did not find similar questions in SO.
I'm still new to development with MEAN stack, minimum of the clues would mean great help. Thank you.
The way you're trying to achieve routing is wrong.
When client makes a GET requests to route /api/search, express is going to look if a GET route is defined for the path. It will execute the first route it finds, in this case router.get("/:author", SearchController.getPostsByAuthor) (which you've mounted it first).
This is because middlewares are mounted like stack, execute first middleware then next and so forth.
You would need to define two different routes, since they are GET requests to two different resources, something like:
const SearchController = require('../controllers/search');
router.get("/author/:author", SearchController.getPostsByAuthor);
router.get("/genre/:Genre", SearchController.getPostsByGenre);
app.use('/api/search', searchRoutes);
Then you can call like:
api/search/author/someName
api/search/genre/someGenre

Completely stuck. (MongoDB / MERN issue)

Im creating an app, and right now I'm working on a feature that takes in user input, and stores it in the database. I've done this plenty of times on other projects, but have come to a problem that I just can't solve.
So far, when a user types in their info and hit's enter, the data is sent to the back end, and start's to head towards the endpoint. I have a controller set up with my 'create' function. It is the following:
const db = require('../database/models');
module.exports = {
// create: function(req, res) {
// console.log('hit controller');
// db.Listing
// .create(req.body)
// .then(dbModel => res.json(dbModel))
// .catch(err => res.status(422).json(err));
// }
create: function(req, res) {
console.log('!!!!HERE:CONTROLLERS' + req.body.receiver);
db.Listing
.create(req.body)
.then(function(dbModel) {
console.log(dbMessage);
res.json(dbModel)
})
.catch(function(err) {
res.json(err);
});
}
};
I have two functions because I tried something a little different for each with the same result. Once it gets to this point, I get the following error ('hit controller' is just the console.log in the create function):
'hit controller'
TypeError: Cannot read property 'create' of undefined
I also get the following error in my console on the browser: xhr.js:178 POST http://localhost:3000/listing/ 500 (Internal Server Error) err from saveListing Error: Request failed with status code 500 at createError (createError.js:16) at settle (settle.js:18) at XMLHttpRequest.handleLoad (xhr.js:77)
Which is coming from my addListing page:
handleFormSubmit = (event) => {
event.preventDefault();
console.log('hit');
console.log("state in handle submit", this.state.title)
if (
this.state.title &&
this.state.description &&
this.state.duration &&
this.state.datesAvailable &&
this.state.tags
) {
API.saveListing({
title: this.state.title,
description: this.state.description,
duration: this.state.duration,
datesAvailable: this.state.datesAvailable,
tags: this.state.tags
})
.then(res => console.log('success'))
.catch((err) => console.log("err from saveListing", err));
}
};
Here is my models file:
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var ListingSchema = new Schema({
// `title` is of type String
title: {
type: String,
required: true
},
description: {
type: String,
required: true
},
duration: {
type: String,
required: true
},
datesAvailable: {
type: String,
required: true
},
hashtags: {
type: Array,
required: true
}
});
var Listing = mongoose.model("Listing", ListingSchema);
module.exports = Listing;
So re-cap: When the user hit's the submit button, the form runs a function, hit's the API with the route it needs, heads to the sever, then to the route for the post request, then the llistingController for the create function for the post, while pulling from my Listing DB model. Once the create function is reached, it poops out. The data is apparently undefined, but I don't know why and can't figure it out.
I feel like what I'm running into is probably basic as fuck but I can't for the life of me figure it out. Additionally if anyone knows some bad ass resources for adding to my mongo/express/react knowledge i'd love to see it.
You're importing db from the models file, but that file is exporting Listing. Import Listing and use Listing.create instead of db.Listing.create.
As 223seneca said, I changed db.Listing.create in my controller to just Listing.create. Then I required Listing in the controller file to the exact file, instead of to just the models folder('const Listing = require('../database/models/Listing');' instead of 'const Listing = require('../database/models');'.
That was all I needed!

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.

Resources