I'm trying to build a simple blog with a MEAN stack and I'm currently setting up the back end. I'm testing my routes with Postman and for some reason, I can't save the title and body of a post in the DB.
My model:
models/posts/db.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var PostSchema = new Schema ({
title: { type: String },
body: { type: String },
date: { type: Date, default: Date.now }
});
module.exports = mongoose.model('Post', PostSchema);
My controller: controllers/posts.index.js
var base = process.env.PWD;
var Post = require(base + '/models/posts/db.js')
var createPost = function(req, res) {
var post = new Post(req.body)
post.save(function(err, post) {
if(err) { res.sendStatus(500, err); }
res.json(post);
})
}
var getPosts = function(req, res) {
Post.find(function(err, posts) {
if (err) { res.sendStatus(500, err); }
res.json(posts);
})
};
module.exports = {
createPost,
getPosts
}
And here are my main routes in routes/index.js
router.get('/posts', posts.getPosts);
router.post('/posts/create', posts.createPost);
module.exports = router;
And my main server is using a /api endpoint:
`app.use('/api', routes);`
So in Postman, when I send a POST request to /api/posts/create with a post containing a title and a body, an empty post is stored. I get something like this inserted:
{
"__v": 0,
"_id": "5a29de91521f168eb9e1bcf2",
"date": "2017-12-08T00:36:33.280Z"
}
Any help would be appreciated.
It looks like the Post may not be getting the body of your actual post. You can fill the body property on your request with the body-parser module. Do an npm install body-parser and add this to your code:
const bodyParser = require('body-parser')
app.use(bodyParser.json())
I figured it out, 2 problems:
The order of where you place body-parser is important, I wrote the line after setting my routes so it wasn't parsing anything.
I hadn't set up my Postman correctly, it was sending regular text instead of a JSON object. facepalm
Related
PROBLEM: When I am making the POST request in postman, the postman keeps on sending requests and I do not get any response.
I went through other answers about postman hanging when POST request is made, but could not find a solution to my problem.
GET REQUEST WORKING FINE
Following is the request that I made
{
"title": "This is title",
"description":"This is my first RestfulAPI"
}
I have 3 files Post.js, posts.js, app.js
Post.js
const mongoose = require('mongoose');
//Creating a schema
const PostSchema= mongoose.Schema({
title: {
type: String,
required: true
},
description: {
type: String,
required: true
}
})
module.exports=mongoose.model('Posts',PostSchema);
posts.js
const express= require('express');
const router=express.Router();
const Post= require('../models/Post');
router.get('/',(req,res) => {
res.send('We are on posts');
});
router.get('/specific',(req,res) => {
res.send('Specific posts');
});
router.post('/',async (req,res)=>{
console.log(req.body);
const post= new Post({
title: req.body.title,
description: req.body.description
});
try{
const savedPost = await post.save();
res.json(savedPost).status(3000).end();
}catch(err){
res.json({message: err}).status(3000).end();
console.log('Something is wrong');
}
});
module.exports= router;
app.js
const express = require('express');
const mongoose= require('mongoose');
const app= express();
const bodyParser= require('body-parser');
require('dotenv/config');
app.use(bodyParser.json());
const postsRoute = require('./routes/posts');
app.use('/posts',postsRoute);
app.get('/',(req,res) => {
res.send('We are on home');
});
mongoose.connect(process.env.DB_CONNECTION,{ useNewUrlParser: true,useUnifiedTopology: true },() =>
console.log('connected to DB!')
);
app.listen(3000);
My console after sending POST request
You would not need .end() after calling res.json(), as you probably want to send the savedPost back to the client.
The express documentation mentions here that
[res.end()] is used to quickly end the response without any data. If you need to respond with data, instead use methods such as res.send() and res.json().
You also need to send back the proper HTTP code that ranges from 1xx to 5xx, when working with HTTP. You can read more about them here
Your response should probably look like
res.status(200).json(savedPost);
I use mongoose to populate "Post Schema" with information about users whic create the post.
postModule.js
const mongoose = require('mongoose');
const postSchema = mongoose.Schema({
title:String,
description:String,
datePost:Date,
images:[String],
like:[String],
dislike:[String],
author:{
type: mongoose.Schema.Types.ObjectId,
ref:'User'
},
});
postSchema.pre(/^find/,function(next){
this.populate({
path:'author',
select:'photo firstName lastName'
});
next();
});
const Post = mongoose.model('Post',postSchema);
module.exports = Post;
This is the controller build in postController.js
//Get All User Post
exports.getUsersPost = catchAsync(async(req,res,nex)=>{
const userPost = await Post.find({author:req.params.userId});
res.status(200).json({
status:"success",
length:userPost.length,
data:{
post:userPost
}
});
});
postRouter.js
router.route('/get-user-posts/:userId').get(authController.protect,postController.getUsersPost)
I don't know what is wrong, I recive in postman this error Cannot GET /api/v1/get-user-posts/5f719092ba22b8373c72196
There is any option to resolve this problem and the result of request it must to by all the posts created by the user.
If your app.js looks like below, then you endpoint should be:
/api/v1/post/get-user-posts/5f719092ba22b8373c72196.
It takes the whole string in the use() function. So /api/v1/user/**Routes you've defined in your Routes files**
const sessionRoutes = require('./routes/sessionsRoutes');
const userRoutes = require('./routes/userRoutes');
const viewRoutes = require('./routes/viewRoutes');
const postRoutes = require('./routes/postRoutes');
app.use('/api/v1/session',sessionRoutes);
app.use('/api/v1/user',userRoutes);
app.use('/api/v1/post',postRoutes);
app.use('/',viewRoutes);
module.exports = app;
Also add and extra slash just to be sure app.use('/api/v1/user/', userRoutes)
I am using Postman to learn about APIs. The contents of my server.js file is in the code below. However, when I send a post through Postman, the error "Cannot read property 'title' of undefined" keeps showing.
var Product = require("./model/product");
var WishList = require("./model/wishlist");
app.post("/product", function (request, response) {
var product = new Product();
product.title = request.body.title;
product.price = request.body.price;
product.save(function (err, savedProduct) {
if (err) {
response.status(500).send({ error: "Could not save product" });
} else {
response.status(200).send(savedProduct);
}
});
});
app.use(express.json());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.listen(3000, function () {
console.log("Swag Shop API runing on port 3000...");
});
The product.js file contains the code below.
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var product = new Schema({
title: String,
price: Number,
likes: { type: Number, default: 0 },
});
module.exports = mongoose.model("Product", product);
I tried to send the following json file through Postman but then the errorType: "Cannot read property 'title' of undefined " was showing.
{
"title": "Test Title",
"price": 100.00
}
These are the folders to see the location of my files: Folders.
This solution using npm install express#">=3.0.0 <4.0.0" --save did not work in my case. After I used it in my terminal, the same error kept showing.
How can I solve this issue?
Try this and either use express.json() or bodyParser.json()
if you go into the file node_module/express/lib/express.js you can see under module dependencies body-parser module is already imported var bodyParser = require('body-parser);
var Product = require("./model/product");
var WishList = require("./model/wishlist");
//app.use(express.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.post("/product", function (request, response) {
var product = new Product();
product.title = request.body.title;
product.price = request.body.price;
product.save(function (err, savedProduct) {
if (err) {
response.status(500).send({ error: "Could not save product" });
} else {
response.status(200).send(savedProduct);
}
});
});
app.listen(3000, function () {
console.log("Swag Shop API runing on port 3000...");
});
Install express.js & mongoose by typing $npm install --save
express mongoose
Type the codes below on TOP for your proper
imports and declarations
var express = require('express');
var app = express();
var mongoose = require('mongoose');
var db = mongoose.connect('mongodb://localhost/swag-shop');
I am writing a node/express rest api.
Hitting,
http://localhost:5000/api/news
and
http://localhost:5000/api/news/?id=c5f69d56be40e3b56e55d80
both give me all the news objects because it enters the same .getNews function on for both the urls.
My controller:
const NewsController = {};
const News = require('../models/news.model');
// This implementation of getNews is using Promises
NewsController.getNews = function(req, res) {
console.log('Inside getNews');
sendResponse = function(arg) {
res.json(arg);
}
const allnews = News.find({}, function(err, ns) {
sendResponse(ns);
});
};
// ES6 style
NewsController.getSingleNews = async (req, res) => {
console.log("Inside getSingleNews");
const news = await News.findById(req.params.id);
res.json[news];
};
NewsController.createNews = async (req, res) => {
const news = new News(req.body);
await news.save();
res.json[{
'status': 'item saved successfully'
}];
};
NewsController.deleteNews = async (req, res) => {
await News.findByIdAndRemove(req.params.id);
res.json[{
'status': 'item deleted successfully'
}]
};
module.exports = NewsController;
My routes.js (I am using the router at /api. So app.js has // use Router
app.use('/api', newsRoutes);
)
const express = require('express');
const router = express.Router();
var newsController = require('../controllers/NewsController')
router.get('/news', newsController.getNews);
router.get('/news/:id', newsController.getSingleNews);
router.post('/news', newsController.createNews);
router.delete('news/:id', newsController.deleteNews);
module.exports = router;
My Model
const mongoose = require('mongoose');
const { Schema } = mongoose;
const newsSchema = new Schema({
title: { type: String, required: true },
content: { type: String, required: true },
author: { type: String },
image: { type: String },
source: { type: String }
});
module.exports = mongoose.model('news', newsSchema);
The issue with your code is the way you are trying to call your endpoint. Express routes don't match query string parameters.
Having said that, your call to the news endpoint that looks like this:
http://localhost:5000/api/news/?id=c5f69d56be40e3b56e55d80
Should look like this instead:
http://localhost:5000/api/news/c5f69d56be40e3b56e55d80
That way the id parameter will get mapped to the req.params.id property inside your getSingleNews controller.
Being that the expected behavior for the way you declared your route:
router.get('/news/:id', newsController.getSingleNews);
For more information on how express routes work, check the documentation here: https://expressjs.com/en/guide/routing.html
Use /news/:id first. Your request will be redirected to the first matched url following the declaration order.
So /api/news satisfies app.get(/news)? Yep, gets redirected to that controller.
/api/news/?id=c5f69d56be40e3b56e55d80 satisfies app.get(/news)? Yep, also gets redirected to /news controller.
By the way, as your getting the id from req.params you should use /news/c5f69d56be40e3b56e55d80. If you were to get it from req.query you wouldn't need another route. /news?id=c5f69d56be40e3b56e55d80 would be perfect, you'd just need to check the existence of req.query.
I have a task to implement a pseudo cart page and when I click on checkout i want to send a request to a json file "ordersTest.json" with a following structure:
{ "orders": [] }. So when a post request is sent i have to put the data in that orders array in the json. I am completely new to Nodejs and express. This is my first project on it and i came up with a very simple server.
const express = require('express')
const path = require('path')
const fs = require('fs')
const url = require('url')
const bodyParser = require('body-parser')
const app = express()
const ordersJson = require('./public/ordersTest.json');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.post('/api/orders', (req, res) => {
let body = req.body;
console.log(body);
fs.appendFile('./public/ordersTest.json', JSON.stringify(body), err => {
if (err) console.log(err);
})
})
But this thing only appends it to the end of the file. I need to put it inside this orders array
This is my ajax passing an example object in the body of the post:
$(".btn-checkout").on('click', function() {
let date = new Date();
$.ajax({
method : "POST",
url: "/api/orders",
data : {a: "abc"},//{ order: "order",date: date.toDateString(), order: JSON.stringify(cart)},
success : function(success){
console.log(success,'success');
},
error : function(err) {
console.log(err);
}
});
clearCart();
displayClearedCart();
});
You need to parse the JSON file and then treat it like an object. Once you are done with it, convert it to JSON again and overwrite your file. like this
app.post('/api/orders', (req, res) => {
let body = req.body;
var ordersTest = require('./public/ordersTest.json');
ordersTest.orders.push(body);
fs.writeFile('./public/ordersTest.json', JSON.stringify(ordersTest), function(err) {
if (err) res.sendStatus(500)
res.sendStatus(200);
});
})
Not tested, please fix typo error if any.