firebase once('value') function on database not response - node.js

I would happy for your help
I'm trying to use firebase on nodejs server.
after initial configurations I build a rest on node server that used to fetch data from firebase database
Here is the first version of the code
app.get('/api/users/:id', (req,res) =>{
const usersRef = firebase.database().ref('users');
usersRef.once('value')
.then((snapshot) => {
console.log(snapshot);
res.status(200).send(snapshot.val())
})
.catch((error) => {
console.log(error);
res.status(404).send(error.message)
})
}))
I've checked the route with postman and found that I didn't received any response from that route
I've check with logs that the route received the request and I found that I must create async call to database, so, I created middleware
And here is the new version of code:
const asyncMiddleware = fn =>
(req, res, next) => {
Promise.resolve(fn(req, res, next))
.catch(next);
};
app.get('/api/users/:id', asyncMiddleware(async (req,res,nex) =>{
const usersRef = firebase.database().ref('users');
await usersRef.once('value')
.then((snapshot) => {
console.log(snapshot);
res.status(200).send(snapshot.val())
})
.catch((error) => {
console.log(error);
res.status(404).send(error.message)
})
}))
But the problem continue even after the changes.
So I found that the reason for the problem is because the 'once' function stack when he tried to fetch data from firebase and not return any response.
I would really like to your help here
thanks

I guess it has to do with the way you handle the asynchronous requests. Try the code below and let's see if we'll get any luck.
const fetchUsers = () => new Promise((resolve, reject) => {
try{
const usersRef = firebase.database().ref('users')
usersRef.once('value', (snapShot) => {
resolve(snapShot)
})
}catch(err){
reject(err)
}
})
app.get('/api/users/:id', async (req,res) =>{
const users = await fetchUsers()
/**
* clean the users response
* and respond with data
*/
res
.status(200)
.json({
data: users //cleaned
})
}))

So, After Investigate I found a solution for this problem.
I've used axios on server send request by using REST API of firebase
https://firebase.google.com/docs/reference/rest/database

Related

Empty row on MongoDB data insertion using express.js

I want to add data to my MongoDB collection. I'm getting this data via a local Flask API. I'm GETting the data on my React Frontend and it's displaying fine. I'm not sure why I can't do the same thing on my express nodejs backend. I want to get that same data and use it to build the entity that I'm going to store.
This is how I'm attempting to get the data
app.get('/', async (req, res) => {
let initialData = {};
axios.get('http://localhost:3000/details').then((res) => {
initialData = res.data;
});
const recruit = new RecruitModel({ email:initialData.email,
mobile_number:initialData.mobile_number,
name:initialData.name});
try {
await recruit.save()
res.send("inserted data")
} catch (error) {
console.log(error)
}
})
I'm pretty sure something wrong there and nowhere else. Because if I pass static information instead it's correctly stored, no issues.
You are saving to the database's Recruit Collection before the promise is resolved. Since data to save in the Recruit Collection is dependent upon the result from the API which will initially return the promise, therefore, use promise resolving functions to wait for its result.
Solution#1 (using .then function):
app.get('/', async (req, res) => {
let initialData = {};
try {
axios.get('http://localhost:3000/details').then((response) => {
initialData = response.data;
const recruit = new RecruitModel({
email: initialData.email,
mobile_number: initialData.mobile_number,
name: initialData.name,
});
recruit.save().then((response) => res.send('inserted data'));
});
} catch (error) {
console.log(error);
}
});
Solution#2 (using async await keywords):
app.get('/', async (req, res) => {
try {
const response = await axios.get('http://localhost:3000/details');
const recruit = new RecruitModel({
email: response.data.email,
mobile_number: response.data.mobile_number,
name: response.data.name,
});
await recruit.save();
res.send('inserted data');
} catch (error) {
console.log(error);
}
});
Either solution will work in your case.

Hide api using expressjs and react

I'm using MERN stack for a project. I want to hide my api endpoints on the frontend when I call them. I'm now making a request from React like so:
useEffect(() => {
axios
.get("https://MY_API_URL/posts") // MY_API_URL is the url that I want to hide
.then((res) => {
dispatch(setCurrentUser(res.data));
})
.catch((err) => {
console.log(err);
});
});
This is how I'm GETing the posts from the expressjs:
controllers/posts.js
const Post = require("../models/post");
const getPosts = async (req, res) => {
try {
const post = await Post.find();
res.status(200).json(post);
} catch (err) {
res.status(404).json({ message: err });
}
};
I want to make the request to the url from the backend so that my API is hidden in the client.
This is what I have tried in the frontend:
useEffect(() => {
axios
.get("http://localhost:3000/posts")
.then((res) => {
dispatch(setCurrentUser(res.data));
})
.catch((err) => {
console.log(err);
});
});
And my backend now looks like this but it doesn't work. I also have removed the Posts.find() inside the request, I'm not sure if it is still necessary or how am I going to use this?
controllers/posts.js
const getPosts = async (req, res) => {
try {
const response = await axios.get(
"https://MY_API_URL/posts"
);
const posts = response.data;
console.log(posts);
res.status(200).json(posts);
} catch (err) {
res.status(404).json({ message: err });
}
};
On localhost it works fine, but when I push my code to github and deploy it, it doesn't work on the deployed version then in the localhost it also stops working.
Error message on console:
GET http://localhost:3000/posts 404 (Not Found)

React.js + Node.js - Error when responding from server. "UnhandledPromiseRejectionWarning: Error: Request failed with status code 304"

As the title suggest, I get a weird error when responding with data from my server.
In homepage.js (which I want to load after loggin in) I have this request to the server to get the posts and then set the posts to the response.
useEffect(() => {
//userService.getDashboard() === Axios.get('http://localhost:3001/homepage')
userService.getDashboard().then((response) => {
setListOfPosts(response)
});
}, []);
This request first goes to the homepage.js, which further sends a request to getPosts, like so:
const headers = req.headers;
const getPosts = Axios.get('http://localhost:3001/getPosts', {headers: headers});
getPosts.catch((response) => {
//NEVER GET ANY RESPONSE???
console.log('Error in homepage.js')
//res.send(response);
});
getPosts.then((response) => {
//NEVER GET ANY RESPONSE???
res.send(response.data);
});
And lastly in the chain I have the getPosts router which does:
router.get('/', authenticateToken, async (req, res) => {
await db.query('SELECT * FROM posts',
(err, result) => {
if (err) {
console.log('HELLO FROM ERROR')
res.send({errorMessage: err});
} else {
console.log(result)
res.send(result);
}
});
});
So I can confirm that after every request to homepage I get all the way to getPosts() and the database query always works fine and goes into the result where "console.log(result)" lies and I can confirm that the result is indeed all the posts. The weird stuff happens when I'm sending back the data. So from getPosts() I'm obviously doing a res.send(result) which sends the data back to homepage.js. But this is when I get the error "UnhandledPromiseRejectionWarning: Error: Request failed with status code 304"
Any idea why?
you should not use res.send inside the .then of axios
this code works for me
useEffect(() => {
getPosts.then((response) => {
console.log("inside getPosts.then ");
console.log(response);
});
and this is my controller file to send request to backend:
const axios = require("axios");
export const getPosts = axios.get("http://localhost:5000/tasks/taskscheck");
getPosts.catch((response) => {
console.log("Error in homepage.js");
});
getPosts.then((response) => {
console.log("inside then get posts");
console.log(response);
});
I have tasks project and I can see in the response all my tasks.

multiple async-await get requests not working in PERN stack app

I'm working on building an inventory management application using PERN stack. I have a modal where I need to make 2 GET requests and when I console.log in front end both requests are getting Status 200 response. However in my express server, first get request is working fine but the second request is not receiving anything.
My frontend code
const openModal = async () => {
setDetailModalOpen(true)
try {
await Promise.all([
(async () => {
const serial_number = props.bacsSerial
const response = await fetch(`http://localhost:5000/bacslist/demoinventory/${serial_number}`)
const parseResponse = await response.json()
console.log(response)
setInputs({
bacsUnit: parseResponse.bacs_unit,
serialNumber: parseResponse.serial_number,
partNumber: parseResponse.part_number,
bacsLocation: parseResponse.bacs_location,
description: parseResponse.bacs_description
})
setBacsId(parseResponse.id)
setBacsData(parseResponse)
})(),
(async () => {
const response2 = await fetch(`http://localhost:5000/bacslist/demoinventory/${bacsId}`)
console.log(response2)
})()
])
} catch (err) {
console.error(err.message)
}
}
My backend code
router.get("/demoinventory/:serial_number", async (req, res) => {
console.log('This one is working')
try {
const {serial_number} = req.params
const getDemoBacs = await pool.query(
"SELECT * FROM demo_inventory WHERE serial_number = $1", [serial_number]
)
res.json(getDemoBacs.rows[0])
} catch (err) {
console.error(err.message)
}
})
router.get("/demoinventory/:bacsId", async (req, res) => {
console.log(req.params)
console.log('This one is not working')
try {
const getHistoryData = await pool.query(
"SELECT * FROM demo_inventory_history"
)
console.log(getHistoryData)
res.json(getHistoryData)
} catch (err) {
console.error(err.message)
}
})
Sorry, Kinda new to this stuff so this isn't exactly an answer but I'm not allowed to leave a comment. I can't see your state variables with the code you posted, but are you sure that BacsId is being set to state before it is used in the second call, or is the parameter in the second call being sent empty, thus not using the right URL? Just a thought.

Node.js: Better way to resolve Promise from another API

Suppose I have two APIs, the first API is called by the client. Then it will call a API on the storage server to store some data. The storage server will return an response immediately with status code 202.
app.post('/create/:requestId', (req, res) => {
const { requestId } = req.params;
// Call 3rd party API
axios.post('/store', { id: requestId });
});
After the data is successfully stored, the storage service will call another API on the server as a webhook to notify us that the data is stored.:
app.post('/resolve/:requestId', (req, res) => {
// Called by the storage server to notify the data is successfully stored
});
What I need is that, when the client calls POST /create/:requestId, it won't return until the data is successfully stored on the storage server. One way to do so is that:
const pendingRes = [];
app.post('/create/:requestId', async (req, res) => {
const { requestId } = req.params;
// Call 3rd party API
const result = await axios.post('/store', { id: requestId });
if (result.data.success) {
pendingRes.push({ id: requestId, res });
}
});
app.post('/resolve/:requestId', (req, res) => {
// Called by the storage server to notify the data is successfully stored
const { requestId }= req.params;
const resToResolve = pendingRes.find(r => r.id === requestId);
const idx = pendingRes.findIndex(r => r.id === requestId);
if (resToResolve) {
// Response to the create API
resToResolve.res.json({ success: true });
pendingRes.splice(idx, 1);
}
// Response to the resolve API
res.json({ success: true });
});
I know this can solve the problem but I wonder if there is any better way to do that such as using Promise. I don't like this method because actually there are many similar APIs on the storage server and I need to create many arrays for saving pending res.
Of course, I cannot change the API on the storage server :(
You can create and await a Promise which will be resolved at /resolve/:requestId.
const requestId2resolve = new Map();
app.post('/create/:requestId', async (req, res) => {
const { requestId } = req.params;
// Call 3rd party API
const result = await axios.post('/store', { id: requestId });
if (result.data.success) {
await new Promise(resolve => requestId2resolve.set(requestId, resolve));
res.json({ success: true });
}
});
app.post('/resolve/:requestId', (req, res) => {
// Called by the storage server to notify the data is successfully stored
const { requestId }= req.params;
if (requestId2resolve.has(requestId)) {
const resolve = requestId2resolve.get(requestId);
resolve();
requestId2resolve.delete(requestId);
}
// Response to the resolve API
res.json({ success: true });
});

Resources