Cloud Function Not Returning Any Documents - node.js

Over the last couple of days my Cloud Functions have been failing for reasons I can't figure out. A basic query to fetch a document is not returning anything.
I've been through the documentation, and since this is such a simple query, I'm not sure where it could be failing. I've hardcoded the document reference number and I'm sure the document exists.
I'm only facing this issue from Cloud Functions. I'm able to query the table and return the document from a Flutter app I'm building.
exports.sendEventInvites = functions.https.onCall((data, context) => {
return sendEventInvites.send(data, context).then((result) => {
return result;
}).catch((error) => {
console.log(error);
return {
status: 500,
message: 'Failed to create event document',
}
});
});
function send(event, context) {
let db = admin.firestore();
return new Promise(resolve => {
db.collection(`users`).doc('hardcoded-value').get().then(doc => {
if (!doc.exists) {
console.log("Failed to fetch organizer document. Invites not sent");
return resolve({
status: 501,
message: "Failed to send invites"
});
}
// a bunch of code here that never gets executed because doc.exists is false
}).catch(error => {
console.log(error);
return resolve({
status: 503,
message: "Failed to send invites"
});
});
});
}
I'm not getting any errors, just no document. I've tried initializing admin both ways from the documentation:
admin.initializeApp({credential: admin.credential.cert(require('./secret-doc')), databaseURL: "db-url"});
and
admin.initializeApp(functions.config().firebase);
I'm using the following relevant npm modules:
"#google-cloud/firestore": "^2.2.4"
"firebase-admin": "^8.2.0"
"firebase-functions": "^3.1.0"
"firebase-tools": "^7.1.0"

Related

Node GET by ID API

I have follow the instructions to create a NODE API here.
I'm trying to have a few endpoints with a NODE app to serve data to my React UI.
The database is mongodb where I have a collection for 'stores'.
I have 2 GET calls:
One to retrieve all stores
One to retrieve a store by ID
Node app.js:
app.get('/viewstores', (request, response) => {
storesCollection.find({}).toArray((error, result) => {
if (error) {
return response.status(500).send(error);
}
response.send(result);
});
});
app.get("/viewstores/:id", (request, response) => {
storesCollection.findOne({ "_id": new ObjectId(request.params.id) }, (error, result) => {
if(error) {
return response.status(500).send(error);
}
response.send(result);
});
});
I make my API calls from axios in React.
If I make a call to the first API to retrieve all stores, there no problem at all, but if I try to make the API call by ID, I still get all stores from the first API.
It seems that I am not able to target the GET by ID api.
React app
React.useEffect(() => {
axios.get('http://localhost:5000/viewstores', {
params: { _id: params.storesid}
})
.then(({data}) => {
console.log("DATA ==> ", data)
})
.catch(error => console.log("ERROR API GET ==> ", error))
}, [])
MongoDB store sample:
_id: ObjectId("12345")
businessname:"ABC"
businessaddress:"address abc 1"
Any idea why when I try to call the GET by ID I always get back the whole collection?
Thanks in advance.
Joe.
Assume params.storesid is 12345,
your current React code sends requests to http://localhost:5000/viewstores?_id=12345, and the route /viewstores is reached. To reach the /viewstores/:id route, the URL should be something likes http://localhost:5000/viewstores/12345 then Express will capture the 12345 part in the URL to request.params.id. You can try the code below:
React.useEffect(() => {
axios.get(`http://localhost:5000/viewstores/${params.storesid}`)
.then(({data}) => {
console.log("DATA ==> ", data)
})
.catch(error => console.log("ERROR API GET ==> ", error))
}, [])
You can read about Express route parameters in the official document.

AngularJs $http request stays pending and does not return value from the database

I am currently writing a route which allows me to recieve information from a stored procudre I have in a database. I have written a request in AngularJS and a route in NodeJS but I am just recieving a pending request in the chrome Network developer window. I can see that the console.log in the NodeJs app has the data I require so it has retrieved it but there is nothing coming back in any of the console logs in the the AngularJS app.
Here is the code for the both the angularJS app and the Node App:
AnglaurJS:
checkForReplenishmentEmptyTrolley = async () => {
LIBRIS.extensions.openLoadingModal();
console.log('in checkForReplenishmentEmptyTrolley');
try {
const varPromise = await $http.get(`${LIBRIS.config.stockService}stockMovement/checkForUnattachedTrolley`)
.then((response) => {
console.log(response);
// Request completed successfully
}, (error) => {
// Request error
console.log(error);
});
console.log(varPromise.data);
// 1. check that there are no ghost replenish - lines 1-15
console.log('in try/catch');
console.log('promise', varPromise);
} catch (error) {
console.log(error);
}
},
NodeJS code:
app.get(`${ROUTE}/attachTrolley`, async function(req, res){
const newRequest = await DB.newRequest();
console.log('we have made it to the route');
try {
console.log('we have made it to the Try/Catch route');
newRequest.input();
const record = await newRequest.execute('dbo.usp_STK_CheckForUnattachedTrolley');
res.json(record)
console.log(record, 'record');
} catch (err){
handleError(res, err);
console.log(err);
}
});
The problem is that you are doing a .then on a awaited promises and not returning anything from that. You have two choice here
Either return response from then so when you try to access the value here console.log(varPromise.data); it works.
Or remove the .then alltogather as it is not required because you are awaiting it any ways.
Basically just do this
checkForReplenishmentEmptyTrolley = async () => {
LIBRIS.extensions.openLoadingModal();
console.log("in checkForReplenishmentEmptyTrolley");
try {
const varPromise = await $http.get(`${LIBRIS.config.stockService}stockMovement/checkForUnattachedTrolley`);
console.log(varPromise.data);
// 1. check that there are no ghost replenish - lines 1-15
console.log("in try/catch");
console.log("promise", varPromise);
} catch (error) {
console.log(error);
}
};
Hope this fixes your issue.
Solved it! I had no return statement in my route!

get value from firestore take time

The problem is that the value from the database is updated after the response to google action is finished , i have tried couple of option to make the function to wait for the value to update, but it doesn't work,
i need to execute twice to get the right valuelog
function operation(callback) {
dialogflowAgentDoc.doc(format).get()
.then(doc => {
console.log(doc.data().Url);
Url = doc.data().Url;
})
.catch((err) => {
console.log('Error getting documents', err);
});
callback(Url);
}
app.intent("Default Welcome Intent", conv => {
new GetFormat();
console.log("GetFormat Started");
new operation(function(Url) {
console.log("Ask Started");
conv.ask(
new SimpleResponse({
speech: "Playing Gallay Tzahal",
text: "Playing Gallay Tzahal"
}),
new MediaObject({
name: 'Gallay Tzahal News',
url: Url,
description: "text",
icon: new Image({
url: 'https://upload.wikimedia.org/wikipedia/he/thumb/3/30/GaltzLogo.svg/150px-GaltzLogo.svg.png',
alt: 'Media icon',
}),
})
);
});
conv.ask(suggestions3);
});
Loading data from the cloud takes take. To prevent blocking your app while waiting for that data, the Firestore (and most modern web APIs) load the data asynchronously and then call a function you pass into then() when the data is available.
This means that code that needs the data from Firestore must be inside the then() callback, which gets called when the data is available. So:
function operation(callback) {
dialogflowAgentDoc.doc(format).get()
.then(doc => {
console.log(doc.data().Url);
Url = doc.data().Url;
callback(Url);
})
.catch((err) => {
console.log('Error getting documents', err);
});
}

Issues writing response actions in firebase functions

I have a function in index.js and I'm trying to resolve an account id from a response on an API. The original response is the following:
{
"data": {
"user": null,
"account": {
"id": 865,
"email": "mitch#gmail.com",
"plan_identifier": "dnsimple-business",
"created_at": "2018-06-24T00:55:29Z",
"updated_at": "2018-06-24T00:56:49Z"
}
}
}
And my code is the following:
exports.dnsCheckAuthorization = functions.https.onRequest((req, res) => {
cors(req, res, () => {
dnsimple.identity.whoami().then((response) => {
return res.status(200).send(response.data.account.id);
}).catch(error => (
res.status(500).send(error)
))
});
});
Finally, the error I receive in PostMan is the following:
Error: could not handle the request
And the error in the Firebase log is the following:
Function execution took 519 ms, finished with status: 'response error'
I've tried literally everything I can think of to get just the ID returned by this function and just can't figure it out. What am I missing?
UPDATE
I got this to work with the following code. Not quite what I want though. I want to return just the account id.
exports.dnsCheckAuthorization = functions.https.onRequest((req, res) => {
cors(req, res, () => {
dnsimple.identity.whoami().then((response) => {
var accountID = response.data.account.id;
console.log('account id is', accountID);
return res.status(200).json({id: accountID});
}).catch(error => (
res.status(500).send(error)
))
});
});
res.send() is an express only function. So it may not work if you did not create your server using express. Instead, you could use try something like this -
res.status(200).end(response.data.account.id)

MongoDB Error: Cannot use retryable writes with limit=0

I'm currently working on my first node.js rest api with express, mongodb (atlas cloud) and mongoose, when i try to make a .remove request i get this error:
{
"error": {
"name": "MongoError",
"message": "Cannot use (or request) retryable writes with limit=0",
"driver": true,
"index": 0,
"code": 72,
"errmsg": "Cannot use (or request) retryable writes with limit=0"
}
This is my request:
router.delete('/:productId', (req, res, next) => {
const id = req.params.productId;
Product.remove({ _id: id })
.exec()
.then(result => {
res.status(200).json(result);
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
})
}); ;
});
The findOneAndRemove() function would work more accordingly since its specific to the filtering method passed in the function .findOneAndRemove(filter, options) to remove the filtered object. Still, if the remove process is interrupted by the connection the retryRewrites=true will attempt the execution of the function when connected.
More information here
When using retryRewrites set to true tells the MongoDB to retry the same process again which in fact can help prevent failed connections to the database and operate correctly, so having it turn on is recommended.
More info here
If you are using Mongoose 5^ and MongoDB 3.6 your code is better written like:
mongoose.connect('mongodb.....mongodb.net/test?retryWrites=true', (err) => {
if(err){
console.log("Could not connect to MongoDB (DATA CENTER) ");
}else{
console.log("DATA CENTER - Connected")
}
});// CONNECTING TO MONGODB v. 3.6
router.delete('/:productId', (req, res, next) => {
const id = req.params.productId;
Product.findOneAndRemove({ _id: id })//updated function from .remove()
.exec()
.then(result => {
res.status(200).json({
message: "Product Removed Successfuly"
});
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
})
}); ;
});
I just changed the true to false in retryWrites=true and it worked. Is that a good approach? Or there is a better way to solve this problem?
retryWrites=true is a good thing, a workaround for this incompatibility is to use findOneAndRemove instead of remove (looks like you're using mongoose)

Resources