How do I expose my initialized bookshelf object to my routes file?

2k Views Asked by At

As this is my first foray into nodejs/express/bookshelf please be gentle and verbose if possible with regards to your comments/answers.

I'm having a hard time figuring out how to properly use express with bookshelf, specifically, with exposing objects in the various modules. The bookshelf docs say that ideally the initialization should only happen once and that the initialized bookshelf instance should be returned 'throughout your library'.

In my app.js file I create a knex/bookshelf connection to my database, and I also define my model mapping to the table I want..

(app.js)

var knex = require('knex')({
    client: 'sqlite3',
    connection: {
        filename: '<path-to-my-db'
    }
});

...
var questionRoutes = require('./routes/questions');
var app = express();
var bookshelf = require('bookshelf')(knex);

// define model
var Question = bookshelf.Model.extend({
    tableName: 'questions'
});

...

app.use('/', routes);
app.use('/api', questionRoutes);

In my routing file i want to pull in data using Bookshelf...

(routes/quesions.js)

var express = require('express');
var router = express.Router();

// on routes that end in /questions ...
router.get('/questions', function (req, res) {
    new Question()
        .fetchAll()
        .then(function (questions) {
            console.log(questions.toJSON());
        });
});

...but how do I expose my Question model object to my routing file? Or, alternatively, if I moved the model definition to my routes, then how do I expose my initialized bookshelf instance?

I haven't been able to find any useful reference apps for Bookshelf, just code snippets and API docs.

2

There are 2 best solutions below

0
On

I can't remember where I found this but I using a "make" function to support passing in supporting singleton helpers (like bookshelf). The make function is exported and then I call it whenever I include the route file. See the following example:

index.js (main file)

var passport = require('passport');

var knex = require('knex')({
    client: 'mysql',
    connection: {
        host     : 'localhost',
        user     : 'user',
        password : 'password',
        database : 'database',
        charset  : 'utf8'
    }
});
var bookshelf = require('bookshelf')(knex);

require('./routes/user')(app, bookshelf);

user.js route file

module.exports = function(app, bookshelf) {

   app.get('/user/id/:id', function (req, res) {    
      User = require('../models/user').make(bookshelf);
      ... // do something
   });
}

UPDATE

I just ended up refactoring the above code into a supporting file I call datastore and then I assign it as an attribute of the app.

// datastore.js
module.exports = function (app) {
    app.set('datastore', bookshelf);

    return bookshelf;
};


// app.js
var datastore = require('./lib/datastore')(app);
app.set('datastore', datastore);

So far both options worked for me but I went with the latter trying to refactor more code of app.js.

0
On

I'm learning node.js and related stuff as well; I would have done as follows:

lib/common/bookshelf.js sets up Bookshelf.js:

var dbConfig = {
   client: 'sqlite3'
   // ...
};
var knex = require('knex')(dbConfig);
var bookshelf = require('bookshelf')(knex);
module.exports = bookshelf;

lib/model/question.js file to define the Question model:

var bookshelf = require("../common/bookshelf");
var Question = bookshelf.Model.extend({
    tableName: 'questions'
});

lib/routes/question.js:

var Question = require('../model/question');
// rest of the code.