Understand the purpose of application models


Models represent the data managed by the Blueprint application. For example, we can have models that define messages, comments, and likes.

In Blueprint, we do not provide a general-purpose modeling language to define your models. Instead, we rely of domain-specific frameworks and libraries to define a model. For example, if you want to use MongoDB, then you can use mongoose as your modeling language. Likewise, if you are using SQL, you can use sequelize as your modeling language.

Typically, there are Blueprint modules that provide support for different storage strategies In such cases, the module will dictate what framework or library to use. For example, the blueprint-mongodb module uses mongoose. This means that when you use blueprint-mongodb, its corresponding models will be defined using a mongoose Schema.

All models are located in the app/models directory.

Defining a Model

As mentioned in the introduction, Blueprint does not provide a general-purpose modeling language for users to define models. Instead, Blueprint relies on existing frameworks and libraries to define models. This makes it easier for Blueprint to support polyglot data solutions.

To illustrate how to define a model, let's convert our the message class we defined in the message controller to a local in-memory model. First, we create the message model.

const { BO } = require ('@onehilltech/blueprint');

module.exports = BO.extend ({
  id: null              // message id
  from: null,           // who the message is from
  to: null,             // who the message is to
  date: null,           // date of the message
  subject: null,        // message subject
  content: null,        // content of the message
  init () { (this, ...arguments);
    if (! = new Date ();

As you can see from the example above, we just move the class definition from the controller to its own module located in the app/models directory.

Accessing a Model

After you define your models, you access a model by defining a data property with the value model([name]). The name parameter is the name of the model. If the name of the data property is the same as the model, then the name is not required.

Let's update the message controller to use the message model.

const { Controller, Action, model } = require ('@onehilltech/blueprint');
const { pick } = require ('lodash');

module.exports = Controller.extend ({
  messages: null,                // collection of messsages
  Message: model ('message'),    // load the message model
  init () { (this, ...arguments);
    this.messages = [];
  create () {
    return Action.extend ({
      _nextId: 0,      // id of the next message
      execute (req, res) {
        let id = this._nextId ++;
        let data = Object.assign ({id}, pick (req.body.message, ['from','to','date','subject','content']));
        let msg = this.controller.Message.create (data);
        this.controller.messages.push (msg);
        res.status (200).json ({message: msg});

As shown in the example above, the Message data property is bound to the message model. We have to give to specify the name parameter because the name of the data property is different from the name of the model. Then, in the create() action, we use the Message model to create a new message.

Moving Forward

Again, this is just one example of create a model that uses a local in-memory model. The method you use for defining a model will vary depending on the storage strategy for you data. It is therefore for you to understand how you are storing you data, and identifying a library or framework to managed the data. Afterwards, accessing the model is the same regardless of what library or framework you use to manage the data.

Last updated