Background

LoopBack and Deployd are both flavors of the “noBackend” and “mBaaS” trends. Frameworks and tooling specifically designed to simplify backend development, allowing you to focus on building great web and mobile user experiences. For a brief history lesson on LoopBack, Deployd, and backend services in general, take a look at my previous post: “A Brief history of mBaaS”.

This post is designed to walk you through building a mobile or web backend. We’ll start by quickly prototyping our API in Deployd and MongoDB then migrate our data and our entire backend to LoopBack to run against our production MySQL database.

Note: If you are starting with an existing Deployd application, skip to Porting to LoopBack.

Installing LoopBack and Deployd

Before running the examples below, make sure you have these dependencies installed

  • node v0.10.x
  • mongodb
  • mysql (optional)
  • Install both deployd and LoopBack by running the command below:

    npm install -g strong-cli deployd

    You can verify they are installed with the following commands.

    dpd -V # deployd version
    slc version # strong-cli / loopback version

    The Prototype

    Create a prototype app with the dpd create command.

    dpd create dpd-inventory

    Then start up the dashboard.

    cd dpd-inventory
    dpd -d

    Create a new collection and enter “/products”. Give it two properties “name” (string) and “price” (number).

    Click on the “data” tab (on the left) and enter some test products. You should be able see your products by hitting “http://localhost:2403/products”.

    Create a user collection and leave the default route “/users”. Add an additional property “isAdmin” (boolean). Create two users for testing using the data editor. One user should have “isAdmin” set to true and the other false.

    In order to ensure only admins can edit products, create a “on validate” event in the products collection. Below is a simple check to see if the requesting user is logged in as an admin.

    var allowed = me && me.isAdmin;
    if(!allowed) cancel('You are not allowed...');
    

    Confirm the event is working with a simple PUT to the products collection.

    curl -X PUT -H “Content-Type:application/json” \
    -d ‘{“name”: “foobar”}’ \
    http://localhost:2403/products/a2f6072319577879

    The above request should respond with.

    {“message”:”You are not allowed…”,”status”:400}

    Porting to LoopBack

    The basic process for porting a deployd app to LoopBack can be split into 6 major steps.

    1. Create a LoopBack project
    2. Convert deployd Collections to LoopBack models
    3. Convert deployd Query Syntax to LoopBack’s syntax<
    4. Port the deployd User Collection to LoopBack’s User API
    5. Port deployd events to LoopBack hooks
    6. Migrate data from our MongoDB (if required)

    Creating our LoopBack project

    Create the LoopBack project with the following command.

    slc lb project lb-inventory
    cd lb-inventory

    Now we can run our app with node.

    node app

    Collections to Models

    First we convert our prototype’s collections to LoopBack model definitions. Below is part of the deployd configuration we are basing our LoopBack configuration on. It is located in “dpd-inventory/resources/products/config.json” and declares our deployd products collection.

    {
      "type": "Collection",
      "properties": {
        "name": {
          "name": "name",
          "type": "string",
          "typeLabel": "string",
          "required": false,
          "id": "name",
          "order": 0
        },
        "price": {
          "name": "price",
          "type": "number",
          "typeLabel": "number",
          "required": false,
          "id": "price",
          "order": 1
        }
      }
    }
    

    Whereas deployd uses the “dpd” tool for creating projects, LoopBack uses the “slc” tool to scaffold Models as well as the project itself. The following command will create an empty LoopBack model that we can add our properties to.

    Note: LoopBack expects the singular form of the deployd collection name.

    slc lb model product

    We can copy the entire “properties” configuration from our deployd product collection (“dpd-invetory/resources/products/config.json”) and remove the following incompatible properties.

    • typeLabel
    • id
    • order

    We should end up with a model definition that looks like this:

    "product": {
     "properties": {
       "name": {
         "name": "name",
         "type": "string",
         "required": false,
       },
       "price": {
         "name": "price",
         "type": "number",
         "required": false
       }
     },
     "public": true,
     "dataSource": "db"
    }
    

    Now we can create “products” using the LoopBack REST API.

    curl -X PUT -H “Content-Type:application/json” \
    -d ‘{“name”: “pencil”, “price”: 0.99}’ \
    http://localhost:3000/products

    Query Syntax

    Now we need to convert deployd query syntax to LoopBack’s syntax. This should be fairly simple using the qs node module / component. It works in both node and the browser.

    Here is a request using super agent using the deployd query syntax.

    require('superagent')
     .get('http://localhost:2403/products?{"price": {"$gt": 2}}')
     .set('Content-Type', 'application/json')
     .end(function(err, res) {
       console.log(res.body);
       // => [ { name: 'pen', price: 2.99, id: '74b1049dd990a83b' } ]
     });
    

    The same request in LoopBack would can be made by passing the query object to the qs module.

    var qs = require('qs');
    var query = {
     where: {
       price: {gt: 2}
     }
    };
    require('superagent')
     .get('http://localhost:3000/api/products?' + qs.stringify(query))
     .set('Content-Type', 'application/json')
     .end(function(err, res) {
       console.log(res.body);
       // => [ { name: 'pen', price: 2.99, id: '74b1049dd990a83b' } ]
     });
    

    Keep these subtle differences in mind:

    • LoopBack models are mounted at /api/:pluralName
    • deployd prefixes special query commands with $ where LoopBack does not
    • LoopBack takes a filter object of “where”, “limit”, “skip”, etc where deployd merges these into a single object

    Users and Access Control

    Porting your deployd User Collection to LoopBack’s User API is fairly simple. LoopBack apps come with a User model. The login, logout, and registration process are almost identical. Below are the key differences to resolve.

    • As of v1.4.1, LoopBack does not have a `/users/me` route
    • Requests must include a valid AccessToken instead of a session cookie

    LoopBack also supports role based authentication. Depending on your application, you might need to rework how roles are stored.

    Events to Hooks

    In our prototype example above, we created a deployd “on validate” hook to restrict edit access to admin users. Porting this to LoopBack can be done in several ways.

    The simplest way is to define an access control list. Below is an example that will add an access control prevent anyone from modifying products.

    slc lb acl –model product –deny –write –unauthenticated

    Alternatively we can use LoopBack’s hooks to write custom logic. The following example will prevent unauthenticated users from calling the following methods.

    // in lb-inventory/models/products.js
    var product = require('../app').models.product;
    product.beforeRemote('**', function(ctx, inst, next) {
     var token = ctx.req.accessToken;
     var isUser = token && token.userId;
     var allowed = ctx.req.method === 'GET' || isUser;
     var notAllowed = new Error('not allowed');
     notAllowed.statusCode = 401;
     if(!allowed) return next(notAllowed);
     next();
    });
    

    Migrating Data

    If your prototype application contains valuable data you have several options. The simplest option is to just keep using the MongoDB backing deployd. Below are several other options for migrating away from MongoDB using LoopBack.

    mongoexport

    This tool allows you to export your mongo collections as JSON / CSV / and other formats. If the database you are targeting allows you to import these formats, it should be fairly straightforward.

    Using LoopBack

    LoopBack’s API makes it pretty straightforward to read a collection of JSON objects from a MongoDB collection. If you followed the steps above – you should have a set of models that correspond to deployd’s collections. Just point your LoopBack data source at your local MongoDB and run a script that finds all records and inserts them into a data source pointing to another database.

    Recap

    Following the guide above, porting an application from deployd to LoopBack should be straightforward:

    • Since deployd collections and LoopBack models share a similar configuration format, so converting between the two shouldn’t take too much effort.
    • It’s a bit trickier to convert the Deployd query string syntax to LoopBack’s, but using the “qs” node module should make that easier.
    • Porting logic in events and resolving the differences in access control is probably the trickiest part of the migration, but …

    If you have any questions, leave a comment, open a github issue, or ping us at callback @ strongloop dot com.

    Next Steps