JSON object persisting state from previous calls in nodejs express - node.js

In my express code I have a config in json, refer to the "template" variable below. I am doing some modifications in it for some purpose in call one and then in my second call when I am trying to get it, it is returning the modified value of field xyz that is A while I expect it to return the original config.
I did try to move that first line "const template = xxx" inside each method so that a new object gets created but it is still having the same issue. How can I fix this?
const express = require("express");
const { db, pgp } = require("../../helpers/dbConnection");
const { auth } = require("../middlewares/Auth");
const router = express.Router();
const template = require('../../config/template.json');
router.get("/callone", async (req, res) => {
try {
template.xyz = "A"
return res.status(200).send();
}
catch (err) {
return res.status(500).send(err.message);
}
});
router.get("/calltwo", async (req, res) => {
try {
return res.status(200).send(template);
}
catch (err) {
return res.status(500).send(err.message);
}
});

This approach is generally a bad idea.
It doesn't work if you ever want to scale beyond 1 server.
It doesn't work when there's more than 1 user using the system at the same time.
The right way to handle something like this is by adding either a database, or a session system.
Sessions feels like the right approach here, because that concept is specific for letting you store information specific to a user, and store/retrieve that over the course of several requests.

Related

Node.js stucked with var declaration

I have encode\decode up (React Next.sjs + Node.js Express). I've done almost everything I wanted. The only one problem I don't know how to solve this is decoding. For decoding\encoding I'm using Cryptr library.
Here below my decode function code:
export const decodeBlog = async(req, res, next) => {
const { text, secretkeyword } = req.body;
const cryptr = new Cryptr(secretkeyword);
const encrypted = text;
let decrypted; //The problem is here
try {
const decrypted = cryptr.decrypt(encrypted, secretkeyword);
console.log("encrypted data", decrypted);
} catch (err) {
console.log(err);
return res.status(400).json({message: "Incorrect Secret keyword"});
}
return res.status(200).json({message: decrypted});
};
Here in postman I'm getting an empty {} brackets.
But in node.js console I have console.log and it works:
I will be really appreciate if you help me. Thank you in advance!:)
You have two variables named decrypted:
one inside the try-catch block: this one is declared with const, it gets a value and is output with console.log
one outside the try-catch block: this one is declared with let and output with res.json, but it never gets a value.
Omit the word const inside the try-catch block. The let outside suffices.

how to prevent extra stuff being send in req.body in Express.js

I was just wondering is it possible to restrict what is been sent in the req.body
like can I create a middleware that checks the req.body for extra junk before it goes to the controller
is this even an issue?
if I just select the needed data it doesn't matter how bloated is the req.body?
thank you.
I guess you want to reject requests containing body parameters with names that aren't in an allowed list. It should be relatively easy to do that.
const createError = require('http-errors')
const bodyAllowedList = new Set (['username', 'password'])
function checkbody(req,res,next) {
for (const prop in req.body) {
if(req.body.hasOwnProperty(prop) && !bodyAllowedList.has(prop)) {
next(createError(400, 'unexpected parameter in POST body'))
}
}
}
route.post('whatever', checkbody, function (req, res, next){
/* your route handler here. */
})
You see the general pattern: look at the properties of the req.body object: they are the body parameters. If you see one you don't want call next(error) and express will kick an error back to the requestor.
You can do some object destructuring as a way to limit the data being passed in and used, but that may clutter up your route handler code. I would go with destructuring in your controller methods, rather than modifying the data through middleware, which can lead to confusion.
For example:
const User = require("./user");
const express = require("express");
const router = new express.Router();
router.post("/login", async (req, res, next) => {
// let's pretend req.body has username, password, and otherJunk.
//option 1
const userThing1 = await User.authenticate1(req.body);
// option 2
const userThing2 = await User.authenticate2(req.body);
// option 3
const { username, password, otherJunk } = req.body;
const userThing3 = await user.authenticate3({username, password});
// ...do stuff with userThing responses here
}
the User class with the authenticate1, authenticate2, authenticate3 methods are defined below
class User {
// see route handler first
static async authenticate1(data) {
// destructure here, grab only what you need
const {username, password} = data;
// do stuff with username and password here.
// note that data.otherJunk is still accessible here.
}
static async authenticate2({username, password }) {
// destructured in the parameters, do stuff with username and password here
// otherJunk is not accessible here.
}
static async authenticate3({username, password, otherJunk }) {
// destructured in the parameters, do stuff with username and password here.
// note that otherJunk will not be accessible because of the way we passed variables into the route handler.
}
}
module.exports = User;
There are of course many ways to do this, but I'd go with either option 1 or option 2, grabbing username, password, and ignoring otherJunk in the destructuring process. It still allows for the necessary data to be passed through, but makes it so that you're grabbing only what you need for explicitness and readability.

Pass parameter to middleware function and return result

So guys, what I want to accomplish and not manage to get is to write a function that performs a query against database as a middleware, using req and res objects, and also can be used in a socket connection, to pass parameters to it and not use the req and res objects. Also I want it to return the result of the query. I tried using a middleware wrapper
function myFunc(param1, param2){
return (req, res) => {
here query
}}
works when hitting the endpoint with or without args i send, but dosnt work when i call the function from somewhere else
When you call myFunc you get returned a new function. You need to invoke that funcion, something like
myFunc('value1', 'value2')()
This will cause an error since you have no request or response object. These are express objects.
A better way to re-use the database code would be to put it in a function and inject that function to the middlewere.
E.g.
function getArticleById(id) {
return db.query('select * from articles where id = $1', [id])
}
Then create a middlewhere that takes this function in as dependency
function makeMiddlewere (getArticleById) {
return (req, res) => {
return articleById(req.query.id).then(articles => {
res.json(articles)
})
}
}
Then in your code you can do
Normal way
getArticleById(5).then(articles => {
console.log(articles)
})
Create the middlwere an
const express = require('express')
const getArticleById = require('./articlebyid')
const makeMiddlewere = require('./makemiddlewere')
const middlwere = makeMiddlwere(getArticleById)
const app = express.app
app.get('/article', middlewere)

Express middleware with async operation that happens only once

I am trying to append some data to my request object using a middleware, but I want to do it only once the server is up.
So I tried doing it with a middleware, while trying to use a function's context, but it's a bit problematic to perform such an action on a middleware, because I cannot pass a promise as a middleware.
This is what I'm trying to do:
const setupData = async () => {
const data = await getSomeData();
return (req, res, next) => {
req.data = data;
next();
}
}
app.use(setupData());
I tried using the solution suggested here, but it won't work as this will happen on every request.
Any idea how can I go around this? I can always put the info on a global var, but I would like to avoid it.
I also saw some in-memory packages to help with it (such as node-cache), but I would like to do it with a middleware.
Thanks in advance
Just cache the result using a normal variable:
let data = null;
function setupData (req, res, next) {
if (data !== null) {
req.data = data;
next();
}
else {
getSomeData().then(result => {
data = result
req.data = data;
next();
});
}
}
app.use(setupData);
This is the minimal, least complicated implementation. You can of course refactor it to be much DRYer and less prone to mistakes by taking out the caching logic:
Cleaner Implementation
let cache = null;
async function getCachedData() {
if (cache === null) {
cache = await getSomeData();
}
return cache;
}
Which makes setupData much cleaner:
function setupData (req, res, next) {
getCachedData().then(data => {
req.data = data;
next();
});
}
Either way, the cache is triggered on the first request. This means that there is a possibility that a second request may arrive before the data is possibly cached. So at startup the getSomeData() function may run more than once.
Really call getSomeData() ONLY ONCE
If you really want to call getSomeData only once you must call it before setting up Express:
async function main () {
const data = await getSomeData();
const app = express();
//
// set up express middlewares...
//
app.use((req,res,next) => {
req.data = data;
next();
});
//
// set up routes...
//
app.listen(config.port);
}
main(); // start everything
The key here is to realize that we have been trying to do everything backwards: to set up a constant value asynchronously AFTER starting to set up Express. The natural flow of the program wants the constant value to exist BEFORE we begin setting up Express so we only perform everything else inside the async function (here called main). Not try to run the async function while setting up Express.
You can do it without async:-
const setupData = (req, res, next) => {
// You can put a condition here so that it runs only once
getSomeData().then((data) => {
req.app.locals.data = data //The data can be accessed in the next middleware using req.app.locals
next();
}).catch((error) => {
console.log("Error Occured");
res.status(400).end("Error Occurred");
})
}
app.use(setupData);
You should see the documentation of getSomeData and see how it works

How can I force my function to wait promises before moving on?

I read another posts but they were not solving my particular problem.
I'm trying to move all dependent entries from one user to a default one before deleting the user. But even with Promise.all().then() I'm getting an error saying that I still have foreign key constraints preventing me to delete the user (But if i try to delete it manually after that it works fine, because I really moved all the dependencies to the default user).
async delete (req, res){
try {
const {id} = req.body;
// Here I call all the recipes that this user owns
const recipes = await Recipe.find({where: {chef_id: id}});
// Create the Promises for every UPDATE request in the Database
const changeChefPromises = recipes.map( recipe => {
Recipe.update(recipe.id,{chef_id : 1})
});
/* HERE is the problem, I'm trying to update every single recipe
before I delete the User, but my program is trying to delete
the User before finishing the Update process for all dependencies */
await Promise.all(changeChefPromises).then(() => {
Chef.delete(id);
});
return res.redirect(`/admin/chefs`);
} catch (err) {
console.error(err);
}
}
const changeChefPromises = recipes.map( recipe => {
Recipe.update(recipe.id,{chef_id : 1})
});
This is not creating an array of promises which is what you're expecting. You either need to remove the body of the arrow function or explicitly return the promise inside the body.
E.g.
const changeChefPromises = recipes.map(recipe => Recipe.update(recipe.id,{chef_id : 1}));
or
const changeChefPromises = recipes.map( recipe => {
return Recipe.update(recipe.id,{chef_id : 1})
});
Also, it's a bit weird to mix async/await and .then() so it might also be a good idea to change:
await Promise.all(changeChefPromises).then(() => {
Chef.delete(id);
});
to
await Promise.all(changeChefPromises);
await Chef.delete(id);

Resources