Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to do AOP with node.js?

I have a little problem doing some AOP with node.js: Let's say I have an application in a script called server.js, and I want to monitor its functions.

Here is the code:

var express = require('express');

var app = express();

app.get('/', function(req, res){
    res.setHeader('Content-Type', 'text/plain');
    res.end('Home');
});

app.get('/login', function(req, res){
    login(req,res);
    module.exports.login_(req, res);
});
app.use(function(req, res, next){
    res.setHeader('Content-Type', 'text/plain');
    res.send(404, 'Page introuvable !');
});

function login(req, res){
    res.setHeader('Content-Type', 'text/plain');
    res.end('Page de login');
}

app.listen(1616);

As you can see, I want to monitor the unique function login(req, res). In order to do this, I want to use AOP within another script, but all I can find - and I think it is due to the nature of the Javascript language - implies a lot of code intrusion.

Is there any way to do AOP just like in Spring/Java? Without having to do any code intrusion?

Currently, my solution is this one:
Here is our application with some code-intrusion

    var express = require('express');

    var app = express();

    app.get('/', function(req, res){
        res.setHeader('Content-Type', 'text/plain');
        res.end('Home');
    });

    app.get('/login', function(req, res){

        //We need to use the function in module.exports
                    //--> code intrusion
        //login(req,res);
        module.exports.login_(req, res);
    });


    app.use(function(req, res, next){
        res.setHeader('Content-Type', 'text/plain');
        res.send(404, 'Page introuvable !');
    });


    function login(req, res){
        res.setHeader('Content-Type', 'text/plain');
        res.end('Page de login');
    }

    //We wrap here the function we want to monitor
    wrappedLogin = function(req, res){
        login(req, res);
    }

    module.exports = {
        login_ : wrappedLogin
    };


    app.listen(1616);

And here is our AOP script

var aop = require("node-aop");

//Include the server
var server = require('./server.js');


aop.before(server, "login_", function(key, value){
        //I do some stuff here
});


aop.after(server, "login_", function(key, value){
        //I do some stuff here
});

And finally, all I have to do is

node aop.js

It works, but as you can see, there is some code intrusion. And I want to get rid of it. Does anyone have any idea?

like image 878
nugetchar Avatar asked Jun 19 '14 10:06

nugetchar


2 Answers

I think it is due to the nature of the Javascript language - implies a lot of code intrusion.

please don't :'(

AOP is an extension of OOP, there is no AOP without OOP.

I suggest you to use kaop or TS version with ES7 decorators kaop-ts

1º: npm install kaop --save

2º: define an advice to monitor your methods:

import { reflect } from "kaop"

const Log = reflect.advice(meta => {
  //meta.args contains the arguments {array}
   console.log(meta.methodName + " called");
   console.log("with arguments: " + meta.args);
   console.log("returned: " + meta.result);
})

3º you have to organize your code following OOP guidelines:

const Controller = createClass({
  constructor: function(app){
    app.get('/', this.home);
    app.get('/login', this.login);
    app.use(this.notFound);
  },
  login: [function(req, res){
    //what ever
  }, Log],
  home: [function(req, res){
    res.setHeader('Content-Type', 'text/plain');
    res.end('Home');
  }, Log],
  notFound: [function(req, res){
    res.setHeader('Content-Type', 'text/plain');
    res.send(404, 'Page introuvable !');
  }, Log]
})

I've writed an article on 2018 which discuss AOP on JS server side.

like image 184
k1r0s Avatar answered Sep 20 '22 06:09

k1r0s


A naive attempt would look something like this.

var before = function(object, functionName, action) {
  var oldFunction = object.functionName;
  var newFunction = function() {
    action();
    oldFunction();
  };
  object.functionName = oldFunction;
}

var after = function(object, functionName, action) {
  var fn = object.functionName;
  var after = function() {
    fn();
    action();
  };
  object.functionName = oldFunction;
}

JS is very flexible; you could easily improve on this by storing the after and before actions and adding/removing them as required, but at the very least this should do what you want (albeit not in a very good manner).

like image 30
Dan Avatar answered Sep 23 '22 06:09

Dan