how to API REST tutorial

In this post, we are going to learn how to use LoopBack Node.js framework  to create a fully functional REST API over MongoDB.

We will follow these steps:

1- Define the models in the database

2- Define the relations between models

3- Define users access levels

PREREQUISITES

To follow this tutorial we will need NodeJS and MongoDB installed in our computer.

DATABASE SET UP

Install the LoopBack module.

sudo npm install loopback -g

Run Loopback and follow instructions.

slc loopback
[Node version -> 2.x, Stable version]
[Kind of application -> API server]

Move to the new folder.

cd "folder name"

We are going to do an e-commerce API for the example. We want to to store all date in a persistent way into a MongoDB database that will have Clients, Products and Comments.

In order to do so, we need to specify the route of the database. As it is not created yet, will create a new folder and connect it to MongoDB.

mkdir -p mongo/data
mongod --dbpath mongo/data

Then, in another terminal, we run the Loopback commands to create the database

We’ll call it “ecommerce”

slc loopback:datasource
? Enter the data-source name: MongoDB
? Select the connector for MongoDB: MongoDB (supported by StrongLoop)
Connector-specific configuration:
? Connection String url to override other settings (eg: mongodb://username:passw
ord@hostname:port/database):
? host: localhost
? port: 27017
? user:
? password:
? database: ecommerce
? Install loopback-connector-mongodb@^1.4 Yes

Once we generated the database, we can see the code generated by Loopback at the file model-config.json.

It is recommendable to change the attribute “dataSource”: “db” to the database we just created (“MongoDB”) at ACL,RoleMapping and Role.

1- DEFINE THE MODELS IN THE DATABASE

To create a new collection (what would be a table), we’ll use the following command.

slc loopback:model

The way to define the data will be as the following example:

? Enter the model name: Customer
? Select the data-source to attach Customer to: MongoDB (mongodb)
? Select model's base class User *
? Expose Customer via the REST API? Yes
? Custom plural form (used to build REST URL):
? Common model or server only? common

*In this case is not needed to define more attributes because we are extending the “User” class that already have username, password, email and other needed attributes.

Now we are going to define the “Product” collection.

slc loopback:model
? Enter the model name: Product
? Select the data-source to attach Product to: MongoDB (mongodb)
? Select model's base class PersistedModel
? Expose Product via the REST API? Yes
? Custom plural form (used to build REST URL):
? Common model or server only? common
? Property name: name
invoke loopback:property
? Property type: string
? Required? Yes
? Default value[leave blank for none]:
? Property name: description
invoke loopback:property
? Property type: string
? Required? Yes
? Default value[leave blank for none]:
? Property name: category
invoke loopback:property
? Property type: string
? Required? Yes
? Default value[leave blank for none]:
? Property name: image
invoke loopback:property
? Property type: string
? Required? No
? Default value[leave blank for none]:
? Property name: label
invoke loopback:property
? Property type: string
? Required? No
? Default value[leave blank for none]:
? Property name: price
invoke loopback:property
? Property type: number
? Required? Yes
? Default value[leave blank for none]:

Now, the comments:

slc loopback:model
? Enter the model name: Comments
? Select the data-source to attach Comments to: MongoDB (mongodb)
? Select model's base class PersistedModel
? Expose Comments via the REST API? Yes
? Custom plural form (used to build REST URL):
? Common model or server only? common

Let’s add some Comments properties now.

? Property name: rating
invoke loopback:property
? Property type: number
? Required? Yes
? Default value[leave blank for none]: 5
? Property name: comment
invoke loopback:property
? Property type: string
? Required? Yes
? Default value[leave blank for none]:

Now we have all the collections defined, it’s time to define the relation between them.

2- DEFINE THE RELATION BETWEEN MODELS

Let’s review what we have done up to now.

On the one hand, we have the e-commerce Users and on the other hand we have the Products.

We also want the Users to post Comments about our Products.

So these would be the relations:

1- A product can have several comments.

2- A product can have several users commenting about it.

3- A comment belongs to determined product.

therefore…

4- A user can post several comments.

and

5- A product can have several comments about it.

[insert schema here]

To define the relations between collections, we will use the following command:

slc loopback:relation

1- A product can have several comments.

slc loopback:relation
? Select the model to create the relationship from: Product
? Relation type: has many
? Choose a model to create a relationship with: Comments
? Enter the property name for the relation: comments
? Optionally enter a custom foreign key:
? Require a through model? No

2- A product can have several users commenting about it.

slc loopback:relation
? Select the model to create the relationship from: Product
? Relation type: has many
? Choose a model to create a relationship with: Customer
? Enter the property name for the relation: customers
? Optionally enter a custom foreign key:
? Require a through model? No

3- A comment belongs to determined product.

slc loopback:relation
? Select the model to create the relationship from: Comments
? Relation type: belongs to
? Choose a model to create a relationship with: Product
? Enter the property name for the relation: product
? Optionally enter a custom foreign key:

4- A user can post several comments.

slc loopback:relation
? Select the model to create the relationship from: Customer
? Relation type: has many
? Choose a model to create a relationship with: Comments
? Enter the property name for the relation: comments
? Optionally enter a custom foreign key: customerId
? Require a through model? No

5- A product can have several comments about it.

slc loopback:relation
? Select the model to create the relationship from: Comments
? Relation type: belongs to
? Choose a model to create a relationship with: Customer
? Enter the property name for the relation: customer
? Optionally enter a custom foreign key: customerId

With what we have done up to now

Up to this point, we already have the API and we can do some testing by this command.

node <project folder>/server/server.js

or

node .

Despite of this, we haven’t finished yet, as any user could use all the methods and CREATE and DELETE some data without any authentication, which drives us to the last step.

3- DEFINE USERS ACCESS LEVELS

The first thing that we are going to do in this section is to create the users “admin” and “kike” (although you can change the last one for your username) and we will give to the administrator privileges to the user “admin”.

Loopback allows us to include a script that will run whenever we start the service, so we will use that to introduce these two users into the database.

So, we create a file at <our project folder>/server/boot/script.js and copy the following code:

module.exports = function(app) {
  var MongoDB = app.dataSources.MongoDB;

  MongoDB.automigrate('Customer', function(err) {
    if (err) throw (err);
    var Customer = app.models.Customer;

  Customer.create([
    {username: 'admin', email: 'admin@admin.com', password: 'abcdef'},
    {username: 'kike', email: 'bodi.inf@gmail.com', password: 'abcdef'}
  ], function(err, users) {
  if (err) throw (err);
  var Role = app.models.Role;
  var RoleMapping = app.models.RoleMapping;

  //create the admin role
  Role.create({
    name: 'admin'
  }, function(err, role) {
    if (err) throw (err);
  //make admin
  role.principals.create({
    principalType: RoleMapping.USER,
    principalId: users[0].id
    }, function(err, principal) {
      if (err) throw (err);
      });
    });
  });
});

This will create two new users. A regular user (Kike) and an Admin user (obviously, admin). After that we create a Role admin and bind them together.

Now, let’s restrict the some accesses for Authenticated users:

We will use the Loopback Access Control List (ACL) by using this command:

slc loopback:acl

So first, let’s deny all kind of accesses:

slc loopback:acl
? Select the model to apply the ACL entry to: (all existing models)
? Select the ACL scope: All methods and properties
? Select the access type: All (match all types)
? Select the role All users
? Select the permission to apply Explicitly deny access

Once we have done this, let’s enable GET (READ) accesses for autheticated users:

slc loopback:acl
? Select the model to apply the ACL entry to: (all existing models)
? Select the ACL scope: All methods and properties
? Select the access type: Read
? Select the role Any authenticated user
? Select the permission to apply Explicitly grant access

And finally, allow Admins to perform all operations:

slc loopback:acl
? Select the model to apply the ACL entry to: (all existing models)
? Select the ACL scope: All methods and properties
? Select the access type: All (match all types)
? Select the role other
? Enter the role name: admin
? Select the permission to apply Explicitly grant access

Once we have done this, we finished and already have a fully functional REST API with Node.js.

We can run it and start playing with it with he following command:

node <project folder>/server/server.js

Cool, isn’t it? Now you can relax, take a cup of coffee and tell your coworkers how hard you have been working.

Cheers!