Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best Way to Use OOP in Express REST API?

I'm going all in and doing a project using only node. It's been a lot of fun, but sometimes I get a little lost in it and I want to try to gain understanding as I get confused so I build it correctly and don't get too overwhelmed. Anyway, here's the problem:

I have REST API that's using Express and mysql. I set up mysql:

app.js

//Variables, move these to env
var dbOptions = {
    host: config.db_config.host,
    user: config.db_config.user,
    password: config.db_config.password,
    port: config.db_config.port,
    database: config.db_config.database
};
app.use(myConnection(mysql, dbOptions, 'single'));

and then I include my routes, passing the routes the app and log middleware so I can use them in the route:

app.js cont.

var userRoute = require('./routes/users.js')(app,log);
app.use('/users', userRoute);

That actually was a little confusing, but now I get it, I have to pass them into module in order for the module to get the data.

Then in my route file I want to use an object so that I can use the same functionality in other routes, but in the user file in order to use the same connection pool that everything else is using, or at least to not have to set up the connection again I have to pass it the response and request? There's gotta be a better way to do that. It's really ugly that way. Here's the relevant part of

routes/users.js

var User = require('../controllers/User.js');

module.exports = (function(app,log) {
var userR = express.Router();

userR.post('/register', function(req,res){
        var email = req.body.email;
        var password = req.body.password;
        var firstName = req.body.first_name;
        var lastName = req.body.last_name;
        var userId;

        try {
            var query;
            var status = 200;
            var response = '';

            var newUser = {
                email: email,
                password:password,
                first_name: firstName,
                last_name: lastName,
                password: password
            };

            var user = new User(req,res);

            user.register(newUser);
...

};

controllers/User.js

module.exports = function User(req,res) {
this.id = 0;
    this.register = function(newUser){

        var _this = this;
        var deferred = q.defer();
req.getConnection(function(err,connection){
...

There must be a pattern I'm missing here. I should just be able to pass the app or something and have access to the req.getConnection etc.

Thanks.

like image 973
Z2VvZ3Vp Avatar asked Jan 28 '15 03:01

Z2VvZ3Vp


People also ask

Is Express GOOD FOR REST API?

Express is a perfect choice for a server when it comes to creating and exposing APIs (e.g. REST API) to communicate as a client with your server application.

Can we use OOP in node JS?

If you want to use a real strong OOP in Javascript/Node, you can have a look at the full-stack open source framework Danf. It provides all needed features for a strong OOP code (classes, interfaces, inheritance, dependency-injection, ...).

Is JavaScript functional programming or OOP?

JavaScript can function as both a procedural and an object oriented language. Objects are created programmatically in JavaScript, by attaching methods and properties to otherwise empty objects at run time, as opposed to the syntactic class definitions common in compiled languages like C++ and Java.


1 Answers

There's kind of a lot going on here, but I'll take a crack at this one.

My first recommendation would be to try to keep your routers pretty slim. It's not labeled, but I'm assuming the largest snippet of code you've provided is your router. There are lots of opinions of course, but if I were doing this here's what my router would look like. I'm assuming you're using Express 4x.

routes/users.js

var User = require('../controllers/user.js');
var userRouter = express.Router();
userRouter.post("/register", User.register);
module.exports = userRouter;

So what we've done here is eliminated the dependency on your app/log middleware.

This means your main file (what I usually call app.js), will look like this:

app.js

var userRouter = require('./routes/users.js');
app.use('/users', userRouter);

This is also where you can put any middleware you chose (logging, body-parsing, error-handling, etc).

In the later versions of Express the above code actually mounts our userRouter to "/users". In this case you will now have a "/users/register" route.

So now since we've pulled out some of the logic of the router, we have to put that somewhere. Typically a router will talk to a controller so let's take a look:

controllers/user.js

var User = require("../models/user.js")
var register = function(req, res, next){
    var email = req.body.email;
    var password = req.body.password;
    var firstName = req.body.first_name;
    var lastName = req.body.last_name;
    var userId;
    var params = {
            email: email,
            password:password,
            first_name: firstName,
            last_name: lastName,
            password: password
        };
    var newUser = new User(params);

    try {
       newUser.register();
        // do other things...
    }
};
module.exports = {register: register};

The first thing you'll notice is that I would have a UserModel file. By doing this, we've de-coupled our model object from this route. Let's say for instance we have a new register route (maybe one of them has an email + pw, the other registers through FB and we have to store different things). We should be able to use the same function (user.register in this case) specified in our model without having to change a whole bunch of things!

Now, here's what a UserModel might look like:

/models/user.js

var connection = require("../lib/connection.js");
var User = function(params){
   this.email = params.email;
   // ...etc
};

User.prototype.register = function(newUser){
    connection.getConnection(function(error, connection){
        //connection.doWhatever();
    });
};

module.exports = User;

Now we've finally gotten to the core of your question. At the top, you'll see we have a connection file. This is where we're going to put all of our DB-related logic like our connection pools.

/lib/connection.js

/*
This will be in some JSON config we'll say
var dbOptions = {
    host: config.db_config.host,
    user: config.db_config.user,
    password: config.db_config.password,
    port: config.db_config.port,
    database: config.db_config.database
};

*/
//This will depend on which version/module/db you're using, but here's what mine looks like
var MySQL = require("mysql");
var config = require("../config/db.json");
connectionPool = MySQL.createPool({host: config.db_config.host, ...});

var getConnection = function(done){
   connectionPool.getConnection(done);
};

module.exports = {getConnection: getConnection};

So, in conclusion, instead of passing your connection along with your request object, we now simply include our short connection module in whichever model file we're in, kindly ask for a connection, and do whatever processing we need to. Also note you'll have to release the connections back into the pool, but I'll leave that as an exercise for you :).

Also, I usually write CoffeeScript, so please excuse any small errors. Let me know if you have need for further clarification.

Cheers, Brennan

like image 105
Brennan Avatar answered Oct 20 '22 21:10

Brennan