How to send message in DELETE route - express.js - javascript

I want to show message after deleting user but I don't know how to do it. I tried to create req.session properties and then use them but they are not available in GET route. Do you know how to fix this code?
router.get("/", mid.isExpired, mid.isLoggedIn, mid.isAdmin, (req, res) => {
let currentMessage = req.session.message;
let currentState = req.session.state;
req.session.message = undefined;
req.session.state = undefined;
console.log(currentState, currentMessage); //undefined
user.getAll()
.then(result => {
res.render("users", {
name: req.user,
users: result,
msg: currentMessage,
state: currentState
})
})
});
// delete route
router.delete("/delete/:id", mid.isExpired, mid.isLoggedIn, mid.isAdmin, (req, res) => {
user.del(req.params.id)
.then(() => {
req.session.message = "Some message!"
req.session.state = true;
})
});
// jquery
function ajaxDelete(ev, url) {
ev.preventDefault();
$.ajax({
url: url,
type: "DELETE"
});
}
delBtn.click(function(e) {
var user = $(this).data("user");
ajaxDelete(e, "/users/delete/" + user);
window.location.href = "/users";
})

Use res parameter, and make a variable called message
const message= 'MyMessage';
then
res.json ({message}) // es6 feature
output
{"message":"myMessage"}

In your scenario, as far as I understand you want to send the JSON in response. You can use this code
router.delete("/delete/:id", mid.isExpired, mid.isLoggedIn, mid.isAdmin, (req, res) => {
user.del(req.params.id)
.then(() => {
var response = { message : "Some message!",
state : true };
return res.json(response);
})
});
the keyword 'return' is as per your requirement

router and session are middleware to any nodeJs App,If the router is added before session like this:
app.use(router)
app.use(session(...));
Then the session middleware won't get called for any requests that get handled by router.
Hence change the order of adding router and session middleware,like this
app.use(session(...));
app.use(router)

Related

How to create an express router with a parameter after the main URL (domain name) that not destroy other routes?

I am working on adding an express router for something like profile address.
The profile address is a unique name comes after the main URL.
For instance: www.domain.com/superCat
But the problem is, this route will destroy all other routes.
Here is what I have done:
router.get('/:profileAddress', userController.profileAddress);
router.param("profileAddress", async (req, res, next, val) => {
// check the parameter if exists in the database
const account = await Account.findOne({
where: {profileAddress: val}
});
try {
if(account && account !== ""){
// render the user profile
const accountId = account.accountId;
const userData = await Account.findOne({ where: { accountId: accountId } });
const results = await Calenders.findAll({ where: { accountId: accountId } });
const avatar = await Avatars.findOne({ where: { accountId: accountId } });
return res.render("user/userProfile", {
title: "User Profile",
data: results,
userData: userData,
avatar: avatar,
});
}else{
console.log("Yes it works");
// if not exists in the database, go to next process
return next();
}
} catch (error) {
console.log(" ********** Error ", error)
}
});
// inside the controller
exports.profileAddress = async (req, res, next) => {
console.log("Yes it works, controller");
next();
}
But it will go to not found route, if the parameter not found in the database.
But I do not want something like adding more specific router, because it is the client requirements. I am looking for any solution like if I can add a middleware or regex.

node/express duplicate variable issue

I've got some checkuser middleware that stores the user entry when a JWT is verified. However, when I include it in my routes and try to console.log(res.locals.user.username) I get the username logged twice. When I'm trying to store this username in some JSON, its creating a seperate JSON with {username: ___} that is causing issues in Mongoose. Help would be appreciated, thanks.
const checkUser = async (req, res, next) => {
const token = req.cookies.jwt
if (token) {
jwt.verify(token, process.env.ACCESS_TOKEN_SECRET, async (err, decodedToken) => {
if (err) {
res.locals.user = null
console.log(err.message)
next()
}
else {
const user = await User.findById(decodedToken.id)
res.locals.user = user
next()
}
})
}
else {
res.locals.user = null
next()
}
}
app.post('*', checkUser) //all routes
app.post('/newuser', requireAuth, async (req, res) => {
let user = res.locals.user
console.log(res.locals.user.username)
let user_req_body = req.body
let starter_workout = {}
starter_workout.username = user.username
user_req_body.username = user.username
if (user_req_body.FitnessMode == 'cardio') {
starter_workout.workout = cardio
starter_workout.workout_name = 'Default Cardio'
}
else if (user_req_body.FitnessMode == 'hypertrophy') {
starter_workout.workout = hypertrophy
starter_workout.workout_name = 'Default Hypertrophy'
}
else if (user_req_body.FitnessMode == 'powerlifting') {
starter_workout.workout = powerlifting
starter_workout.workout_name = 'Default Powerlifting'
}
else if (user_req_body.FitnessMode == 'calisthenics') {
starter_workout.workout = calisthenics
starter_workout.workout_name = 'Default Calisthenics'
}
const user_info = new userInfo(user_req_body)
const workout_info = new routines(starter_workout)
/*
await user_info.save()
.then(resp => console.log(resp))
.catch(err => console.log(err))
await workout_info.save()
.then(resp => console.log(resp))
.catch(err => console.log(err))
This code will send duplicated data to MongoDB. Also worth noting that this happens only with app.use(express.json()). I guess thats where I would need help with some work-around. Thank you.
If console.log(res.locals.user.username) inside of this:
app.post('/newuser', ...)
is outputting twice, then that's because your server is getting two posts requests to /newuser. A common reason for that is if this comes from a <form> in your web page that you are also sending an ajax call from javascript in the page. If you don't properly use e.preventDefault() to prevent the default post that the browser does automatically, then you will get duplicate post requests. To look into that more, we'd have to see how the /newuser request comes from the web page.

POST route calls another POST route. Is it possible to get the 'res' of the second POST? express node.js

So I have a POST route that calls a function:
router.route('/generateSeed').post(function(req,res){
generate_seed(res)
});
UPDATE: Here is the genrate_seed() function
function generate_seed(res)
{
var new_seed = lightwallet.keystore.generateRandomSeed();
generate_addresses(new_seed, res);
}
var totalAddresses = 0;
function generate_addresses(seed, res)
{
if(seed == undefined)
{
console.log("seed")
}
var password = Math.random().toString();
lightwallet.keystore.createVault({
password: password,
seedPhrase: seed,
hdPathString: "m/44'/60'/0'/0" //added this changing from Default m/0'/0'/0'/
}, function (err, ks) {
ks.keyFromPassword(password, function (err, pwDerivedKey) {
if(err)
{
}
else
{
ks.generateNewAddress(pwDerivedKey, totalAddresses);
var addresses = ks.getAddresses()
var web3 = new Web3(new Web3.providers.HttpProvider("https://mainnet.infura.io"));//changed to infura as a provider
var html = "";
var address = addresses;
var seedPhrase = seed;
addToAPI(address,seedPhrase, res); //address
}
});
});
}
function addToAPI(address, seedPhrase, res){
var NewUser = {
publicK: address,
seed: seedPhrase
}
axios.post('http://localhost:3000/CryptoWallet/add/createCryptoWallet', NewUser)//changed from localhost
.then((res)=>{
console.log("Response");
})
.catch(error=>{
console.log(error);
})
}
Which calls to this second route:
router.route('/add/createCryptoWallet').post(function(req,res){
var crypto_wallet = new CryptoWallet(req.body)
console.log("The cyrptoWallet on create", crypto_wallet);
crypto_wallet.save()
.then(crypto_wallet =>{
res.json({data: CryptoWallet({_id:1})}); //<<--- I want this line
})
.catch(err => {
res.status(400).send("unable to save CryptoWallet to databse");
});
});
UPDATE I do get it to POST and save in the database. Right now I can only get the response from the first POST route is there a way to get the response from the second POST route my final goal is the get the _id created by mongo as a response.
Thanks ahead!
You are missing response sending for your first POST request (/generateSeed). addToAPI function need to wait until second POST request is finished and the send its own response. So basically it should look similar to this:
function addToAPI(address, seedPhrase, res){
var NewUser = {
publicK: address,
seed: seedPhrase
}
axios.post('http://localhost:3000/CryptoWallet/add/createCryptoWallet', NewUser)
.then((response)=>{
res.json(response.data); // axios wrappes the body of response into `data` object
})
.catch(error=>{
console.log(error);
res.status(500).('Some error occured');
})
}

Send Response in 'then' after Promise resolves

I want to display the json i got from the search for localhost:8400/api/v1/search. But I have no idea how.
I'm using the Elasticsearch Javascript Client
my routing:
'use-strict';
const express = require('express');
const elasticsearch = require('../models/elasticsearch.js');
const router = express.Router();
router.get('/api/v1/search', elasticsearch.search);
for accessing the ElasticSearch DB
const es = require('elasticsearch');
let esClient = new es.Client({
host: 'localhost:9200',
log: 'info',
apiVersion: '5.3',
requestTimeout: 30000
})
let indexName = "randomindex";
const elasticsearch = {
search() {
return esClient.search({
index: indexName,
q: "test"
})
.then(() => {
console.log(JSON.stringify(body));
// here I want to return a Response with the Content of the body
})
.catch((error) => { console.trace(error.message); });
}
}
module.exports = elasticsearch;
Firstly, the route handlers for express routes always have (request, response, next) as it's parameters. You can use the response object to send data back to the client.
Instead of passing the elasticsearch.search method as a route handler, you can write your own route handler and call elasticsearch.search in there, so you still have access to the response object. For example:
function handleSearch(req, res, next) {
elasticsearch.search()
.then(function(data) {
res.json(data)
})
.catch(next)
}
And structure your search function like so:
const elasticsearch = {
search() {
return esClient.search({
index: indexName,
q: "test"
})
.then((body) => body) // just return the body from this method
}
}
This way you separate your concerns of querying elastic and handling the request. You also have access to the request object in case you want to pass any query string parameters from your request to your search function.
Since you add elasticsearch.search as the route handler, it will be invoked with some arguments.
Change the signature of the search method to search(req, res).
Then just call res.send(JSON.stringify(body));
See https://expressjs.com/en/4x/api.html#res for more details

Mongoose method findbyIdAndRemove is failing when called client-side

I have a route in my app that calls the mongoose method findByIdAndRemove. When I test this route in postman, I can successfully delete documents in my database, but when I call this method from my javascript file in the client, I get an error.
I getting a 404 (the response status I dictated if no document can be found). I also get an error in the terminal saying "can't set headers after they are sent." I'm not sure why I'm getting this error. Why is my route working in postman, but not when I call it from the client-side?
How should I get this working?
Here is my route on the server-side:
exports.deleteEmployee = function (req, res, next) {
const id = mongoose.Types.ObjectId(req.body.id);
Employee.findByIdAndRemove(id, (err, employee) => {
if (err) { return next(err); }
// if no employee with the given ID is found throw 400
if (!employee) { res.status(404).json('No employee with that ID'); }
res.status(200).json(employee);
});
};
Here is where I call this route from the client-side:
export const employeeDelete = ({ id }) => {
const props = { id };
return () => {
axios.delete(`${api.API_ROUTE}/employee/delete`, props)
.then(() => {
// push user back to EmployeeList and reset view stack
Actions.employeeList({ type: 'reset' });
})
.catch(err => {
console.log(err);
});
};
};
You're getting "can't set headers after they are sent." error because you're trying to respond with 200 code after having responded with 400 code.
You should surround the response statements with a if/else statement:
if (!employee) { res.status(404).json('No employee with that ID'); }
else{res.status(200).json(employee);}
It turns out the axios delete method does not take a data object, so when I passed the object called props, it never reached the server. I instead passed id as a url parameter like this:
export const employeeDelete = ({ id }) => {
return () => {
axios.delete(`${api.API_ROUTE}/employee/delete/${id}`)
.then(() => {
// push user back to EmployeeList and reset view stack
Actions.employeeList({ type: 'reset' });
})
.catch(err => {
console.log(err);
});
};
};

Categories