In Node JS (Hapijs) how to globally access the Server variable - node.js

It must be simple but I can not find a good solution.
In a node module for example I want to log if something goes wrong. So I need want to use the Hapi function server.log(...). An example:
In the server.js:
const server = new Hapi.Server({...});
server.connection({port:3000});
server.start((err) => {
if (err) { throw err }
}
In the file test.js, I want to use the server variable created in the server.js. It should be usable in any module, because of logging and loading other plugins.
class Test {
logInfo(text) {
server.log(['info'], text); // this will not work.
}
}
module.exports = new Test();
I can ofcause add the server to every call for the module, but that would be an overkill.
How do I get a reference to the server variable outside the module it was created?

If you want to log a message during a request, you can use request.log(...).
Alternatively, you can use server.log(...) by accessing the server object on the request object in a handler.
{
method: 'GET',
path: '/do/stuff',
handler: function (request, reply) {
request.server.log('server.log() method');
request.log('request.log() method');
const test = new Test(request.server);
test.logInfo('some text here');
}
}
Check out my answer on logging in hapi, too.
In your case, you'd need to pass a reference to the server object to your module if you specifically wanted to log a message a hapi server event.
class Test {
private server;
constructor(server) {
this.server = server;
}
logInfo(text) {
this.server.log(['info'], text); // this will work.
}
}
But the commenter on your question is likely right. You should avoid this pattern if you want to avoid tight coupling of your modules.

Related

Trigger function in app.js from module.js

First time poster — please forgive (and call me out) on any formatting mistakes!
So let's say I have app.js, which requires module.js. In module.js I have an express server running that can receive simple webrequests (GET / POST). Is there any way for me to trigger functions in app.js when I receive a request in module.js?
Something along the lines of:
var webModule = require('./module.js')
webModule.on('GET', async function (req) {
//do stuff with the request
});
The reason I'm not just putting the express server in app.js is that I want to run a certain amount of code to verify that the request is legitimate, and then re-use module.js in separate scripts to minimise the amount of code — and avoid having to update 5-6 scripts everytime I want to update the authentication process.
You can use the Event system that exists in Node.js. If you set it up correctly you can emit an event on each call and have a listener respond to the event.
Example from the Node.JS documentation:
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('event', () => {
console.log('an event occurred!');
});
myEmitter.emit('event');
In your case you could create a class that extends EventEmitter that you use in each request. This class can then emit an event when the request gets call which is then handled in your app.js file by setting up the listener.
I might have a solution, will take some time to code (since my question is obviously very simplified).
In module.js:
var functionActions = {};
module.exports = {
on : (async function(requestType, returnFunction){
functionActions[requestType].do = returnFunction;
});
}
//general express code
app.get('*', function(req,res) {
if (verifyRequest(req) == 'okay'){ //authentication
return functionActions['GET'].do();
} else { //if the request is not authorised
res.status(403).send('Stop trying to hack me you stupid hacker ಠ╭╮ಠ');
}
});
I'll try it out and update this answer once I've figured out the potential kinks.

Abstracting the superagent

Our application consists of nodejs, express, reactjs, and newforms.
To make rest calls we are using :
var RestClient = require('superagent-ls')
And we are making rest calls like:
cleanBirthDate(callback) {
var {birthDate} = this.cleanedData
var formattedDob = moment (birthDate).format('DDMMYYYY')
RestClient.get(Global.getBirthDateServiceUrl() + '/' + formattedDob)
.end((err, res) => {
if (err) {
callback (err)
}
else if (res.clientError) {
var message = errorsMappingSwitch(res.body.error)
callback(null, forms.ValidationError(message))
}
else {
callback(null)
}
})
},
We want to move the RestClient related code to our own file say RestCleint.js and then require it and use it across the application. By doing so we can apply some generalised code(like error handling, logging, redirect to specific error pages depending on the error code) in one place.
Appreciate any help in this direction.
I did the exact same thing you require (even with using superagent). I created modules with the API code in a /utils folder and required them where applicable. For even more abstraction we're using CoffeeScript to create classes that inherit from a BaseAPIObject and invoke using something like API.Posts.getAll().end() etc.
This article was very helpful in understanding how to write your own modules: Export This: Interface Design Patterns for Node.js Modules.
you can always require it like
RestClient.js
export default function callApi(callback) {
//your rest code
// use the callback here in the callback of your call.
}
app.js
import {callApi} from './RestClient';
callApi((err, result) => {
if (err) console.log(err)
});

Wait for Node constructor to connect to api before issuing commands

Sorry if the question title is a tad ambiguous, but I'm not entirely sure how to word it.
I'm writing an NPM module that talks to a json-rpc api - this is the current setup.
// The module
function MyModule(config) {
// do some connection stuff here
connected = true
}
MyModule.prototype.sendCommand = function() {
if(connected) {
// do command
} else {
// output an error
}
}
module.exports = MyModule;
// The script interacting with the module
var MyModule = require('./MyModule');
var config = {
// config stuff
};
var mod = new MyModule(config);
var mod.sendCommand;
The command won't send, as at this point it hasn't connected, I assume this is due to NodeJS' asynchronous, non-blocking architecture and that I perhaps need to use promises to wait for a response from the API, where would I implement this? Do I do it in my module or do I do it in the script interacting with the module?
You will need to use either a callback or promises or something like that to indicate when the connection is complete so you can then use the connection in further code that is started via that callback.
Though it is generally not considered the best practice to do asynchronous stuff in a constructor, it can be done:
function MyModule(config, completionCallback) {
// do some connection stuff here
connected = true
completionCallback(this);
}
var mod = new MyModule(config, function(mod) {
// object has finished connecting
// further code can run here that uses the connection
mod.sendCommand(...);
});
A more common design pattern is to not put the connecting in the constructor, but to add a method just for that:
function MyModule(config) {
}
MyModule.prototype.connect = function(fn) {
// code here that does the connection and calls
// fn callback when connected
}
var mod = new MyModule(config);
mod.connect(function() {
// object has finished connecting
// further code can run here that uses the connection
mod.sendCommand(...);
});
don't use promises, use node's programming model where you don't "call functions" but you "call functions with a result handler for dealing with the data once it's actually available":
MyModule.prototype.sendCommand = function(handler) {
if(connected) {
// run stuff, obtain results, send that on:
handler(false, result);
} else {
// output an error, although really we should
// just try to connect if we're not, and say
// there's an error only when it actually fails.
handler(new Error("ohonoes"));
}
}
and then you call the function as
var MyModule = require('./MyModule');
var mod = ...
mod.sendCommand(function(err, result) {
// we'll eventually get here, at which point:
if (err) { return console.error(err); }
run();
more();
code();
withResult(result);
});

How to pass this to require() in NodeJS?

What's the best way to pass thisArg to a require()d module?
I want to do something like this:
index.js
function Main(arg) {
return {
auth: auth,
module: require('/some/module')
}
}
module.js
module.exports = {
someMethod: function() {...}
}
Then, in my code somewhere I call Main(), which returns the object.
So Main().auth exists, cool. But how do I access it from Main().module?
The thisArg in Main().module.someMethod() points to the module itself.. but I need the parent.
Is there any way to do this without using new keyword, functions and prototypes?
EDIT:
Thanks for all the answers guys! Some additional info:
Main() is the module what I wanna require() and use in my app. The "module" Main tries to import is actually just sub functionality of Main, it's just a part of code which I moved to a separate "module" to better organize the code.
So a better example would be:
function RestApi(param) {
return {
common_param: param,
commonFunc: function() {...}
endpoint1: require('/some/module'),
endpoint2: require('/some/module2'),
endpoint3: require('/some/module3')
}
}
And my app would use it like this:
RestApi = require('./RestApi')
RestApi().endpoint1.someHTTPCall(...)
But inside someHTTPCall(), both "common_param" and "commonFunc" should be accessible via thisArg, like this.commonFunc().
So this is kinda a general question, how do you merge multiple modules using require() properly, so "this" would point to the right object (i.e.: the parent)
I know this could be achieved using Function.prototype and inheritance, just would like to know if there is a simpler way.
The best I found so far is something like this:
var _ = require('lodash');
function Module(auth) {
this.auth = auth || {};
}
Module.prototype = {
endpoint1: function() { return _.extend(require('./endpoint1'),{auth: this.auth, commonFunc: commonFunc})}
}
function commonFunc() {...}
However, this is not ideal, since RestApi.endpoint1() would create a new the object on every call.
Is there a better way to handle this?
Thanks in advance!
Create own "require" module with auth param and allways use it.
project/module/require2.js
module.exports = function(path, auth){
if (!check(auth))
return null
return require(path)
}
You could change the module to return a function, like this:
// some/module.js
module.exports = function(mainModule) {
var main = mainModule;
return {
someMethod: function() {
main.doSomethingElse();
}
}
}
Then require it passing the main object:
function Main(arg) {
var main = {
auth: auth,
other: stuff,
};
main.module = require('/some/module')(main);
return main;
}

How to emit an event and pass a function as a parameter with socket.io

I am using socket.io and I am trying to emit an event from my server and pass an object with a function as a parameter. Here is my code:
socket.emit('customEvent', {
name : "Test".
myFunc : function() {
//some logic here
}
});
and then in the client (my app in the browser) I am able to access 'name' property but when I try to access 'myFunc' but I get 'undefined' for it. Here is my code
socket.on('customEvent', function(data){
data.myFunc();
});
What is the correct approach for this (if it is possible at all)?
The data is transmitted as JSON, so it can't contain functions. Maybe you're looking for what's called 'acknowledgments' in socket.io's documentation?
// server
socket.on('customEvent', function (data, fn) {
fn(data.x)
})
// client
socket.emit('customEvent', { x: 1 }, function(){
// ...
})
You can serialize your function, maybe it's a dangerous way for some functions. But socket.io transfers only strings as pure strings or JSON. You can try to eval string function when receive it from server side.
NOTE: Code not tested below:
function hello() {
return "Hello Cruel World";
}
socket.emit('send-function', { myFunc : hello.toString() });
...
on server side:
socket.on('send-function', data) {
console.log(eval(data.myFunc));
}
Try on this code and give us a feedback if it works.

Resources