Mongoose/Express Get all subdocuments api - node.js

So I feel foolish for asking this, and I know there are a ton of related posts on this, but I cannot find anything to work. I'm guessing that it has to do with the index.js since Postman is saying it cannot even connect to the route. I have 2 routes, and the clientRoutes works just fine, postman returns and it shows up on my frontend. However, making any call to the contractRoutes gets me nothing.
I'm trying to pull all 'contracts' subdocs for a single client. I'm new to Express/Mongoose and I'm guessing that I've missed something totally obvious.
index.js
const express = require("express")
const mongoose = require("mongoose")
const cors = require('cors')
const clientRoutes = require("./routes/clientRoutes")
const contractRoutes = require("./routes/contractRoutes")
const bodyParser = require('body-parser');
mongoose
.connect("mongodb+srv://admin:oneterra#cluster0.0cajn.mongodb.net/Octotest?retryWrites=true&w=majority", { useNewUrlParser: true })
.then(() => {
const app = express()
app.use(express.json())
app.use(cors())
app.use(bodyParser.json());
app.use("/api", clientRoutes)
app.use("/api", contractRoutes)
app.listen(5000, () => {
console.log("Server has started")
})
})
client model
const mongoose = require("mongoose")
const schema = mongoose.Schema({
clientId: Number,
firstName: String,
lastName: String,
phone: String,
contracts: [{
contractId: Number,
authNumber: String,
contType: String,
contHours: Number,
contStartDate: Date,
contEndDate: Date
}],
})
module.exports = mongoose.model("Client", schema)
clientRoutes - which works as expected
const express = require("express")
const Client = require("../models/Client.js")
const router = express.Router()
//Client routes
router.get("/clients", async (req, res) => {
const clients = await Client.find()
res.send(clients)
})
router.get("/clients/:clientId", async (req, res) => {
try {
const client = await Client.findOne({ clientId: req.params.clientId })
res.send(client)
} catch {
res.status(404)
res.send({ error: "Client not found"})
}
})
contractRoutes which only brings the error "Cannot GET /api/clients/1/contracts" (1 being the clientId, which has contracts in the db). On clientRoutes, from the first tutorial I used, I did not put '' around ({ clientId : req.params.clientId). In the code below I have it there when I was trying to figure this out, but I get the same result, and again seems to show I'm missing something at the top level.
const express = require("express")
const Client = require("../models/Client")
const router = express.Router()
try{
const client = await Client.findOne({ 'clientId': req.params.clientId })
const contracts = client.contracts;
res.send(contracts)
} catch {
res.status(404)
res.send({error: "Contracts not found"})
}
console.log(contracts)
I've tried using populate
Client.findOne({ 'clientId': req.params.clientId })
.populate('contracts')
.exec(
function(err, client) {
if (err) res.status(500).send(err);
res.json(client.contracts);
}
);
and even if I copy the exact same route for a single client from clientRoutes, but with the contracts endpoint, I get the same error as above
const express = require("express")
const Client = require("../models/Client")
const router = express.Router()
//Client routes
router.get("/clients/:clientId/contracts", async (req, res) => {
try {
const client = await Client.findOne({ clientId: req.params.clientId })
res.send(client)
} catch {
res.status(404)
res.send({ error: "Client not found"})
}
})
Any help is greatly appreciated, I've spent hours running in circles on this and trying every type of different way to make the call. But in dialing it down to even using the same route from clientRoutes but with the contracts endpoint and getting the error, I'm assuming it has to due with the index.js server connection.

So in case anyone comes across this with the same issue, as I put in the comment, express wasn't accepting the 2nd route starting with the same path.
By changing
app.use("/api", clientRoutes)
app.use("/api", contractRoutes)
to
app.use("/api", clientRoutes)
app.use("/api/clients", contractRoutes)
then the route worked fine. I did not see anything in the express docs saying that no path can be designated as the same, but making the change made it work, so there's that.

Related

I receive no response from the requests i send in NodeJS API it just keeps loading

my code was perfectly working a couple of days ago and it suddenly stopped working it's connected to the mongodb cluster but i fail to receive response from the database everytime i send a request it's i tried reinstalling node reinstalling mongoose updating all packages but nothing seemed to work
keeps loading forever
and no response when i cancel it
here's the server.js code :
const express = require('express');
const bodyParser = require('body-parser');
const morgan = require('morgan');
const mongoose = require('mongoose');
const cors = require('cors')
require('dotenv/config');
const authJwt = require('./helpers/jwt')
const errorHandler = require('./helpers/error-handler')
const api = process.env.URL;
mongoose.connect(process.env.DATABASE,
{
useNewUrlParser:true,
useUnifiedTopology:true
})
.then(()=>{
console.log('connected to database')
})
.catch((err)=>{
console.log(err)
})
//variables
const app = express();
const port = 9090
//middleware calls
app.use(bodyParser.json());
app.use(morgan('tiny'));
app.use(express.Router())
//app.use('')
app.use(cors());
app.options('*',cors())
app.use(errorHandler)
app.use(authJwt)
const categoriesRouter = require('./routers/categories')
const productsRouter = require('./routers/products')
const ordersRouter = require('./routers/orders')
const usersRouter = require('./routers/users')
//Routers
app.use(`${api}/categories`,categoriesRouter)
app.use(`${api}/products`,productsRouter)
app.use(`${api}/users`,usersRouter)
app.listen(port,(req,res)=>
{
console.log('server is running in port '+ port )
})
here's one of the routers code :
const {Category} = require('../models/category')
const express = require('express');
const router = express.Router();
router.get('/',async(req,res)=>{
const categoryList = await Category.find();
if(!categoryList)
{
res.status(500).json({success:false})
}
res.status(200).send(categoryList);
})
router.get('/:id',async(req,res)=>{
const category = await Category.findById(req.params.id)
if(!category)
{
res.status(500).json({message:'The category with the given ID'})
}
res.status(200).send(category)
})
router.post('/',async(req,res)=>{
let category = new Category({
name:req.body.name,
icon:req.body.icon,
color:req.body.color
})
category = await category.save();
if(!category)
return res.status(404).send('the fag category cannot be created')
res.send(category)
})
router.delete('/:id', (req,res)=>{
Category.findByIdAndRemove(req.params.id).then(category=>{
if(category)
{
return res.status(200).json({success:true,message:'the category is deleted'})
}
else
{
return res.status(404).json({success:false,message:'the category is not found'})
}
}).catch(err=>{
return res.status(400).json({success:false , error: err})
})
})
router.put('/:id',async (req,res)=>{
const category = await Category.findByIdAndUpdate(
req.params.id,
{
name:req.body.name,
icon:req.body.icon,
color:req.body.color
},
//i want to return the new updated data
{ new:true }
)
if(!category)
{
return res.status(400).send('The category cannot be created!');
}
res.send(category);
})
module.exports = router;
just to let you know it was working a couple of days ago and now it just suddenly stopped working if there's anything i can do or if you've faced the same problem before please reach out
Make sure to send a proper response on the api side of code.
In the case that u are using the express framework, it could look something like this:
router.get('/', (req, res) => {
res.status(200).json({
your: data
})
})

unending Sending request with Get ... Issue when trying to 'get' data from the mongoDB through Postman/ Thunder Client eeventhough there is no error

I have a mongodb collection with a few examples and I was trying to display them on my get method but it keeps showcasing the Processing, Please wait... buffer screen without outputting any result. I am wondering why it takes so long and does not display even after an hour and more when it displayed quite quickly on my simpler tests before.
This is my Usermodel
const mongoose = require("mongoose")
const userSchema = new mongoose.Schema(
{
username: { type:String,unique:true,required:true},
email:{type:String,unique:true,required: true},
password:{type: String,required:true,},
isAdmin:{type:Boolean,default: false,}, },
{
timestamps: true,
});
const userModel = mongoose.model("users_list",userSchema);
This is the user router
const express = require('express');
const userModel = require('../models/users');
const { model } = require('mongoose');
const router = require("express").Router();
router.get("/getUser",(req,res)=> {
userModel.find({},(err,result)=>{
if(err){
res.json("There is an error");
}
else{
res.json(result);
console.log("got result");
console.log(result);
}
});
res.send("Ok");
});
module.exports = router;
And here is how my index.js where all the routers are called and fixated.
const express = require('express');
const app = express()
const mongoose = require('mongoose');
const dotenv = require('dotenv');
const userRouter = require('./apis/routers/userRouter');
const cors = require("cors");
dotenv.config();
mongoose
.connect(process.env.MONG_URL)
.then(() => console.log("DB Connection Successful!"))
.catch((err) => {
console.log(err);
});
app.use(cors);
app.use(express.json());
app.use('/api/users',userRouter);
I have given the right MongoDB URL and it is not enclosed in quotation marks or anything from .env
And right here as you can see in the image, the postman keeps doing this
This sending request is unending and doesn't fetch the data at all. How can I resolve this?

JSON POST requests empty response on Node/Mongo

Edit: I solved it. It was pretty simple, I had imported the routes before setting app.use for body-parser, so it didn't knew hot to parse JSON and thus returned an undefined body.
I'm trying to make a REST API following a tutorial. I made everything exactly as it was done in it, and tried every fix I could think of, but I can't make JSON POST requests work.
After sending a request I'm supposed to get a JSON like this:
{
"_id": "a13d1s2bc12as3a2",
"name": "Name",
"desc": "bla bla",
"_v": 0
}
But instead I'm only getting a 201 Resource with an empty body. Not even an empty object, just nothing.
I tried all the possible configurations in Postman and also HTTPie.
I also tried the suggested fixes changing body-parser config, since I got a clue something was deprecated or changed in the last months (json, urlencoded, etc.)
I checked if Mongoose was connected to the DB using the function it has for checking it (it was).
I have no clue where's the problem.
This is the index:
const express = require("express");
const mongoose = require("mongoose");
const bodyParser = require("body-parser");
const meals = require("./routes/meals");
const orders = require("./routes/orders");
const app = express();
mongoose.connect(process.env.MONGODB_URI, { useNewUrlParser: true, useUnifiedTopology: true });
app.use("/meals", meals);
app.use("/orders", orders);
app.use(express.json());
app.use(bodyParser.json({ type: 'application/json' }));
module.exports = app;
The routes for Meals:
const express = require("express");
const Meals = require("../models/Meals");
const router = express.Router();
router.get("/", (req, res) => {
Meals.find()
.exec()
.then(x => res.status(200).send(x));
});
router.get("/:id", (req, res) => {
Meals.findById(req.params.id)
.exec()
.then(x => res.status(200).send(x));
router.post("/", (req, res) => {
Meals.create(req.body)
.then(x => res.status(201).send(x));
});
router.put("/:id", (req, res) => {
Meals.findOneAndUpdate(req.params.id, req.body)
.then(x => res.sendStatus(204));
});
router.delete("/:id", (req, res) => {
Meals.findOneAndDelete(req.params.id)
.exec()
.then(() => res.sendStatus(204));
});
module.exports = router;
And the model:
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const Meals = mongoose.model("Meal", new Schema({
name: String,
desc: String
}));
module.exports = Meals;
Thank you.
To debug try this
const handleError = function() {
console.error(err);
// handle your error
};
router.post("/", (req, res) => {
Meals.create(req.body, function (err, req.body) {
if (err) return handleError(err);
})
});
You can also try to just provide static data for testing and see if that works, like :
const meal = new Meals({ name: 'some meal',desc: 'some desc' });
meal.save(function (err) {
if (err) return handleError(err);
// saved! return 200 or whatever you needs to do here
});
I solved it. It was pretty simple, I had imported the routes before setting app.use for body-parser, so it didn't knew hot to parse JSON and thus returned an undefined body.
app.use(bodyParser.json());
app.use("/meals", meals);
app.use("/orders", orders);
module.exports = app;

req.params.userId not found ( path set to /:userId) Node.js

I want to get an user by his userId parameter but it doesn't work. The app connects to the database(Atlas), I can create users, retrieve them all in bulk but I can't retrieve them with a specific parameter ( in this case UserId), producing a not found error message.
UserRoutes.js
const express = require('express');
const UserModel = require('../models/UserModel');
const app = express();
app.get('/getusersById/:userId', async (req, res) => {
const user = await UserModel.find(req.params.userId);
try {
res.send(user);
} catch (err) {
res.status(500).send(err);
}
});
UserModel.js
const mongoose = require('mongoose');
// Define Schema
const UserSchema = new mongoose.Schema({
name: {
type: String,
required: true,
trim: true,
},
age: {
type:Number,
required:true
},
userId: {
type:String,
required:true
},
});
//
const User = mongoose.model('user', UserSchema);
module.exports = User;
Server.js
// Open connection to test database
const express = require('express');
const mongoose = require('mongoose');
const UserRouter = require('./routes/UserRoutes.js');
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
const uri = "mongodb+srv://XXXXXXXXXXX#XXXXXXXeXXXX.gcp.mongodb.net/dbusers?retryWrites=true&w=majority";
mongoose.connect(uri,{
userNewUrlParser: true,
useUnifiedTopology: true
});
// Notify if connection was succesful
var db = mongoose.connection;
db.on ('error', console.error.bind(console, 'connection error'));
db.once('open', function() {
console.log("Connection Succesful");
});
db.on('close', () => {
db.removeAllListeners();
});
// Router & Port
app.use(UserRouter);
app.listen(3000,
() => {console.log('Server is running...')});
And this is the postman request:
Postman get userId
Your request is wrong. You defined your path as:
app.get('/getusersById/:userId', /* callback */)
So the request URL should be:
/getusersById/3
and not
/getusersById/?userId=3
'/getusersById/:userId'
What you are doing here is parameters of your request, which is userId
the correct usage of this api is /getusersById/3
app.get('/getusersById/:usersId', async (req, res) => {
const user = await UserModel.find(req.params.usersId );
However it seems you want to use ?usersId=3 for query the user id
You need to use req.query.usersId
app.get('/getusersById', async (req, res) => {
const user = await UserModel.find(req.query.usersId );
You can find examples of query usage : https://coderrocketfuel.com/article/handle-get-request-query-string-parameters-in-express-js
I think you are new to API development. From the image that I can see that you are sending userId as a query parameter. But in code, you are doing req.parms.userId which is used for path params. In your code you defined route for path parameter so the request should be like this:
/getusersById/3
And to be handled as below
app.get('/getusersById/:userId', async (req, res) => {
const user = await UserModel.find(req.params.userId );
However, If you want to pass userId in query parameter then do this:
app.get('/getusersById', ...)
request can be made like this:
/getusersById/?userId=3
and query parameter will be accessible as below:
app.get('/getusersById', async (req, res) => {
const user = await UserModel.find(req.query.userId );
Read this: Query vs Path params

Req.body works with POST req but not GET req. Using Body-Parser

I am able to store data in my mongoDB database using req.body in a POST request but I am not able to retrieve that data using req.body in a GET request. I can retrieve data if I pass a string but not req.body..
I have seen there are multiple posts on this issue in which body parser seems to solve the issue but I am still retrieving undefined even though I have body parser going.
Thanks in advance.
const express = require('express');
const app = express();
const mongoose = require('mongoose');
const path = require('path');
const bodyParser = require('body-parser');
const PORT = process.env.PORT || 2000;
// app.use(express.urlencoded({extended: true}));
app.use(bodyParser.urlencoded({ extended: false }));
// app.use(express.json());
app.use(bodyParser.json());
app.use(express.static('public'));
const database = mongoose.connect('mongodb://localhost/users')
.then(() => console.log('connected to mongoDB!!'))
.catch((err) => console.error('unable to connect', err));
const userSchema = {
name: String,
email: String
}
const User = mongoose.model('User', userSchema);
app.post('/api/users',(req,res) => {
const user = new User({
name: req.body.name,
email: req.body.email
});
const create = user.save();
res.send('created a user account');
});
app.get('/api/users', async (req,res) => {
const find = await User
.find({ name: req.body.name});
console.log(find);
res.send(`your data is ${req.body.name}`);
})
app.listen(PORT, () => console.log(`listening on port ${PORT}`));
GET Resquest doesn't have a body. Instead you need to use query parameters.
You can do something like:
app.get('/api/users', async (req,res) => {
const find = await User
.find({ name: req.query.name});
console.log(find);
res.send(`your data is ${req.query.name}`);
})
To complement Leandro Lima's answer,
for route parameters:
app.get('/api/users/:name', async (req,res) => {
const find = await User
.find({ name: req.params.name});
console.log(find);
res.send(`your data is ${req.params.name}`);
})
The .../:name part makes up req.params.name (for example, .../:id then is req.params.id).
And for query parameters: /api/users/Dave?sex=male&developer=yes
Then req.queryhas {sex: 'male', developer: 'yes'}, thus could use req.query.sex and req.query.developer as you see fit.
Check out this question too: Node.js: Difference between req.query[] and req.params

Resources