redux-sagas does not dispatch action when firebase cloud function is complete - node.js

this function calls firebase cloud function
function createUser (data3){
var addUser = firebase.functions().httpsCallable('crearPaquete');
addUser(data3).then(function(result) {
// Read result of the Cloud Function.
return result //return uid inserted
}).catch(function(error) {
// Getting the Error details.
var code = error.code;
var message = error.message;
var details = error.details;
// ...
});
}
then I call function createUser inside redux-saga function
export function* createPackageStart({payload}){
try {
yield user= **createUser(payload)**
if(user.data){
yield put(createPackageSuccess()). **///this never is dispatch**
}
} catch(error){
yield put(createPackageFailure(error))
}
}
I need the result of cloud function to dispatch success action but "user" variable never gets update with cloud function result
How can I achieve this purpose?

It looks like your addUser function performs an asynchronous operation. With your current code, Cloud Functions terminates the container for your code when the last } has executed, which is before the asynchronous function has completed. To make the container wait, you need to return a promise.
function createUser(data3) {
var addUser = firebase.functions().httpsCallable('crearPaquete');
return addUser(data3).then(function(result) {
// Read result of the Cloud Function.
return result //return uid inserted
}).catch(function(error) {
// Getting the Error details.
var code = error.code;
var message = error.message;
var details = error.details;
// ...
});
}
For more on this, see the Firebase documentation on sending back the result

Related

Function that return undefined in node.js. Inside the function I have mongoDB.connect

I tried to make function for my project in the service. This service need to check is user exists in my database, but my function(this function is checking) inside the class return undefined.
This is my code:
const express = require("express");
const mongoDB = require('mongodb').MongoClient;
const url = "here I paste url to my databse(everything is good here)";
class CheckService {
isUserExists(username) {
mongoDB.connect(url, (error, connection) => {
if (error) {
console.log("Error", '\n', error);
throw error;
}
const query = {name: username};
const db = connection.db("users");
const result = db.collection("users").find(query).toArray(
function findUser(error, result) {
if (error) {
throw error;
}
const arr = [];
if (result.value === arr.value) {
console.log(false);
connection.close();
return false;
} else {
console.log(true);
console.log(arr);
console.log(result);
connection.close();
return true;
}
});
console.log(result);
});
}
}
module.exports = new CheckService();
I imported my service to another service:
const checkService = require('./check.service');
After this, I invoked my function from my service like this:
console.log('function:',checkService.isUserExists(username));
I expected good result, but function doesn't return, that I want, unfortunately.
Please help!
There are two problems with your function
it doesn't return anything
toArray() is a promise, so your console.log probably just prints a promise.
Probably you're looking for something like this:
class CheckService {
async isUserExists(username) {
const connection = await mongoDB.connect(url);
const query = {name: username};
const db = connection.db("users");
const result = await db.collection("users").find(query).toArray();
connection.close();
return result.length !== 0;
}
}
You'd then invoke it with something like
await new CheckService().isUserExists(username);
Though, it's worth noting that you probably don't need toArray and instead could use findOne or even count() since all you care about is existence. I probably also wouldn't instantiate a new connection each time (but that's not super relevant)
2 things wrong here. Firstly the first comment is correct. You're only logging the result and not passing back to the caller. Secondly, a quick peek at the mongo docs shows that retrieval methods are promises. You need to make the function async and add awaits where needed.
Mongo:
https://www.mongodb.com/docs/drivers/node/current/fundamentals/crud/read-operations/retrieve/
Promises:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

async processing with nodejs and rest api calls & express - sequence error

I am using a rest api service to access a node running program and I found the async and await are not retaining sequence. This code does work with a second api call in the func. I think the await and async are getting out of sequence with the second call and that causes the issue.
I tested using a func without a second api call and the sequence is fine, so the problem is related to the CCAPI promise which is generated. I think the "then" is not correct. Also the code in the func accessing the charity API works in isolation so the actual does work and runs also in the whole code but out of sequence.
Any help appreciated.
async function checkCharityAPI(searchTerm) {
const args = { APIKey: myAPIKey, strSearch: searchTerm };
ccAPI.GetCharitiesByName(args).then(function(result) {
var charityResult = JSON.stringify(result);
var charityResultJson = JSON.parse(charityResult);
console.log(charityResultJson["GetCharitiesByNameResult"]);
return charityResultJson;
}).catch(function(err) {
console.log(`Call to ${err.operationName} failed with error: ${err.err}`);
return null;
});
}
app.post("/api/checkcharitytest", asyncHandler(async (req, res, next) => {
var charitySearch = req.body.charitysearch;
console.log("start api call")
var charityResult = await checkCharityAPI(charitySearch);
console.log("end api call")
res.json({ "charityResult": charityResult})
}));
Addition -
I also tried this -
var charitySearch = req.body.charitysearch;
console.log("start api call")
// var charityResult = await checkCharityAPI(charitySearch);
checkCharityAPI(charitySearch).then(function(result) {
console.log("result")
console.log(result);
res.json({ "charityResult": result})
}).catch(function(err) {
console.log(`Call to ${err.operationName} failed with error: ${err.err}`);
});
console.log("end api call")
Also I added this - then the seq is corrected by the return value is null despite it being populated in the func -
async function checkCharityAPI(searchTerm) {
const args = { APIKey: myAPIKey, strSearch: searchTerm };
await ccAPI.GetCharitiesByName(args).then(function(result) {
var charityResult = JSON.stringify(result);
var charityResultJson = JSON.parse(charityResult);
console.log(charityResultJson["GetCharitiesByNameResult"]);
return charityResultJson["GetCharitiesByNameResult"];
}).catch(function(err) {
console.log(`Call to ${err.operationName} failed with error: ${err.err}`);
return null;
});
}
ccAPI.GetCharitiesByName(args) appears to return a promise, but checkCharityAPI doesn't await it.
You access it with then/catch instead.
Consequently, the promise returned due to the async keyword is entirely independent of the one returned by ccAPI.GetCharitiesByName(args).

Scoping of variables in nodeJS in callback functions

This is a nodeJS code nugget from my application, written for publishing in AWS Lambda. The callProcess function basically returns some processed information about the city I am passing - hard coded here for "New York"
function speech2(intent, session, callback) {
let country;
const repromptText = null;
const sessionAttributes = {};
let shouldEndSession = false;
let speechOutput = 'old text';
callProcess('New York', function (error, data) {
if (!error) {
speechOutput = data;
console.log(speechOutput);
}
else {
console.log(error.message);
}
});
// Setting repromptText to null signifies that we do not want to reprompt the user.
// If the user does not respond or says something that is not understood, the session
// will end.
callback(sessionAttributes,
buildSpeechletResponse(intent.name, speechOutput, repromptText,
shouldEndSession));
}
The console.log(speechOutput) correctly displays the processed information about the city - i.e. callProcess has worked. However the callback at the end of this function that has speechOutput is still referring to 'old text' i.e. I am unable to over-write the variable using the processed information that sits within the function? How do I do this within callbacks?
Any help here is greatly appreciated. Thanks in advance.
your callProcess function is an async function which correctly shows the speechOutput data. The callback you've wriiten is outside this callProcess function which is called before callProcess is executed.
you can get the correct value of speechOutput by calling the callback inside your callProcess function.
like this-`
callProcess('New York', function (error, data) {
if (!error) {
speechOutput = data;
console.log(speechOutput);
callback(sessionAttributes,
buildSpeechletResponse(intent.name, speechOutput, repromptText,
shouldEndSession));
}
else {
console.log(error.message);
}
});
for further info how async method behave have a look at this async and sync functions

Async function in wit actions

I am currently developing a bot using wit.ai. I am quite new to node.js. Basically, I am following the guide provided by node-wit lib. I construct my wit object by:
const wit = new Wit({
accessToken: WIT_TOKEN,
actions,
logger: new log.Logger(log.INFO)
});
In my actions, I have something like:
const actions = {
send({sessionId}, {text}) {
//my sending action goes here.
},
firstaction({context, entities,sessionId}) {
var data = async_function();
context.receiver = data;
return context;
}
}
The issue is that whatever comes after async_function will be executed first. I tried to let async_function return a promise. However, this wouldn't work since whatever comes after my first action in node-wit library will be executed first without waiting for the context to return. I don't want to modify the node-wit library.
Any idea that would solve my issue is appreciated!
you can use async library for asynchronous call
https://caolan.github.io/async/docs.html
const async = require('async')
const actions = {
send({sessionId}, {text}) {
//my sending action goes here.
},
firstaction({context, entities,sessionId}) {
async.waterfall([function(callback) {
var d = async_function();
// if err pass it to callback first parameter
// return callback(err)
callback(null,d);
}], function(err, result) {
if(err) {
return err;
}
var data = result;
context.receiver = data;
return context;
})
}
}

Error handling with promises in Koa

If I yield promises in Koa, they may be rejected:
function fetch = (){
var deferred = q.defer();
//Some async action which calls deferred.reject();
return deferred.promise;
}
this.body = yield fetch(); //bad, not going to work
Is there a error-handling pattern in Koa to handle this besides explicitly unwrapping the promise with then and handling the error explicitly?
Try/Catch. Under the hood koajs uses co. Check out the docs for co, which describes error handling a little better.
function fetch = (){
var deferred = q.defer();
//Some async action which calls deferred.reject();
return deferred.promise;
}
try{
this.body = yield fetch(); //bad, not going to work
}
catch(err){
this.throw('something exploded');
}
Here is an rudimentary example of what's happening with the promise:
function * someGenerator () {
let result;
try{
result = yield fetch();
console.log('won\'t make it here...');
}
catch(err){
console.log(err);
}
console.log('will make it here...');
}
// Normally co() does everything below this line, I'm including it for
// better understanding
// instantiate the generator
let gen = someGenerator();
// calling gen.next() starts execution of code up until the first yield
// or the function returns.
let result = gen.next();
// the value returned by next() is an object with 2 attributes
// value is what is returned by the yielded item, a promise in your example
// and done which is a boolean that indicates if the generator was run
// to completion
// ie result = {value: promise, done: false}
// now we can just call the then function on the returned promise
result.value.then(function(result){
// calling .next(result) restarts the generator, returning the result
// to the left of the yield keyword
gen.next(result);
}, function(err){
// however if there happened to be an error, calling gen.throw(err)
// restarts the generator and throws an error that can be caught by
// a try / catch block.
// This isn't really the intention of generators, just a clever hack
// that allows you to code in a synchronous style (yet still async code)
gen.throw(err);
});
If your still uncertain, here are a couple other things that might help:
Watch my screencast on JavaScript Generators here: http://knowthen.com/episode-2-understanding-javascript-generators/
and/or try the following code:
// test.js
'use strict';
let co = require('co'),
Promise = require('bluebird');
function fetch () {
let deffered = Promise.defer();
deffered.reject(new Error('Some Error'));
return deffered.promise;
}
co.wrap(function *(){
let result;
try{
result = yield fetch();
console.log('won\'t make it here...');
}
catch(err){
console.log(err);
}
console.log('will make it here...');
})();
then on the console run
$ node test.js
[Error: Some Error]
will make it here...
You can easily drop in the package koa-better-error-handler with npm install --save koa-better-error-handler and then implement it as such:
const errorHandler = require('koa-better-error-handler');
// override koa's undocumented error handler
app.context.onerror = errorHandler;
More info: https://github.com/niftylettuce/koa-better-error-handler

Resources