'then is not a function' in MongoDB Stitch Webhook - mongodb

The MongoDB Stitch Webhook docs describe my precise use case: using a POST method to call insertOne then return the inserted _id.
I pasted the example below (directly from the docs) into the Stitch Function Editor.
exports = function(payload, response) {
const mongodb = context.services.get("mongodb-atlas");
const requestLogs = mongodb.db("test").collection("requestlogs");
requestLogs.insertOne({
body: EJSON.parse(payload.body.text()),
query: payload.query
}).then(result => {
response.setStatusCode(201);
response.setBody(result.insertedId);
})
};
I executed the function in the Function Editor console by calling:
exports({query: {arg1: 'hello', arg2: "world!"}, body:BSON.Binary.fromText('{"msg": "world"}')})
An error is returned indicating that .then is not a function.
error: TypeError: 'then' is not a function
Are the docs wrong, or I have I gone astray?

Certain methods, like .then, throw errors in the function editor. In my case, this was a shortcoming of the function editor, rather than an error in my code. Calling the webhook with fetch or Postman, the function executed as expected.
The Incoming Webhook docs contain a special note:
If you want to debug a webhook function response from the function
editor, you must manually provide the HTTP response object when you
run the function.
exports( { body: "This document is the webhook payload" }, new
HTTPResponse() )
That alerted me to the idiosyncratic nature of the function editor as a JS handler. Using Postman I confirmed the function ran without errors when called. The error generated by the function editor was a red herring.

Related

node.js authentication with sequelize and passport - promise and callback confusion

Hopefully someone can help me solve what I am sure is a rookie mistake.
I am trying to adapt an authentication app originally based on mongodb, to work with sequelize\MSSQL instead, but getting tied up in knots with trying to blend a callback-based working example with
seqeulize's promised based approach.
Both MongoDb\Sequelize offer a findOne() method.
Original (working) code referencing MongoDb collection:
module.exports.getUserByUsername = function(username,callback){
var query = {username: username};
User.findOne(query,callback);
}
The callback in this case is from a separate calling module and is the standard verify password of passport.js's local-strategy.
Since the sequelize findOne() method expects a where clause I had hoped the following would be an out of the box solution:
module.exports.getUserByUsername = function(username,callback){
var query = {where: {username: username}};
User.findOne(query,callback);
}
This outputs a functional query into the console.log, but the callback doesn't fire, so the page hangs.
Looking at the respective API docs it appears that sequelize findOne() is exclusively promise based whereas MongoDb findOne() returns a promise only if where a callback function is not passed to the findOne() method, otherwise flow is handed to the callback when one is provided as is the case with the working example.
I tried the following adaptation to work with a sequelize promise (and quite a number of permutations thereof calling the callback function within the .then() clause etc)., but all fail with a hanging page: :
module.exports.getUserByUsername = function(username,callback){
var query = {where: {username: username}};
return User.findOne(query).then(user => {
console.log(user.get({ plain: true }));
return user.dataValues;
//callback(user.dataValues)
}).finally(() => {
console.log('done!')
});
}
The console.log(user.get()) spools out the correct details showing the database query executed correctly returning the required user data, so I feel that I'm very near to finding the right syntax to delivering this back to the passport callback.
Any help would be much appreciated!
Add raw property to true like this, and you can get the user object
User.findOne({ where : {username:username}, raw: true}).then( user => {
return user
})

error.response is undefined if axios request fails

I cannot access the error (response) status code if an axios request has failed in my Vue.js app. I cannot figure out why the response is undefined in both '.catch' and 'axios.interceptors.response'. I followed this instruction that demonstrates that 'error.response' can be easily accessed with a code like this:
axios.interceptors.response.use(
(response) => {
console.log(response);
return response;
},
(error) => {
handleApiFail(error.response);
});
If I add this code to 'main.js' in my app, 'handleApiFail' is called when a request fails, but error.response is undefined in the second lambda and the first lambda is not called. If a request succeeded the 'response' in the first lambda is defined and has the status code.
EDIT1: this is not an option because my OPTIONS requests do not require authorization. Also there are various posts describing the same situation.
The lack of
access-control-allow-origin: *
header in the response caused the browser to block my request.
Adding the header makes axios work fine.
I have code like this:
axios.interceptors.response.use(null, (error) => {
.........
return Promise.reject();
});
Then, I found I miss to return my "error" in promise reject, correct like this:
return Promise.reject(error);
This is an idiosyncrasy of axios. A quick solution to this is to serialize the response:
JSON.stringify(error)
Please refer to this GitHub issue for more info: https://github.com/axios/axios/issues/960
As someone pointed out there, you can check the error status code in the action and run some other commit depending on it.

SAPUI5 - Gateway Errors on update method

I can't seem to get update methods working in SAPUI5.
Here's the example:
oModel.update("/JobOfflineSet('" + self.jobId + "')", oEntry, {
success: function () {
var oRouter = sap.ui.core.UIComponent.getRouterFor(self);
oRouter.navTo("main", {});
dialog.close();
},
error: function (oError) {}
});
And I'm receiving the following error.
There's no error shown in the SAP Gateway and we aren't even getting into ABAP to debug.
{"error":{"code":"/IWBEP/CM_MGW_RT/022","message":{"lang":"en","value":"The system cannot return your search. Please try again."},"innererror":{"application":{"component_id":"","service_namespace":"/SAP/","service_id":"ZSV_SURVEY_SRV","service_version":"0001"},"transactionid":"306596E88F59F1CD80C7005056BEAC32","timestamp":"","Error_Resolution":{"SAP_Transaction":"","SAP_Note":"See SAP Note 1797736 for error analysis (https://service.sap.com/sap/support/notes/1797736)","Batch_SAP_Note":"See SAP Note 1869434 for details about working with $batch (https://service.sap.com/sap/support/notes/1869434)"},"errordetails":[{"code":"/IWBEP/CX_MGW_BUSI_EXCEPTION","message":"The system cannot return your search. Please try again.","propertyref":"","severity":"error","target":""}]}}}
This is mostly because UI5 is triggering a MERGE method instead of a PUT method (To handle MERGE, Gateway internally makes a GET request, which might be failing). You can specify the update method as 'PUT' in the manifest.json.

[ 'Parse error: Can\'t wait without a fiber' ]' When trying to do find within Metor

When receiving JSON data via websockets, I'm trying to feed this data into a mongodb within meteor. I'm getting the JSON data fine, but when trying to find whether the data already exists in the database, I keep getting the error: "[ 'Parse error: Can\'t wait without a fiber' ]'.
binance.websockets.miniTicker(markets => {
//we've got the live information from binance
if (db.Coins.find({}).count() === 0) {
//if there's nothing in the database right now
markets.forEach(function(coin) {
//for each coin in the JSON file, create a new document
db.Coins.insert(coin);
});
}
});
Can anyone point me in the right direction to get this cleared up?
Many thanks,
Rufus
You execute a mongo operation within an async function's callback. This callback is not bound to the running fiber anymore. In order to connect the callback to a fiber you need to use Meteor.bindEnvironment which binds the fiber to the callback.
binance.websockets.miniTicker(Meteor.bindEnvironment((markets) => {
//we've got the live information from binance
if (db.Coins.find({}).count() === 0) {
//if there's nothing in the database right now
markets.forEach(function(coin) {
//for each coin in the JSON file, create a new document
db.Coins.insert(coin);
});
}
}));
You should not require to bind to the function within the forEach as they are not async.
Related posts on SO:
Meteor.Collection with Meteor.bindEnvironment
Meteor: Calling an asynchronous function inside a Meteor.method and returning the result
Meteor wrapAsync or bindEnvironment without standard callback signature
What's going on with Meteor and Fibers/bindEnvironment()?

Empty response on long running query SailsJS

I'm currently running SailsJS on a Raspberry Pi and all is working well however when I execute a sails.models.nameofmodel.count() when I attempt to respond with the result I end up getting a empty response.
getListCount: function(req,res)
{
var mainsource = req.param("source");
if(mainsource)
{
sails.models.gatherer.find({source: mainsource}).exec(
function(error, found)
{
if(error)
{
return res.serverError("Error in call");
}
else
{
sails.log("Number found "+found.length);
return res.ok({count: found.length});
}
}
);
}
else
{
return res.ok("Error in parameter");
}
},
I am able to see in the logs the number that was found (73689). However when responding I still get an empty response. I am using the default stock ok.js file, however I did stick in additional logging to try to debug and make sure it is going through the correct paths. I was able to confirm that the ok.js was going through this path
if (req.wantsJSON) {
return res.jsonx(data);
}
I also tried adding .populate() to the call before the .exec(), res.status(200) before I sent out a res.send() instead of res.ok(). I've also updated Sails to 11.5 and still getting the same empty response. I've also used a sails.models.gatherer.count() call with the same result.
You can try to add some logging to the beginning of your method to capture the value of mainsource. I do not believe you need to use an explicit return for any response object calls.
If all looks normal there, try to eliminate the model's find method and just evaluate the request parameter and return a simple response:
getListCount: function(req, res) {
var mainsource = req.param("source");
sails.log("Value of mainsource:" + mainsource);
if (mainsource) {
res.send("Hello!");
} else {
res.badRequest("Sorry, missing source.");
}
}
If that does not work, then your model data may not actually be matching on the criteria that you are providing and the problem may lie there; in which case, your response would be null. You mentioned that you do see the resulting count of the query within the log statement. If the res.badRequest is also null, then you may have a problem with the version of express that is installed within sailsjs. You mention that you have 11.5 of sailsjs. I will assume you mean 0.11.5.
This is what is found in package.json of 0.11.5
"express": "^3.21.0",
Check for any possible bugs within the GitHub issues for sailsjs regarding express and response object handling and the above version of express.
It may be worthwhile to perform a clean install using the latest sailsjs version (0.12.0) and see if that fixes your issue.
Another issue may be in how you are handling the response. In this case .exec should execute the query immediately (i.e. a synchronous call) and return the response when complete. So there should be no asynchronous processing there.
If you can show the code that is consuming the response, that would be helpful. I am assuming that there is a view that is showing the response via AJAX or some kind of form POST that is being performed. If that is where you are seeing the null response, then perhaps the problem lies in the view layer rather than the controller/model.
If you are experiencing a true timeout error via HTTP even though your query returns with a result just in time, then you may need to consider using async processing with sailjs. Take a look at this post on using a Promise instead.