I have the following code:
app.get("/:listName", function (req, res) { const ListCollection = mongoose.model(req.params.listName, itemSchema); ListCollection.find().then(
function (result) {
if (result.length === 0) {
ListCollection.insertMany(
defaultItems,
function (err) {
if (err) {
console.log(err);
} else {
console.log("Successfully saved items.");
}
}
);
res.redirect("/"+req.params.listName);
} else {
try {
res.render("list", { listTitle: "Work List", newListItems: result });
} catch (error) {
console.log(error);
}
}
}).catch((err) => { console.log(err); })});
All I am trying to do is, when the user ends a URL I get the first param of it and create or load a Model with that name as a list.
If such modal has no data, I add 3 elements, else I just return whats there.
But I mostly get this error:
OverwriteModelError: Cannot overwrite `buba` model once compiled.
at Mongoose.model (C:\Users\Mangetsu\OneDrive\Documentos\Coding\todolist-v2-starting-files\node_modules\mongoose\lib\index.js:582:13)
at C:\Users\Mangetsu\OneDrive\Documentos\Coding\todolist-v2-starting-files\app.js:85:35
at Layer.handle [as handle_request] (C:\Users\Mangetsu\OneDrive\Documentos\Coding\todolist-v2-starting-files\node_modules\express\lib\router\layer.js:95:5)
at next (C:\Users\Mangetsu\OneDrive\Documentos\Coding\todolist-v2-starting-files\node_modules\express\lib\router\route.js:137:13)
at Route.dispatch (C:\Users\Mangetsu\OneDrive\Documentos\Coding\todolist-v2-starting-files\node_modules\express\lib\router\route.js:112:3)
at Layer.handle [as handle_request] (C:\Users\Mangetsu\OneDrive\Documentos\Coding\todolist-v2-starting-files\node_modules\express\lib\router\layer.js:95:5)
at C:\Users\Mangetsu\OneDrive\Documentos\Coding\todolist-v2-starting-files\node_modules\express\lib\router\index.js:281:22
at param (C:\Users\Mangetsu\OneDrive\Documentos\Coding\todolist-v2-starting-files\node_modules\express\lib\router\index.js:354:14)
at param (C:\Users\Mangetsu\OneDrive\Documentos\Coding\todolist-v2-starting-files\node_modules\express\lib\router\index.js:365:14)
at Function.process_params (C:\Users\Mangetsu\OneDrive\Documentos\Coding\todolist-v2-starting-files\node_modules\express\lib\router\index.js:410:3)
And sometimes it randomly works.
Also, in my DB the collections are being created always.
Related
I created a simple custom exception based on this link as follows:
function userErr(message) {
logger.info("reach user error function")
const error = new Error(message);
error.type = "userErr";
return error;
}
function failureErr(message) {
logger.info("reach failure error function")
const error = new Error(message);
error.type = "failureErr";
return error;
}
The expected behaviour is Express will throw this error to the custom error handler middleware at the end of the server.js file:
app.use((error, req, res, next) => {
console.log("Error Handling Middleware: " + error.message);
if (error.type === "userErr") {
res.status(400).json({
status: "error",
statusCode: "400",
message: error.message
});
} else if (error.type === "failureErr") {
res.status(500).json({
status: "fail",
statusCode: "500",
message: error.message
});
} else {
res.status(500).json({
status: "error",
statusCode: "500",
message: error.message
});
}
});
app.listen(8080, () => {
console.log("listening on 8080...");
}); //the server object listens on port 8080
When I put these functions above the routes (app.get, app.post, etc...) in the server.js file (this should be index.js for most people), it works fine. But when I start stripping out these routes and put them into a route file in the routes folder instead, the traffic does come to the route correctly, but whenever an error occurs and executes the function above, JavaScript threw an error at the 2nd line, which is:
const error = new Error(message);
for example:
const error = new Error(message);
^
Error: [object Object]
at new failureErr (file:///.../src/server.js:89:17)
at file:///.../src/routes/testRoutes.js:104:21 {
type: 'failureErr'
Which is weird! I have tried putting these functions into a separate file and importing them into the route file, but it still shows the same error.
I mimicked the folder into the codesandbox (I couldn't manage to make it run) so you can understand the context. The index.js by itself is the one that works, while index2.js with the routers folder is the one that failed.
Appreciate any feedback on the questions, or any ideas on where I did something wrong
The code you show in your sandbox is doing this throw new userError("It's an user error");, but userError() is not properly set up as a constructor and thus can't be called with new. This is the code in your sandbox:
app.get("/api/v1/test", (req, res, next) => {
try {
const userErr = req.headers.userErr;
console.log(userErr);
if (userErr === "true") {
throw new userError("It's an user error");
} else {
throw new failureError("It's an failure error");
}
} catch (e) {
next(e);
}
});
The code you show has not made either userError() or failureError() into classes or constructors. They are merely functions. Therefore, they can't be called with new.
If you want to make them into classes, then do something like this:
class userError extends Error {
constructor(message) {
super(message);
console.log("reach user error function");
this.type = "userErr";
}
}
Note, this is the more modern way of doing this than what is shown in the article you reference (which is apparently old).
Or, you can just use what you have as functions:
app.get("/api/v1/test", (req, res, next) => {
try {
const userErr = req.headers.userErr;
console.log(userErr);
if (userErr === "true") {
next(userError("It's an user error"));
return;
} else {
next(failureError("It's an failure error"));
return;
}
res.send("ok");
} catch (e) {
next(e);
}
});
I know this is a scope issue, but am not quite sure what I'm missing here.
I have a simple endpoint where, if a user is found I return a simple 'no user found message. Here is the function:
export const getOneUser = (req, res) => {
const { id } = req.params;
const foundUser = users.find((user) => user.id == id)
checkUserExists(foundUser)
res.send(foundUser)
}
I've replace my standard guard with a helper function. so instead of:
if(!userfound) res.send('No user was found')
with the following function:
const checkUserExists = (x) => {
if(!x) res.send('No user found')
}
Since I am constantly using this guard I thought this might be a helpful function to write.
The problem is I'm getting the following error, no matter what I do, event if I import { respons } from 'express' and use that:
ReferenceError: res is not defined
at checkUserExists (file:///Users/cnak/Desktop/PROJECTS/TEST3/controllers/users.js:7:12)
at getOneUser (file:///Users/cnak/Desktop/PROJECTS/TEST3/controllers/users.js:18:5)
at Layer.handle [as handle_request] (/Users/cnak/Desktop/PROJECTS/TEST3/node_modules/express/lib/router/layer.js:95:5)
at next (/Users/cnak/Desktop/PROJECTS/TEST3/node_modules/express/lib/router/route.js:137:13)
at Route.dispatch (/Users/cnak/Desktop/PROJECTS/TEST3/node_modules/express/lib/router/route.js:112:3)
at Layer.handle [as handle_request] (/Users/cnak/Desktop/PROJECTS/TEST3/node_modules/express/lib/router/layer.js:95:5)
at /Users/cnak/Desktop/PROJECTS/TEST3/node_modules/express/lib/router/index.js:281:22
at param (/Users/cnak/Desktop/PROJECTS/TEST3/node_modules/express/lib/router/index.js:360:14)
at param (/Users/cnak/Desktop/PROJECTS/TEST3/node_modules/express/lib/router/index.js:371:14)
at Function.process_params (/Users/cnak/Desktop/PROJECTS/TEST3/node_modules/express/lib/router/index.js:416:3)
How do I create a helper function that can actually pass a response?
I've also tried to return the 'res.send('No user found')
Thanks
Because you are not defining res in your checkUserExists function.
const checkUserExists = (x, res) => {
if(!x) res.send('No user found')
}
and
...
checkUserExists(foundUser, res);
...
If you are still getting error after sending res in checkUserExists method. Then problem is not here. You need to check your route, that you are passing actual http res instance here or not. Can you please paste your code of index.js and router file.
In my app I have a category collection that saves the category title with its image ID. The image is saved in another collection with its meta data like path , type and so on. So for retrieving category I should retrieve category image in image collection by its ID and add image path to category object that is retrieved from category collection and send it to client...But I don't know where should I send categories to client?
When I send the response face this error :
throw er; // Unhandled 'error' event
^
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:561:11)
at ServerResponse.header (H:\node.js\online-store\app\node_modules\express\lib\response.js:771:10)
at ServerResponse.send (H:\node.js\online-store\app\node_modules\express\lib\response.js:170:12)
at ServerResponse.json (H:\node.js\online-store\app\node_modules\express\lib\response.js:267:15)
at ServerResponse.send (H:\node.js\online-store\app\node_modules\express\lib\response.js:158:21)
at H:\node.js\online-store\app\controllers\pcategory.controller.js:123:19
at H:\node.js\online-store\app\node_modules\mongoose\lib\model.js:4845:18
at processTicksAndRejections (internal/process/task_queues.js:77:11)
Emitted 'error' event on Function instance at:
at H:\node.js\online-store\app\node_modules\mongoose\lib\model.js:4847:15
at processTicksAndRejections (internal/process/task_queues.js:77:11) {
code: 'ERR_HTTP_HEADERS_SENT'
}
This is my code :
exports.getAll = async (req, res) => {
try{
const categories = await ProductCategory.find({});
categories.map(async(category)=>{
await File.findById(category.imageID).exec(function(err,file){
if(err){
console.log(err)
}else if(file) {
category.imagePath = file.file_path;
tempCategories.push(category)
}
res.send(tempCategories);
})
})
return res.send(tempCategories);
}catch {
res.json(err =>{
console.log(err);
res.status(500).send({
message:
err.message || "There is an error in retrieving category"
});
})
}
}
The problem is that nothing in your code is waiting for the asynchronous operations you're doing in your map callback to complete, so it does the res.send at the end right away — and then does res.send again within the map callback later when the async operations complete. Instead, wait for them to finish and send the result.
Also, you're using res.send where I suspect you want res.json, and using res.json later incorrectly (it doesn't take a callback).
See comments:
exports.getAll = async (req, res) => {
try {
// Get the categories
const categories = await ProductCategory.find({});
// Get the files for the categories, wait for the result
const result = await Promise.all(categories.map(async (category) => {
const file = await File.findById(category.imageID).exec();
// You probably can't modify the `category` object, so let's create
// and return a new object
return {...category, imagePath: file.file_path};
}));
// Send the result converted to JSON
return res.json(tempCategories);
} catch (err) { // Accept the error
// Send an error response
res.status(500).json({
message: err.message || "There is an error in retrieving category"
});
}
};
Side note: Your original code was using map without using the array it creates. That's an antipattern (sadly it seems to be one someone somewhere is teaching). I wrote up why and what to do instead here. (In my update to your code, I still use map, but I use the array it creates, passing it to Promise.all so we can wait for all those promises to settle.)
Your Code Like this,
Now Issue is You are sending two times Headers.
You can use like this, Firstly Declare array and push into it what you need and then last of your logic return it or send it.
exports.getAll = async (req, res) => {
try {
const categories = await ProductCategory.find({});
let tempCategories = []; // New Line
await Promise.all(categories.map(async (category) => {
await File.findById(category.imageID).exec(function (err, file) {
if (err) {
console.log(err)
} else if (file) {
category.imagePath = file.file_path;
tempCategories.push(category)
}
});
return category;
}));
res.send(tempCategories);
} catch {
res.json(err => {
console.log(err);
res.status(500).send({
message:
err.message || "There is an error in retrieving category"
});
})
}
}
I have two functions and i can't access from function 2 to function 1.
How can i do that?
class firstController
{
one(req, res)
{
var stamp = request.query("Select 'ALB'+left(newid(),5)+right(newid(),5)+ left(newid(),5)+right(newid(),5) as stamp");
Promise.all([stamp]).then(function(listOfResults)
{
var data = listOfResults[0][0].stamp;
res.send(data);
}).catch(function(err)
{
// ... query error checks
console.log(err);
});
}
two(req, res){
//get the data returned from function 1
console.log(this.one(req, res));
}
}
module.exports = firstController;
i have this error:
UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): TypeError: Cannot read property 'getStamp' of undefined
Thank you
Use this to access functions within the same class in ES6. This is quite complex in ES5 and ES6 compared to other languages and I recommend you have a look at it.
class firstController
{
one(req, res)
{
res.send("hello");
}
two(req, res){
this.one(req, res);
}
}
module.exports = firstController;
UPDATE
To get the data from one into two you'll need to return the result of the Promise like this
one(req, res) {
var stamp = request.query("Select 'ALB'+left(newid(),5)+right(newid(),5)+ left(newid(),5)+right(newid(),5) as stamp");
return Promise.all([stamp]).then(function(listOfResults) {
return listOfResults[0][0].stamp;
}).catch(function(err) {
// ... query error checks
console.log(err);
return err;
});
}
two(req, res){
//get the data returned from function 1
console.log(this.one(req, res));
}
Only use res.send when you want to return data to the client
I'm trying to automatically log in a user with PassportJS.
This is my current code:
myRouter.get('/signin', function* (next) {
user = {...};
var res = this.res; // needed for the function below
this.req.login(user, function(err) {
if (err)
console.log('error logging in user - '+err);
return res.redirect('/'); // <--- line 439
});
});
But when I run it, I get the error:
error logging in user - TypeError: undefined is not a function
TypeError: undefined is not a function
at /srv/www/domain.com/app.js:439:32
at /srv/www/domain.com/node_modules/koa-passport/node_modules/passport/lib/http/request.js:49:48
at pass (/srv/www/domain.com/node_modules/koa-passport/node_modules/passport/lib/authenticator.js:293:14)
at Authenticator.serializeUser (/srv/www/domain.com/node_modules/koa-passport/node_modules/passport/lib/authenticator.js:295:5)
at Object.req.login.req.logIn (/srv/www/domain.com/node_modules/koa-passport/node_modules/passport/lib/http/request.js:48:29)
at Object.<anonymous> (/srv/www/domain.com/app.js:434:26)
at GeneratorFunctionPrototype.next (native)
at Object.dispatch (/srv/www/domain.com/node_modules/koa-router/lib/router.js:317:14)
at GeneratorFunctionPrototype.next (native)
at Object.<anonymous> (/srv/www/domain.com/node_modules/koa-common/node_modules/koa-mount/index.js:56:23)
A quick semi-derp moment and I realize to redirect in koa it does not use res but this, you must do the following:
var res = this; // needed for the next function
this.req.login(user, function(err) {
if (err)
console.log('error logging in user - '+err);
return res.redirect('/');
});
Your code is fine, it is just that res is called response, so just change
var res = this.res; in var res = this.response; and it will work fine. res does exist, but it is the Node http module response, not the Koa Response object, and therefore does not have any redirect method. The redirect is aliased to this, which is why you can use this.redirect, but it really is a Response method.
Take a look at http://koajs.com/#context for more details.
To avoid having to assign this, or response, you could just bind this to your function, I think it is cleaner in most cases:
myRouter.get('/signin', function* (next) {
user = {...};
this.req.login(user, function(err) {
if (err)
console.log('error logging in user - '+err);
return this.redirect('/'); // <--- line 439
}.bind(this));
});