Basic Node.js question with regards to serverless functions - javascript

I am developing an Alexa Skill for the first time. For the Fulfillment sections, I planned to hook them up to serverless functions (written in Node.js) on Azure. I developed the intents with Google's Dialogflow which I plan to export to Amazon Alexa's console. I am a C# programmer but willing to learn Node.js/Javascript and have a few basic questions.
I installed/used the "azure-functions-core-tools" from Github to create my serverless function in Node.js. It created the file below.
The name of my Function is HelloWorld
Index.js file below was created by "func new" command and contains the following:
module.exports = async function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
if (req.query.name || (req.body && req.body.name)) {
context.res = {
// status: 200, /* Defaults to 200 */
body: "Hello " + (req.query.name || req.body.name)
};
}
else {
context.res = {
status: 400,
body: "Please pass a name on the query string or in the request body"
};
}
};
My questions are
1) Are you limited to one function per file?
2) Can I have multiple functions in the same file?
3) If so, how is that possible because just looking at this, there is no name for this function?
4) If not, how can I call other functions outside this function?
5) I am taking an online class on Node.js but wonder if I really should take a Javascript class instead. What would you recommend?
Many Thanks

Answers:
No
Yes. You basically need to search for basic syntax using a search engine (example: google.com)
Because some js-file/module will use this as a module, importing it using require and then using it as a method. For example :
-
// file name - run.js
var asyncFunction = require('index.js'); // This fetches the function, as its exported in index.js
asyncFunction() // this executes the function.
You use export and require.
Nodejs is a complete set of environment which uses javascript as the programming language. So it basically depends on the content of that course.

Related

Exception: You do not have permission to call DriveApp.createFile

I created a custom script to be run from google sheets which I need to create a file. The script uses the following code excerpt:
/*
Custom function to call IEXAPI IEXkeystatearningsdate
#customfunction
*/
function IEXkeystatearningsdate(inputsymbol, stat, version) {
if (version == "Sandbox" || version == "sandbox")
var url="https://sandbox.iexapis.com/stable/stock/"+inputsymbol+"/stats/"+stat+"?token=xyz";
else
var url="https://cloud.iexapis.com/stable/stock/"+inputsymbol+"/stats/"+stat+"?token=xyz";
var response=UrlFetchApp.fetch(url); //Call REST API
var json=response.getContentText();
var data = JSON.parse(json); //Parse into JSON object
var d = new Date();
var n = d.toLocaleString();
var fn = "IEXkeystatearningsdate_" + n;
DriveApp.createFile(fn,inputsymbol, MimeType.CSV);
return (data);
}
However, I receive this message:
"Exception: You do not have permission to call DriveApp.createFile. Required permissions: https://www.googleapis.com/auth/drive (line 20)"
When I run this script directly from the script editor, I don't receive this message.
This is my manifest file:
{
"oauthScopes": [
"https://www.googleapis.com/auth/drive"
],
"timeZone": "America/Los_Angeles",
"dependencies": {
},
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8"
}
I do not use G-Suite. I only use google/sheets for my personal use. The OAuth FAQ says this call should be allowed for personal use. Can someone help me with what I need to do to get this to work?
From your error description I can assume that you are running your script on a simple onEdit trigger.
Simple onEdit trigger cannot access services that require authorization.
See restrictions.
For you it means that you can perform to DriveApp on simple trigger.
Solution:
Use an Installable trigger instead.
To do so:
Rename the function onEdit() to something else that is not a key word
Go on Edit -> Current project's triggers
Click on + to create a new trigger
Specify the funciton to run
Set Select event type to On edit
Custom functions cannot be used to call services that access personal data:
Unlike most other types of Apps Scripts, custom functions never ask users to authorize access to personal data. Consequently, they can only call services that do not have access to personal data
That, of course, includes DriveApp. And it also includes things like getOAuthToken() (it returns null when called via custom functions), so calling Drive API directly through UrlFetch cannot work either.
You should either install an onEdit trigger, as ziganotschka suggested, or call this function through a custom menu instead of a custom function, so that you're asked for authorization when trying to run it.
Reference:
Using Apps Script services

Javascript is not creating new instance of function in Node.JS API call

I am developing a Node.JS application in which I have an endpoint as shown below:
const streamService = require('./stream.service');
module.exports = function (app) {
/**
* Below API will send all streams data according to the parameters passed in query parameters.
*/
app.get("/streams", async function (request, response) {
var device_id = (!req.query.device_id) ? "" : req.query.device_id;
var userid = (!req.query.user) ? "" : req.query.user;
var streams = streamService.getAllStreams(device_id,userid);
response.send(streams);
});
}
This calls getAllStreams function which is written in some other file. While the function getAllStreams is getting executed if any other API hit comes then it is overriding the data which I am getting from query parameters and affecting the response of 'getAllStreams' function. I have also observed that the response is a mixture of both the API calls expected result. I am willing to know if I am doing anything wrong while calling function. Basically it should create a new instance of that function for every call but it is not creating.
I know this is a very strange behavior of JavaScript I have noticed today. I have never ever expected that but I am looking for any solution. Please note that I have checked the above said scenario multiple times by putting some logs at both server and client side.
Thank you in advance for your help. :-)

sails.js how to call a REST API from a script using restler or not?

I haven't figured out how to get a response from restler in sails.js script. The goal is to import some data each day from a REST API to my database. So I chose to use sails.js script to be able to crontab the call.
When I search what I could use to contact the API. I saw a topic about restler which seem pretty easy to use.
Sadly when I try it I cannot catch the response from the API, I use this basic example
module.exports = {
friendlyName: 'test',
description: 'this is a test',
fn: async function () {
sails.log('Running custom shell script... (`sails run test`)');
var rest = require('restler');
rest.get('http://google.com').on('complete', function(result) {
sails.log("In callback")
if (result instanceof Error) {
sails.log('Error:', result.message);
this.retry(5000); // try again after 5 sec
} else {
sails.log(result);
}
});
sails.log('finished');
}
};
When I run the script this is what I get
info: Initializing hook... (`api/hooks/custom`)
info: Initializing `apianalytics` hook... (requests to monitored routes will be logged!)
info: ·• Auto-migrating... (alter)
info: Hold tight, this could take a moment.
info: ✓ Auto-migration complete.
debug: Running custom shell script... (`sails run test`)
debug: finished
I try other method and other URL too, but apparently I never get in the callback.
So I assume that the script doesn't "wait" the .on('complete') before continuing his execution.
I know, and use, on the database call .then to avoiding that, I think this is called a 'promise'. So from what I understand the problem is around that but sadly after searching, I don't find any answer to solve my issue.
I am not married to restler, and if another and better solution exists don't hesitate, the goal is again to get the content from a REST API from sails.js script.
Thank you for the time you take to answer my question.

RabbitMQ amqp.node integration with nodejs express

The official RabbitMQ Javascript tutorials show usage of the amqp.node client library
amqp.connect('amqp://localhost', function(err, conn) {
conn.createChannel(function(err, ch) {
var q = 'hello';
ch.assertQueue(q, {durable: false});
// Note: on Node 6 Buffer.from(msg) should be used
ch.sendToQueue(q, new Buffer('Hello World!'));
console.log(" [x] Sent 'Hello World!'");
});
});
However, I find it's hard to reuse this code elsewhere. In particular, I don't know how to exports the channel object since it's in a callback. For example in my NodeJs/Express App:
app.post('/posts', (req, res) => {
-- Create a new Post
-- Publish a message saying that a new Post has been created
-- Another 'newsfeed' server consume that message and update the newsfeed table
// How do I reuse the channel 'ch' object from amqp.node here
});
Do you guys have any guidance on this one? Suggestion of other libraries is welcomed (Since I'm starting out, ease of use is what I considered the most important)
amqp.node is a low-level API set that does minimal translation from AMQP to Node.js. It's basically a driver that should be used from a more friendly API.
If you want a DIY solution, create an API that you can export from your module and manage the connection, channel and other objects from within that API file.
But I don't recommend doing it yourself. It's not easy to get things right.
I would suggest using a library like Rabbot (https://github.com/arobson/rabbot/) to handle this for you.
I've been using Rabbot for quite some time now, and I really like the way it works. It pushes the details of AMQP off to the side and lets me focus on the business value of my applications and the messaging patterns that I need, to build featurs.
As explained in the comments, you could use the module.exports to expose the newly created channel. Of course this will be overridden each time you create a new channel, unless you want to keep an array of channels or some other data structure.
Assuming this is in a script called channelCreator.js:
amqp.connect('amqp://localhost', function(err, conn) {
conn.createChannel(function(err, ch) {
var q = 'hello';
ch.assertQueue(q, {durable: false});
//this is where you can export the channel object
module.exports.channel = ch;
//moved the sending-code to some 'external script'
});
});
In the script where you may want to use the "exported" channel:
var channelCreator = require("<path>/channelCreator.js");
//this is where you can access the channel object:
if(channelCreator.channel){
channelCreator.channel.sendToQueue('QueueName', new Buffer('This is Some Message.'));
console.log(" [x] Sent 'Message'");
}
Hope this helps.

Proper Angularjs way to use JSON maintain RESTful urls

I am building an Angularjs web application by the books I guess you could say. I am following the John Papa Angular Styleguide and things have been going well so far. I now have a need to keep all of the RESTful host urls in some sort of configuration file in JSON format. These host endpoints change frequently depending on the client or change of AWS machines, so to keep all of the urls in one place could be beneficial for ease of change.
Currently in the javascript files in my application that deal with making the REST calls things are setup like this:
function ModelViewService($http, $q, exception, logger) {
var HOST = 'http://xxxxxxxxxxxxxxxxxx.amazonaws.com';
var MODULE = '/modelview/service/rest';
...
And then when a call is made to get some data for example it looks like this:
function getGroups() {
return $http.get(HOST + MODULE + '/group/retrieveAll')
.then(success)
.catch(fail);
...
I then have other files with different services and different HOSTs so I basically want to house JSON objects somewhere that look like:
{
'modelviewservice': {
'HOST': 'http://xxxxxxxxxxxxxxxxxx.amazonaws.com',
'MODULE': '/modelview/service/rest'
},
... //other service
}
And then back in the javascript file do something like $http.get(config.modelviewservice.host + config.modelviewservice.MODULE + '/group/retrieveAll').
I don't know the best way to achieve this and follow the angular style guide. I found something called requre.js that apparently would inject the config.json file into the javascript via something like var config = require('config.json')('./config.json'); where the first config.json refers to the config.json npm module, and the second ./config.json refers to my local configuration JSON file. This seemed like an ok solution but since I couldn't get it to work it had me second guessing if there was an easier or more proper way to do this.
Well, this is how I do it to make my endpoints organize. Add constant to main module of the application .
(function() {
'use strict';
angular
.module('apiConstant', [])
.constant('apiConstant', constant());
function constant() {
return {
HOST: 'http://xxxxxxxxxxxxxxxxxx.amazonaws.com',
modules: {
MODULE_1: '/modelview/service/rest',
MODULE_2: '/modelview/factory/rest',
MODULE_3: '/modelview/sample/rest'
},
endpoints: {
GET_GROUPS: '/group/retrieveAll',
GET_USERS: '/users/retrieveAll',
POST_GROUP: '/group/add'
}
};
}
})();
And then in your service
function ModelViewService($http, $q, exception, logger, apiConstant) {
var HOST = apiConstant.HOST;
var MODULE = apiConstant.modules.MODULE_1;
...
function getGroups() {
return $http.get(HOST + MODULE + apiConstant.endpoints.GET_GROUPS)
.then(success)
.catch(fail);
...

Categories