When you’re developing in any language it’s always a good idea to modularize your code. Bookshelf models are no exception to this rule. Unfortunately, the first time I used this neat package I threw my hands up and ended up defining all of my models in one file, in one big exported object. It wasn’t modular. The reason I did this was because of circular dependency errors.
It’s likely that you’ll need to do something like this with your code at some point (example taken directly from the Bookshelf wiki)
1 2 3 4 5 6 7 8 9 10 11 12 13
That’s a circular dependency error right there. And if your models have any relations that’s exactly what’ll happen if you follow the Bookshelf docs as written and put each model in a separate file.
Please note that I’m using Node v5+ here and taking advantage of some ES6 features. If you’re not using ES6 yet be sure to change my
Create a reusable Bookshelf instance
The first thing you need to do is create a file that’ll export an instance of Bookshelf when required. Because of how Node
require calls work, each time you require this file you’ll always get back the same instance of Bookshelf so you don’t need to worry about new connection pools being opened each time you reference it. The file itself is pretty simple. Just a reference to Knex, Bookshelf, then a line that exports the Bookshelf instance.
1 2 3 4 5 6 7 8 9
The one line to take note of is the one that reads
bookshelf.plugin('registry');. That declares that you’ll be using the Model Registry plugin. This plugin allows you to specify relations between models using a string instead of passing variables. You can read more about how it works on the wiki but for our purposes what you need to know is that it takes care of those circular dependencies.
Creating the models
Now that you have a module for the database you can focus on your models. Let’s suppose that you have an application with users and those users generate invoices so we have a User and Invoice model. We’ll create those here:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Again, a pretty basic model. You access Bookshelf not by requiring it directly but instead by requiring your
database.js file which returns the same instance of Bookshelf wherever it gets called. The line to look at is the last one, the
exports call. Here we’re registering our User model as the string
'User'. Now we’ll be able to reference the User model using a string rather than assigning it to a variable (that’s what gets us the circular dependency error to begin with).
Another thing to note is that we’re
require()ing our Invoice model but not assigning it to a variable. The Registry plugin expects you to simply require the model you need as a relation, it’s perfectly fine if you don’t assign it to a variable (and in fact you should not assign it to a variable).
So now let’s build the invoice model:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
The Invoice model is created exactly like the User model so I won’t explain the code a second time.
Using the models and relations
Now that the models are set up and the relations are defined we can use them in our code. Here’s an example of what you’d write within an Express route to get invoices related to a user.
1 2 3 4 5 6 7 8 9 10 11 12 13
And that’ll get you the JSON representation of your user in the browser and the invoices relation in your console. Once you set it up it seems obvious. Its just too bad the Bookshelf docs don’t make this clearer.