I'm currently working with nodejs, I created a server side function that returns and prints data from a database.
app.get('/renderMainDashboard', (req,res)=>{ //DASHBOARD DATA
con.connect(err => {
if (!err){
con.query("SELECT * FROM owners", (err, data, fields) =>{
console.log(data); //IT LOGS THE DATA INTO DE VS TERMINAL
return data;
})
}
});
});
I need this function to be called from the client side, so there is a class that makes the fetch inside the constructor:
export default class{
constructor() {
this.title = "Dashboard";
fetch('http://localhost:5600/renderMainDashboard') //DEFAULT GET ()
.then(response => response.json())
.then(finalResponse => {console.log('Datos recibidos desde el server', finalResponse);});
//DOESN'T LOG 'Datos recibidos...' TO WEB CONSOLE
//.then(console.log('Response from then statement'); //IT DOES THE LOG
}
//----
}
The function actually works, when I try to do the fetch it is still working but I need to log the response. As you may see, there is a then statement with a console.log('Datos recibidos...') but it is not working. Any idea of what I may be doing wrong?
Actual output of the DB:
[
TextRow {
id: 1,
firstName: 'Andres',
lastName: 'Gonzalez',
email: 'androsogt#gmail.com',
personalKey: 'androso+1234-',
phoneNumber: '35006115'
},
TextRow {
id: 2,
firstName: 'Pedro',
lastName: 'Contreras',
email: 'sirpedro#gmail.com',
personalKey: 'holamundo',
phoneNumber: '41508886'
},
TextRow {
id: 3,
firstName: 'Yuhana',
lastName: 'Melgar',
email: 'melgar.keyla#gmail.com',
personalKey: 'COD2002',
phoneNumber: '37578639'
}
]
You don't end your request by sending a response. See this example:
app.get('/', function (req, res) {
res.send('hello world')
})
You should use res.send() method to end your request and send back data.
Why it doesn't log? Because response.json() returns a rejected promise as there's no response (timeout) and hence, second .then doesn't get called.
Your express get /renderMainDashboard handler is not sending anything back to the client.
Try replacing:
return data;
with:
res.status(200).json(data); // provided that data is a valid JSON object
Related
I am trying to make a fetch in react.js using backend node.js api url which then further makes a post api call within the server to another route using another url.
How am i supposed to do that?
Take a look at the code below:
From the frontend "/confirm" api will be called using fetch.
app.post("/save-info",(req,res)=>{
//Does some more stuff and returns a
response to the confirm api.
}
app.post("/confirm", (req,res)=>{
//Does some stuff
//Makes another call inside this api
to the "/save-info" route
}
Updated Query
Guys, please take a look at the code below
async function signUp(info) {
const {
firstName,
lastName,
address,
email,
phoneNumber,
password,
city,
postal_code,
} = info;
console.log("only info: ", phoneNumber);
const queryInsertNewUser = `INSERT INTO public."Users"(
"First_Name", "Email", "Mobile", "Address", "User_Type", "Last_Name", "password", "city","postal_code")
VALUES ('${firstName}', '${email}', '${phoneNumber}', '${address}', 'Customer', '${lastName}', '${password}','${city}','${postal_code}')
RETURNING user_id;`;
// return { email: "kalo", id: "23" };
client.query(queryInsertNewUser, (err, result) => {
if (!err) {
if (result.rowCount == 1) {
console.log("User registered.");
return {
status: "Success",
msg: "User Registered Successfully",
user_id: result.rows[0].user_id,
};
} else {
console.log("Not Registered.");
return {
status: "Error",
msg: "Could not register user. Call Developer.",
};
}
} else {
console.log(err);
}
});
}
app.post("/signup", async(req, res) => {
const { email } = req.body;
const data = await signUp(req.body);
console.log(data);
});
data is printing undefined. Still it does not work
You don't need to call your route again. Just create an function and call it.
const saveInfo = ()=>{
// do wathever you want here
return "some stuff done"
}
app.post("/save-info",(req,res)=>{
// you probabbly don't need this route.
}
app.post("/confirm", (req,res)=>{
//Does some stuff
const data = saveInfo()
return res.send({success:true, done})
}
So, I have used the passport library from npm for user credentials authentication for a project. Now, I have defined a payload that needs to be sent as a method paramater in the auditEvent() function as shown in the code snippet below. However, while debugging the code, the debugger reaches Line 36 of the code where passport.serialzeUser() has been defined but it fails to go inside the serializeUser() and without calling the auditEvent() function written inside, it directly moves on to the deserializeUser() function and then stops.
Since, the passport.serializeUser() is wriiten inside the initializePassport() function, I am pasting the complete function body here.
const initializePassport = async (router) => {
router.use(passport.initialize());
router.use(passport.session());
passport.serializeUser((req, user, done) => {
const payload = {
...(user?.tenantId ? {tenantId: user?.tenantId}: {}),
...(user?.companies[0] ? {companyId: user?.companies[0]}: {}),
...(user?.firstName || user?.lastName ? {identifier: `${user?.firstName||""} ${user?.lastName||""}`}: {}),
entityType: "USER",
createdBy: req.id,
modifiedBy: req.id,
auditEvent: {
type: "USER LOGIN",
source: "passport",
description: `Login request ${req.id}`,
status: "SUCCESSFUL",
},
};
auditEvent(req.id, req.log, payload, getAppContext());
done(null, user);
});
passport.deserializeUser((user, done) => {
done(null, user);
});
initializeLocalStrategy(router);
await initializeAuthRoutes(router);
};
I am expecting that the debugger will reach auditEvent() function and will call it to perform the microservice task. I am also sending the Postman request body that is being sent to one of the routes.
//Postman request body
The route defined is: http://localhost:7501/auth/signup
Request Type: POST
{
"email":"test#test.com",
"password":"Test#124"
}
The code for the above route is as follows:
router.post(
"/auth/signup",
passport.authenticate("local-signup"),
async (req, res) => {
res.cookie("isLoggedIn", true);
res.status(200).json({
userId: req.user.userId,
tenantId: req.user.tenantId,
companyId: req.user.companyId,
});
}
);
So basically, I'm trying to separate my code that handles data (mongoose) from my express Router code, since I might want to use it elsewhere too.
The first thing I did was, I got rid of the res.json() calls, since I don't want the code to only work returning a http response. I want it to return data, so I can then return that data from my router as a http response, but still use it as regular data elsewhere.
Here is a function I wrote to get data from mongoose.
module.exports.user_login = data => {
console.log(data);
ModelUser.findOne({email: data.email}).then(user => {
if(!user){
console.log({email: 'E-mail address not found'});
return {
status: response_code.HTTP_404,
response: {email: 'E-mail address not found'}
}
}
bcrypt.compare(data.password, user.password).then(isMatch => {
if(!isMatch){
console.log({password: 'Invalid password'});
return {
status: response_code.HTTP_400,
response: {password: 'Invalid password'}
}
}
const payload = {
id: user.id,
email: user.email
};
jwt.sign(
payload,
config.PASSPORT_SECRET,
{
expiresIn: "1h"
},
(err, token) => {
console.log({
status: response_code.HTTP_200,
response: {
success: true,
token: token
}
});
return {
status: response_code.HTTP_200,
response: {
success: true,
token: token
}
}
}
);
});
});
};
When this code gets executed in my route like so:
router.post("/login", (req, res) => {
const { errors, isValid } = validateLogin(req.body);
if(!isValid) return res.status(400).json(errors);
console.log("ret", dm_user.user_login(req.body));
});
The log says the return value of user_login() is undefined, even though right before the return statement in user_login() I am logging the exact same values and they are getting logged.
Before I changed it to a log, I tried to store the return value in a variable, but obviously that remained undefined as well, and I got the error: 'Cannot read propery 'status' of undefined' when trying to use the value.
I am definitely missing something..
Well you have an small callback hell here. It might be a good idea to go with async / await and splitting up your code into smaller chunks instead of putting everyhing in 1 file.
I rewrote your user_login function:
const { generateToken } = require("./token.js");
module.exports.user_login = async data => {
let user = await ModelUser.findOne({ email: data.email });
if (!user) {
console.log({ email: "E-mail address not found" });
return {
status: response_code.HTTP_404,
response: { email: "E-mail address not found" }
};
}
let isMatch = await bcrypt.compare(data.password, user.password);
if (!isMatch) {
console.log({ password: "Invalid password" });
return {
status: response_code.HTTP_400,
response: { password: "Invalid password" }
};
}
const payload = {
id: user.id,
email: user.email
};
let response = await generateToken(
payload,
config.PASSPORT_SECRET,
response_code
);
return response;
};
I have moved your token signing method into another file and promisfied it:
module.exports.generateToken = (payload, secret, response_code) => {
return new Promise((res, rej) => {
jwt.sign(
payload,
secret,
{
expiresIn: "1h"
},
(err, token) => {
if (err) {
rej(err);
}
res({
status: response_code.HTTP_200,
response: {
success: true,
token: token
}
});
}
);
});
};
Now you need to change your router function into an async:
router.post("/login", async (req, res) => {
const { errors, isValid } = validateLogin(req.body);
if(!isValid) return res.status(400).json(errors);
let result = await dm_user.user_login(req.body);
console.log(result);
});
In addition: You get undefined because you return your value to an callback function
I also would seperate your routes from your controllers instead of writing your code inside an anonymous function
Please notice that whenever you are trying to return any value you are always present in the callback function and that is definitely not going to return any value to its intended place.
There are a couple of things you can improve about your code :
1.Donot use jwt inside your code where you are making database calls, instead move it where your routes are defined or make a separate file.
2.If you are intending to re-use the code, I would suggest you either use async-await as shown in the answer above by Ifaruki or you can use something like async.js. But the above shown approach is better.
Also always use 'error' field when you are making db calls like this:
ModelUser.findOne({email: data.email}).then((error,user) => {
So in general, the shopping cart details are stored in local storage, being parsed back and assinged to an array, and then should be subscribed and posted to MongoDB, but returns "undefined":
checkout.ts
confirmOrder(){
let orderDetails: any = {};
orderDetails.firstName = this.checkOutForm.controls['firstName'].value;
orderDetails.lastName = this.checkOutForm.controls['lastName'].value;
orderDetails.phone = this.checkOutForm.controls['phone'].value;
orderDetails.address = this.checkOutForm.controls['address'].value;
orderDetails.country = this.checkOutForm.controls['country'].value;
orderDetails.city = this.checkOutForm.controls['city'].value;
this.orderItem=[];
for (let i in this.productAddedToCart) {
this.orderItem.push({
product_Name:this.productAddedToCart[i].product_Name,
id:this.productAddedToCart[i].id,
product_Price:this.productAddedToCart[i].product_Price,
product_Quantity:this.productAddedToCart[i].product_Price,
type:this.productAddedToCart[i].type,
product_Img: this.productAddedToCart[i].product_Img,
product_Description:this.productAddedToCart[i].product_Description,
_id:this.productAddedToCart[i]._id
});
}
orderDetails.product= this.orderItem
debugger
console.log("orderDetails:", orderDetails.product)
this.connectionService.sendReceipt(this.checkOutForm.value).subscribe((res) =>{
debugger
console.log("res is:", res);
});
this.orderService.CreateOrder(orderDetails).subscribe((data:OrderDetails) => {
debugger
console.log("data is:", data) // prints nothing
debugger
this.globalResponse = data
console.log("data is:", this.globalResponse) //prints nothing
debugger
});
alert('Your order has been received.');
this.checkOutForm.reset();
this.disabledSubmitButton = true;
this.router.navigate(['/']);
localStorage.removeItem('product');
localStorage.removeItem('cartItemCount');
};
this.globalResonse is "undefined".
Why is it not possible to console.log(data)?
Doesnt it get subscribed?
order.service.ts:
CreateOrder(orderDetails:OrderDetails){
return this.http.post(`${this.uri}/order`, orderDetails,{
observe:'body'})
}
My backend if needed(works):
//create order
orderRoute.route('/').post((req, res) =>{
Product.findById(req.body.productId)
.populate('product')
.then(product => {
if(!product){
return res.status(404).json({
message: "product not found"
});
}
const order = new OrderDetails({
_id: new mongoose.Types.ObjectId(),
product: req.body.productId,
email: req.body.email,
firstName:req.body.firstName,
lastName: req.body.lastName,
phone: req.body.phone,
address: req.body.address,
});
return order.save()
})
.then(result => {
console.log(result);
return res.status(200).json({
message: "Order was Created",
order: {
order_id: result._id,
product: result.product,
firstName:result.firstName,
lastName: result.lastName,
email: result.email,
phone: result.phone,
address: result.address,
createdAt: new Date,
},
request:{
type:"GET",
order_url: "http://localhost:5000/order/" + result._id
}
});
})
.catch(err => {
console.log(err);
res.status(500).json({
error:err
});
});
});
I also receive 2 errors:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
(node:17548) UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
Much Appreciated!
I think the reason for not to receive any data from executing CreateOrder() because it get an interesting HTTP error. From following this document I got this content and it says,
Error [ERR_HTTP_HEADERS_SENT] is an interesting error that is fired up when a server tries to send more than one response to a client. What this means is that for a given client request the server previously sent a response (either a success response with the resource requested or error response for a bad request) back to the client and now is unexpectedly trying to send another response
So your backend tries to send the response twice. that's the issue here. If you could open the network tab in the browser console you can inspect if it's true.
Hope this helps.
I'm trying to do an API call to my express server to fetch employees that work in the same place based on the location ID. However, the API call returns just an empty array while it does work in the command-line interface.
Employee model
module.exports = mongoose => {
var schema = mongoose.Schema(
{
first_name: String,
last_name: String,
address: {
housenumber: Number,
street: String,
city: String,
zip: Number,
country: String
},
phone: Number,
mobile: Number,
email: String,
enrollment_date: Date,
staff_id: Number,
location: { type : mongoose.Schema.ObjectId, ref : 'location' },
department: String,
function: String,
active: Boolean
},
{ timestamps: true }
);
schema.method("toJSON", function() {
const { __v, _id, ...object } = this.toObject();
object.id = _id;
return object;
});
const Employee = mongoose.model("employee", schema);
return Employee;
};
Employee routing for API
router.get("/location/:location_id", employees.findAllByLocation);
Employee controller handling above call
exports.findAllByLocation = (req, res) => {
Employee.find({ location: req.params.location_id })
.then(data => {
res.send(data);
})
.catch(err => {
res.status(500).send({
message:
err.message || "Some error occurred while retrieving Employees."
});
});
};
Dummy database data to test on
Postman API call result
However, trying to find the user with that location ID in the command line interface does work and gives the desired output.
[
So somehow it messes up and I can't seem to figure out why it's doing this. I did some research and found that it might have to do with the location being a reference as an ObjectId. So I tried wrapping the req.params.location_id to an ObjectId might fix it but that didn't work.
What's the best way to get this working?
In order to use promise chain, you have to return something and then returned value will be passed chained “then()” as data. In your example you should
return Employee.find({location:req.params.location_id})