var app = loopback()

LoopBackApplication

The App object represents a Loopback application.

The App object extends Express and supports Express / Connect middleware. See Express documentation for details.

var loopback = require('loopback');
var app = loopback();

app.get('/', function(req, res){
  res.send('hello world');
});

app.listen(3000);

app.remotes()

Lazily load a set of remote objects.

NOTE: Calling app.remotes() more than once returns only a single set of remote objects.

Returns
Name Type Description
result RemoteObjects

app.model(modelName, config)

Define and attach a model to the app. The Model will be available on the app.models object.

var Widget = app.model('Widget', {dataSource: 'db'});
Widget.create({name: 'pencil'});
app.models.Widget.find(function(err, widgets) {
  console.log(widgets[0]); // => {name: 'pencil'}
});
Arguments
Name Type Description
modelName String

The name of the model to define.

config Object

The model's configuration.

config
Name Type Description
dataSource String or DataSource

The DataSource to which to attach the model.

[options] Object

an object containing Model options.

[options.acls] ACL[]

an array of ACL definitions.

[options.hidden] String[]

experimental an array of properties to hide when accessed remotely.

[properties] Object

object defining the Model properties in LoopBack Definition Language.

Returns
Name Type Description
result ModelConstructor

the model class

app.models()

Get the models exported by the app. Returns only models defined using app.model()

There are two ways to access models:

  1. Call app.models() to get a list of all models.
var models = app.models();

models.forEach(function (Model) {
 console.log(Model.modelName); // color
});

**2. Use app.model to access a model by name. app.model has properties for all defined models.

The following example illustrates accessing the Product and CustomerReceipt models using the models object.

var loopback = require('loopback');
 var app = loopback();
 app.boot({
  dataSources: {
    db: {connector: 'memory'}
  }
});

app.model('product', {dataSource: 'db'});
app.model('customer-receipt', {dataSource: 'db'});

// available based on the given name
var Product = app.models.Product;

// also available as camelCase
var product = app.models.product;

// multi-word models are avaiable as pascal cased
var CustomerReceipt = app.models.CustomerReceipt;

// also available as camelCase
var customerReceipt = app.models.customerReceipt;
Returns
Name Type Description
result Array

Array of model classes.

app.dataSource(name, config)

Define a DataSource.

Arguments
Name Type Description
name String

The data source name

config Object

The data source config

app.remoteObjects()

Get all remote objects.

Returns
Name Type Description
result Object

Remote objects.

app.docs()

Enable swagger REST API documentation.

Note: This method is deprecated. Use loopback-explorer instead.

Options

Example

// enable docs
app.docs({basePath: 'http://localhost:3000'});

Run your app then navigate to the API explorer. Enter your API basepath to view your generated docs.

app.dataSources

An object to store dataSource instances.

app.enableAuth()

Enable app wide authentication.

app.boot([options])

Initialize an application from an options object or a set of JSON and JavaScript files.

This function takes an optional argument that is either a string or an object.

If the argument is a string, then it sets the application root directory based on the string value. Then it:

  1. Creates DataSources from the datasources.json file in the application root directory.
  2. Creates Models from the models.json file in the application root directory.

If the argument is an object, then it looks for model, dataSources, and appRootDir properties of the object. If the object has no appRootDir property then it sets the current working directory as the application root directory. Then it:

  1. Creates DataSources from the options.dataSources object.
  2. Creates Models from the options.models object.

In both cases, the function loads JavaScript files in the /models and /boot subdirectories of the application root directory with require().

NOTE: mixing app.boot() and app.model(name, config) in multiple files may result in models being undefined due to race conditions. To avoid this when using app.boot() make sure all models are passed as part of the models definition.

Throws an error if the config object is not valid or if boot fails.

Model Definitions

The following is example JSON for two Model definitions: "dealership" and "location".

{
  "dealership": {
    // a reference, by name, to a dataSource definition
    "dataSource": "my-db",
    // the options passed to Model.extend(name, properties, options)
    "options": {
      "relations": {
        "cars": {
          "type": "hasMany",
          "model": "Car",
          "foreignKey": "dealerId"  
        }
      }
    },
    // the properties passed to Model.extend(name, properties, options)
    "properties": {
      "id": {"id": true},
      "name": "String",
      "zip": "Number",
      "address": "String"
    }
  },
  "car": {
    "dataSource": "my-db"
    "properties": {
      "id": {
        "type": "String",
        "required": true,
        "id": true
      },
      "make": {
        "type": "String",
        "required": true
      },
      "model": {
        "type": "String",
        "required": true
      }
    }
  }
}
Arguments
Name Type Description
options String or Object

Boot options; If String, this is the application root directory; if object, has below properties.

options
Name Type Description
appRootDir String

Directory to use when loading JSON and JavaScript files (optional). Defaults to the current directory (process.cwd()).

models Object

Object containing Model definitions (optional).

dataSources Object

Object containing DataSource definitions (optional).

app.listen(cb)

Listen for connections and update the configured port.

When there are no parameters or there is only one callback parameter, the server will listen on app.get('host') and app.get('port').

// listen on host/port configured in app config
app.listen();

Otherwise all arguments are forwarded to http.Server.listen.

// listen on the specified port and all hosts, ignore app config
app.listen(80);

The function also installs a listening callback that calls app.set('port') with the value returned by server.address().port. This way the port param contains always the real port number, even when listen was called with port number 0.

Arguments
Name Type Description
cb Function

If specified, the callback is added as a listener for the server's "listening" event.

Returns
Name Type Description
result http.Server

A node http.Server with this application configured as the request handler.

loopback

loopback

Main entry for LoopBack core module. It provides static properties and methods to create models and data sources. The module itself is a function that creates loopback app. For example,

var loopback = require('loopback');
var app = loopback();

loopback.isBrowser

True if running in a browser environment; false otherwise.

loopback.isServer

True if running in a server environment; false otherwise.

loopback.version

Framework version.

loopback.mime

Expose mime.

loopback.createDataSource(name, Data)

Create a data source with passing the provided options to the connector.

Arguments
Name Type Description
name String

Optional name.

Data Object

Source options

Data
Name Type Description
connector Object

LoopBack connector.

Other properties *

See the relevant connector documentation.

loopback.createModel(name, properties, options)

Create a named vanilla JavaScript class constructor with an attached set of properties and options.

Arguments
Name Type Description
name String

Unique name.

properties Object
options Object

(optional)

loopback.remoteMethod(fn, options)

Add a remote method to a model.

Arguments
Name Type Description
fn Function
options Object

(optional)

loopback.template(path)

Create a template helper.

var render = loopback.template('foo.ejs');
var html = render({foo: 'bar'});
Arguments
Name Type Description
path String

Path to the template file.

Returns
Name Type Description
result Function

loopback.memory([name])

Get an in-memory data source. Use one if it already exists.

Arguments
Name Type Description
[name] String

The name of the data source. If not provided, the 'default' is used.

loopback.getModel(modelName)

Look up a model class by name from all models created by loopback.createModel()

Arguments
Name Type Description
modelName String

The model name

Returns
Name Type Description
result Model

The model class

loopback.getModelByType(The)

Look up a model class by the base model class. The method can be used by LoopBack to find configured models in models.json over the base model.

Arguments
Name Type Description
The Model

base model class

Returns
Name Type Description
result Model

The subclass if found or the base class

loopback.setDefaultDataSourceForType(type, dataSource)

Set the default dataSource for a given type.

Arguments
Name Type Description
type String

The datasource type

dataSource Object or DataSource

The data source settings or instance

Returns
Name Type Description
result DataSource

The data source instance

loopback.getDefaultDataSourceForType(type)

Get the default dataSource for a given type.

Arguments
Name Type Description
type String

The datasource type

Returns
Name Type Description
result DataSource

The data source instance

loopback.autoAttach()

Attach any model that does not have a dataSource to the default dataSource for the type the Model requests

loopback.token(options)

Options

  • cookies - An Array of cookie names
  • headers - An Array of header names
  • params - An Array of param names
  • model - Specify an AccessToken class to use

Each array is used to add additional keys to find an accessToken for a request.

The following example illustrates how to check for an accessToken in a custom cookie, query string parameter and header called foo-auth.

app.use(loopback.token({
  cookies: ['foo-auth'],
  headers: ['foo-auth', 'X-Foo-Auth'],
  cookies: ['foo-auth', 'foo_auth']
}));

Defaults

By default the following names will be checked. These names are appended to any optional names. They will always be checked, but any names specified will be checked first.

  • access_token
  • X-Access-Token
  • authorization
  • access_token

NOTE: The loopback.token() middleware will only check for signed cookies.

accessToken = new AccessToken

Token based authentication and access control.

AccessToken.ANONYMOUS

Anonymous Token

assert(AccessToken.ANONYMOUS.id === '$anonymous');

AccessToken.createAccessTokenId(callback)

Create a cryptographically random access token id.

Arguments
Name Type Description
callback Function
callback
Name Type Description
err Error
token String

AccessToken.findForRequest(req, [options], callback)

Find a token for the given ServerRequest.

Arguments
Name Type Description
req ServerRequest
[options] Object

Options for finding the token

callback Function
callback
Name Type Description
err Error
token AccessToken

accessToken.validate(callback)

Validate the token.

Arguments
Name Type Description
callback Function
callback
Name Type Description
err Error
isValid Boolean

accessContext = new AccessContext(context)

Access context represents the context for a request to access protected resources

Arguments
Name Type Description
context Object

The context object

context
Name Type Description
principals Principal[]

An array of principals

model Function

The model class

modelName String

The model name

modelId String

The model id

property String

The model property/method/relation name

method String

The model method to be invoked

accessType String

The access type

accessToken AccessToken

The access token

Returns
Name Type Description
result AccessContext

accessContext.addPrincipal(principalType, principalId, [principalName])

Add a principal to the context

Arguments
Name Type Description
principalType String

The principal type

principalId Any

The principal id

[principalName] String

The principal name

Returns
Name Type Description
result boolean

accessContext.getUserId()

Get the user id

Returns
Name Type Description
result Any

accessContext.getAppId()

Get the application id

Returns
Name Type Description
result Any

accessContext.isAuthenticated()

Check if the access context has authenticated principals

Returns
Name Type Description
result boolean

accessContext.debug()

Print debug info for access context.

principal = new Principal(type, id, [name])

This class represents the abstract notion of a principal, which can be used to represent any entity, such as an individual, a corporation, and a login id

Arguments
Name Type Description
type String

The principal type

id Any

The princiapl id

[name] String

The principal name

Returns
Name Type Description
result Principal

principal.equals(principal)

Compare if two principals are equal Returns true if argument principal is equal to this principal.

Arguments
Name Type Description
principal Object

The other principal

accessRequest = new AccessRequest(model, property, accessType, permission)

A request to access protected resources.

Arguments
Name Type Description
model String

The model name

property String
accessType String

The access type

permission String

The requested permission

Returns
Name Type Description
result AccessRequest

accessRequest.isWildcard()

Is the request a wildcard

Returns
Name Type Description
result boolean

ACLSchema

System grants permissions to principals (users/applications, can be grouped into roles).

Protected resource: the model data and operations (model/property/method/relation/…)

For a given principal, such as client application and/or user, is it allowed to access (read/write/execute) the protected resource?

ACL

A Model for access control meta data.

ACL.getMatchingScore(rule, req)

Calculate the matching score for the given rule and request

Arguments
Name Type Description
rule ACL

The ACL entry

req AccessRequest

The request

Returns
Name Type Description
result number

ACL.checkPermission(principalType, principalId, model, property, accessType, callback, )

Check if the given principal is allowed to access the model/property

Arguments
Name Type Description
principalType String

The principal type

principalId String

The principal id

model String

The model name

property String

The property/method/relation name

accessType String

The access type

callback Function

The callback function

undefined callback
Callback
Name Type Description
err String or Error

The error object

result AccessRequest

The access permission

ACL.checkAccess(context, callback)

Check if the request has the permission to access

Arguments
Name Type Description
context Object
callback Function

ACL.checkAccessForToken(token, model, modelId, method, callback)

Check if the given access token can invoke the method

Arguments
Name Type Description
token AccessToken

The access token

model String

The model name

modelId Any

The model id

method String

The method name

callback Function
callback
Name Type Description
err String or Error

The error object

allowed Boolean

is the request allowed

scope = new Scope

Resource owner grants/delegates permissions to client applications

For a protected resource, does the client application have the authorization from the resource owner (user or system)?

Scope has many resource access entries

Scope.checkPermission(scope, model, property, accessType, callback)

Check if the given scope is allowed to access the model/property

Arguments
Name Type Description
scope String

The scope name

model String

The model name

property String

The property/method/relation name

accessType String

The access type

callback Function
callback
Name Type Description
err String or Error

The error object

result AccessRequest

The access permission

ApplicationSchema

Data model for Application

application = new Application

Manage client applications and organize their users.

Application.register(Owner's, Name, Other, Callback)

Register a new application

Arguments
Name Type Description
Owner's owner

user id

Name name

of the application

Other options

options

Callback cb

function

application.resetKeys(callback)

Reset keys for the application instance

Arguments
Name Type Description
callback Function
callback
Name Type Description
err Error

Application.resetKeys(appId, callback)

Reset keys for a given application by the appId

Arguments
Name Type Description
appId Any
callback Function
callback
Name Type Description
err Error

Application.authenticate(appId, key, callback)

Authenticate the application id and key.

matched parameter is one of:

  • clientKey
  • javaScriptKey
  • restApiKey
  • windowsKey
  • masterKey
Arguments
Name Type Description
appId Any
key String
callback Function
callback
Name Type Description
err Error
matched String

The matching key

email = new Email

The Email Model.

Properties

  • to - String (required)
  • from - String (required)
  • subject - String (required)
  • text - String
  • html - String

email.send(options, callback)

Send an email with the given options.

Example Options:

{
  from: "Fred Foo <foo@blurdybloop.com>", // sender address
  to: "bar@blurdybloop.com, baz@blurdybloop.com", // list of receivers
  subject: "Hello", // Subject line
  text: "Hello world", // plaintext body
  html: "<b>Hello world</b>" // html body
}

See https://github.com/andris9/Nodemailer for other supported options.

Arguments
Name Type Description
options Object

See below

callback Function

Called after the e-mail is sent or the sending failed

options
Name Type Description
from String

Senders's email address

to String

List of one or more recipient email addresses (comma-delimited)

subject String

Subject line

text String

Body text

html String

Body HTML (optional)

model = new Model

The built in loopback.Model.

Arguments
Name Type Description
data Object

Model.checkAccess(token, modelId, method, The, callback)

Check if the given access token can invoke the method

Arguments
Name Type Description
token AccessToken

The access token

modelId Any

The model id

method String

The method name

The callback

callback function

callback Function
callback
Name Type Description
err String or Error

The error object

allowed Boolean

is the request allowed

Model.getApp(callback)

Get the Application the Model is attached to.

Arguments
Name Type Description
callback Function
callback
Name Type Description
err Error
app Application

Model.remotes(callback)

Get the Model's RemoteObjects.

Arguments
Name Type Description
callback Function
callback
Name Type Description
err Error
remoteObjects RemoteObjects

dataModel = new DataModel

DataModel

Extends Model with basic query and CRUD support.

Change Event

Listen for model changes using the change event.

MyDataModel.on('changed', function(obj) {
   console.log(obj) // => the changed model
});
Arguments
Name Type Description
data Object
data.id Number

The default id property

DataModel.create([optional], obj))

Create new instance of Model class, saved in database

Arguments
Name Type Description
[optional] data
obj) callback(err or

callback called with arguments:

  • err (null or Error)
  • instance (null or Model)

DataModel.upsert

Update or insert a model instance

Arguments
Name Type Description
data Object

The model instance data

[callback] Function

The callback function

DataModel.findOrCreate(query, data, cb)

Find one record, same as all, limited by 1 and return object, not collection, if not found, create using data provided as second argument

Arguments
Name Type Description
query Object

search conditions: {where: {test: 'me'}}.

data Object

object to create.

cb Function

callback called with (err, instance)

DataModel.exists(id, cb)

Check whether a model instance exists in database

Arguments
Name Type Description
id id

identifier of object (primary key value)

cb Function

callbacl called with (err, exists: Bool)

DataModel.findById(id, cb)

Find object by id

Arguments
Name Type Description
id Any

primary key value

cb Function

callback called with (err, instance)

DataModel.find(params, callback)

Find all instances of Model, matched by query make sure you have marked as index: true fields for filter or sort

Arguments
Name Type Description
params Object

(optional)

  • where: Object { key: val, key2: {gt: 'val2'}}
  • include: String, Object or Array. See DataModel.include documentation.
  • order: String
  • limit: Number
  • skip: Number
callback Function

(required) called with arguments:

  • err (null or Error)
  • Array of instances

DataModel.findOne(params, cb)

Find one record, same as all, limited by 1 and return object, not collection

Arguments
Name Type Description
params Object

search conditions: {where: {test: 'me'}}

cb Function

callback called with (err, instance)

DataModel.count(where, cb)

Return count of matched records

Arguments
Name Type Description
where Object

search conditions (optional)

cb Function

callback, called with (err, count)

dataModel.save({validate:, obj))

Save instance. When instance haven't id, create method called instead. Triggers: validate, save, update | create

Arguments
Name Type Description
{validate: options

true, throws: false} [optional]

obj) callback(err or

dataModel.isNewRecord()

Determine if the data model is new.

Returns
Name Type Description
result Boolean

dataModel.updateAttribute(name, value, callback)

Update single attribute

equals to `updateAttributes({name: value}, cb)

Arguments
Name Type Description
name String

name of property

value Mixed

value of property

callback Function

callback called with (err, instance)

dataModel.updateAttributes(data, callback)

Update set of attributes

this method performs validation before updating

Arguments
Name Type Description
data Object

data to update

callback Function

callback called with (err, instance)

dataModel.reload(callback)

Reload object from persistence

Arguments
Name Type Description
callback Function

called with (err, instance) arguments

dataModel.setId(val)

Set the corret id property for the DataModel. If a Connector defines a setId method it will be used. Otherwise the default lookup is used. You should override this method to handle complex ids.

Arguments
Name Type Description
val Any

The id value. Will be converted to the type the id property specifies.

dataModel.getIdName()

Get the id property name of the constructor.

DataModel.getIdName()

Get the id property name

roleMapping = new RoleMapping

The RoleMapping model extends from the built in loopback.Model type.

roleMapping.application(callback)

Get the application principal

Arguments
Name Type Description
callback Function
callback
Name Type Description
err Error
application Application

roleMapping.user(callback)

Get the user principal

Arguments
Name Type Description
callback Function
callback
Name Type Description
err Error
user User

roleMapping.childRole(callback)

Get the child role principal

Arguments
Name Type Description
callback Function
callback
Name Type Description
err Error
childUser User

role = new Role

The Role Model

Role.registerResolver(, The)

Add custom handler for roles

Arguments
Name Type Description
role
The resolver

resolver function decides if a principal is in the role dynamically

function(role, context, callback)

Role.isOwner(modelClass, modelId, userId, callback)

Check if a given userId is the owner the model instance

Arguments
Name Type Description
modelClass Function

The model class

modelId Any

The model id

userId *)

The user id

callback Function

Role.isAuthenticated(context, callback)

Check if the user id is authenticated

Arguments
Name Type Description
context Object

The security context

callback Function
callback
Name Type Description
err Error
isAuthenticated Boolean

Role.isInRole(role, context, callback)

Check if a given principal is in the role

Arguments
Name Type Description
role String

The role name

context Object

The context object

callback Function
callback
Name Type Description
err Error
isInRole Boolean

Role.getRoles(context, callback, callback)

List roles for a given principal

Arguments
Name Type Description
context Object

The security context

callback Function
callback Function
callback
Name Type Description
err
An String[]

array of role ids

user = new User

Extends from the built in loopback.Model type.

Default User ACLs.

  • DENY EVERYONE *
  • ALLOW EVERYONE create
  • ALLOW OWNER removeById
  • ALLOW EVERYONE login
  • ALLOW EVERYONE logout
  • ALLOW EVERYONE findById
  • ALLOW OWNER updateAttributes

User.login(credentials, callback)

Login a user by with the given credentials.

   User.login({username: 'foo', password: 'bar'}, function (err, token) {
     console.log(token.id);
   });
Arguments
Name Type Description
credentials Object
callback Function
callback
Name Type Description
err Error
token AccessToken

User.logout(accessTokenID, callback)

Logout a user with the given accessToken id.

   User.logout('asd0a9f8dsj9s0s3223mk', function (err) {
     console.log(err || 'Logged out');
   });
Arguments
Name Type Description
accessTokenID String
callback Function
callback
Name Type Description
err Error

user.hasPassword(password)

Compare the given password with the users hashed password.

Arguments
Name Type Description
password String

The plain text password

Returns
Name Type Description
result Boolean

user.verify(options)

Verify a user's identity by sending them a confirmation email.

   var options = {
     type: 'email',
     to: user.email,
     template: 'verify.ejs',
     redirect: '/'
   };

   user.verify(options, next);
Arguments
Name Type Description
options Object

User.confirm(userId, token, redirect, callback)

Confirm the user's identity.

Arguments
Name Type Description
userId Any
token String

The validation token

redirect String

URL to redirect the user to once confirmed

callback Function
callback
Name Type Description
err Error

User.resetPassword(options, callback)

Create a short lived acess token for temporary login. Allows users to change passwords if forgotten.

Arguments
Name Type Description
options Object
callback Function
options
Name Type Description
email String

The user's email address

callback
Name Type Description
err Error

Data Source object

LoopBack models can manipulate data via the DataSource object. Attaching a DataSource to a Model adds instance methods and static methods to the Model; some of the added methods may be remote methods.

Define a data source for persisting models.

var oracle = loopback.createDataSource({
  connector: 'oracle',
  host: '111.22.333.44',
  database: 'MYDB',
  username: 'username',
  password: 'password'
});

Methods

dataSource.createModel(name, properties, options)

Define a model and attach it to a DataSource.

var Color = oracle.createModel('color', {name: String});

You can define an ACL when you create a new data source with the DataSource.create() method. For example:

var Customer = ds.createModel('Customer', {
      name: {
        type: String,
        acls: [
          {principalType: ACL.USER, principalId: 'u001', accessType: ACL.WRITE, permission: ACL.DENY},
          {principalType: ACL.USER, principalId: 'u001', accessType: ACL.ALL, permission: ACL.ALLOW}
        ]
      }
    }, {
      acls: [
        {principalType: ACL.USER, principalId: 'u001', accessType: ACL.ALL, permission: ACL.ALLOW}
      ]
    });

dataSource.discoverModelDefinitions([username], fn)

Discover a set of model definitions (table or collection names) based on tables or collections in a data source.

oracle.discoverModelDefinitions(function (err, models) {
  models.forEach(function (def) {
    // def.name ~ the model name
    oracle.discoverSchema(null, def.name, function (err, schema) {
      console.log(schema);
    });
  });
});

dataSource.discoverSchema([owner], name, fn)

Discover the schema of a specific table or collection.

Example schema from oracle connector:

    {
      "name": "Product",
      "options": {
        "idInjection": false,
        "oracle": {
          "schema": "BLACKPOOL",
          "table": "PRODUCT"
        }
      },
      "properties": {
        "id": {
          "type": "String",
          "required": true,
          "length": 20,
          "id": 1,
          "oracle": {
            "columnName": "ID",
            "dataType": "VARCHAR2",
            "dataLength": 20,
            "nullable": "N"
          }
        },
        "name": {
          "type": "String",
          "required": false,
          "length": 64,
          "oracle": {
            "columnName": "NAME",
            "dataType": "VARCHAR2",
            "dataLength": 64,
            "nullable": "Y"
          }
        },
        "audibleRange": {
          "type": "Number",
          "required": false,
          "length": 22,
          "oracle": {
            "columnName": "AUDIBLE_RANGE",
            "dataType": "NUMBER",
            "dataLength": 22,
            "nullable": "Y"
          }
        },
        "effectiveRange": {
          "type": "Number",
          "required": false,
          "length": 22,
          "oracle": {
            "columnName": "EFFECTIVE_RANGE",
            "dataType": "NUMBER",
            "dataLength": 22,
            "nullable": "Y"
          }
        },
        "rounds": {
          "type": "Number",
          "required": false,
          "length": 22,
          "oracle": {
            "columnName": "ROUNDS",
            "dataType": "NUMBER",
            "dataLength": 22,
            "nullable": "Y"
          }
        },
        "extras": {
          "type": "String",
          "required": false,
          "length": 64,
          "oracle": {
            "columnName": "EXTRAS",
            "dataType": "VARCHAR2",
            "dataLength": 64,
            "nullable": "Y"
          }
        },
        "fireModes": {
          "type": "String",
          "required": false,
          "length": 64,
          "oracle": {
            "columnName": "FIRE_MODES",
            "dataType": "VARCHAR2",
            "dataLength": 64,
            "nullable": "Y"
          }
        }
      }
    }

dataSource.enableRemote(operation)

Enable remote access to a data source operation. Each connector has its own set of set remotely enabled and disabled operations. You can always list these by calling dataSource.operations().

dataSource.disableRemote(operation)

Disable remote access to a data source operation. Each connector has its own set of set enabled and disabled operations. You can always list these by calling dataSource.operations().

// all rest data source operations are
// disabled by default
var oracle = loopback.createDataSource({
  connector: require('loopback-connector-oracle'),
  host: '...',
  ...
});

// or only disable it as a remote method
oracle.disableRemote('destroyAll');

Notes:

  • Disabled operations will not be added to attached models.
  • Disabling the remoting for a method only affects client access (it will still be available from server models).
  • Data sources must enable / disable operations before attaching or creating models.

dataSource.operations()

List the enabled and disabled operations.

console.log(oracle.operations());

Output:

{
  find: {
    remoteEnabled: true,
    accepts: [...],
    returns: [...]
    enabled: true
  },
  save: {
    remoteEnabled: true,
    prototype: true,
    accepts: [...],
    returns: [...],
    enabled: true
  },
  ...
}

GeoPoint object

The GeoPoint object represents a physical location.

Use the GeoPoint class.

var GeoPoint = require('loopback').GeoPoint;

Embed a latitude / longitude point in a Model.

var CoffeeShop = loopback.createModel('coffee-shop', {
  location: 'GeoPoint'
});

You can query LoopBack models with a GeoPoint property and an attached data source using geo-spatial filters and sorting. For example, the following code finds the three nearest coffee shops.

CoffeeShop.attachTo(oracle);
var here = new GeoPoint({lat: 10.32424, lng: 5.84978});
CoffeeShop.find({where: {location: {near: here}}, limit:3}, function(err, nearbyShops) {
  console.info(nearbyShops); // [CoffeeShop, ...]
});

Distance Types

Note: all distance methods use miles by default.

  • miles
  • radians
  • kilometers
  • meters
  • miles
  • feet
  • degrees

Methods

geoPoint.distanceTo(geoPoint, options)

Get the distance to another GeoPoint; for example:

var here = new GeoPoint({lat: 10, lng: 10});
var there = new GeoPoint({lat: 5, lng: 5});
console.log(here.distanceTo(there, {type: 'miles'})); // 438

GeoPoint.distanceBetween(a, b, options)

Get the distance between two points; for example:

GeoPoint.distanceBetween(here, there, {type: 'miles'}) // 438

Properties

geoPoint.lat

The latitude point in degrees. Range: -90 to 90.

geoPoint.lng

The longitude point in degrees. Range: -180 to 180.

Model object

A Loopback Model is a vanilla JavaScript class constructor with an attached set of properties and options. A Model instance is created by passing a data object containing properties to the Model constructor. A Model constructor will clean the object passed to it and only set the values matching the properties you define.

// valid color
var Color = loopback.createModel('color', {name: String});
var red = new Color({name: 'red'});
console.log(red.name); // red

// invalid color
var foo = new Color({bar: 'bat baz'});
console.log(foo.bar); // undefined

Properties

A model defines a list of property names, types and other validation metadata. A DataSource uses this definition to validate a Model during operations such as save().

Options

Some DataSources may support additional Model options.

Define A Loopbackmodel.

var User = loopback.createModel('user', {
  first: String,
  last: String,
  age: Number
});

Methods

Model.attachTo(dataSource)

Attach a model to a DataSource. Attaching a DataSource updates the model with additional methods and behaviors.

var oracle = loopback.createDataSource({
  connector: require('loopback-connector-oracle'),
  host: '111.22.333.44',
  database: 'MYDB',
  username: 'username',
  password: 'password'
});

User.attachTo(oracle);

NOTE: until a model is attached to a data source it will not have any attached methods.

Properties

Model.properties

An object containing a normalized set of properties supplied to loopback.createModel(name, properties).

Example:

var props = {
  a: String,
  b: {type: 'Number'},
  c: {type: 'String', min: 10, max: 100},
  d: Date,
  e: loopback.GeoPoint
};

var MyModel = loopback.createModel('foo', props);

console.log(MyModel.properties);

Outputs:

{
  "a": {type: String},
  "b": {type: Number},
  "c": {
    "type": String,
    "min": 10,
    "max": 100
  },
  "d": {type: Date},
  "e": {type: GeoPoint},
  "id": {
    "id": 1
  }
}

CRUD and Query Mixins

Mixins are added by attaching a vanilla model to a data source with a connector. Each connector enables its own set of operations that are mixed into a Model as methods. To see available methods for a data source call dataSource.operations().

Log the available methods for a memory data source.

var ops = loopback
    .createDataSource({connector: loopback.Memory})
    .operations();

console.log(Object.keys(ops));

Outputs:

[ 'create',
  'updateOrCreate',
  'upsert',
  'findOrCreate',
  'exists',
  'findById',
  'find',
  'all',
  'findOne',
  'destroyAll',
  'deleteAll',
  'count',
  'include',
  'relationNameFor',
  'hasMany',
  'belongsTo',
  'hasAndBelongsToMany',
  'save',
  'isNewRecord',
  'destroy',
  'delete',
  'updateAttribute',
  'updateAttributes',
  'reload' ]

Here is the definition of the count() operation.

{
  accepts: [ { arg: 'where', type: 'object' } ],
  http: { verb: 'get', path: '/count' },
  remoteEnabled: true,
  name: 'count'
}

Static Methods

Note: These are the default mixin methods for a Model attached to a data source. See the specific connector for additional API documentation.

Model.create(data, [callback])

Create an instance of Model with given data and save to the attached data source. Callback is optional.

User.create({first: 'Joe', last: 'Bob'}, function(err, user) {
  console.log(user instanceof User); // true
});

Note: You must include a callback and use the created model provided in the callback if your code depends on your model being saved or having an id.

Model.count([query], callback)

Query count of Model instances in data source. Optional query param allows to count filtered set of Model instances.

User.count({approved: true}, function(err, count) {
  console.log(count); // 2081
});

Model.find(filter, callback)

Find all instances of Model, matched by query. Fields used for filter and sort should be declared with {index: true} in model definition.

filter

  • where Object { key: val, key2: {gt: 'val2'}} The search criteria

    • Format: {key: val} or {key: {op: val}}
    • Operations:
      • gt: >
      • gte: >=
      • lt: <
      • lte: <=
      • between
      • inq: IN
      • nin: NOT IN
      • neq: !=
      • like: LIKE
      • nlike: NOT LIKE
  • include String, Object or Array Allows you to load relations of several objects and optimize numbers of requests.

    • Format:
      • 'posts': Load posts
      • ['posts', 'passports']: Load posts and passports
      • {'owner': 'posts'}: Load owner and owner's posts
      • {'owner': ['posts', 'passports']}: Load owner, owner's posts, and owner's passports
      • {'owner': [{posts: 'images'}, 'passports']}: Load owner, owner's posts, owner's posts' images, and owner's passports
  • order String The sorting order

    • Format: 'key1 ASC, key2 DESC'
  • limit Number The maximum number of instances to be returned

  • skip Number Skip the number of instances
  • offset Number Alias for skip

  • fields Object|Array|String The included/excluded fields

    • ['foo'] or 'foo' - include only the foo property
    • ['foo', 'bar'] - include the foo and bar properties
    • {foo: true} - include only foo
    • {bat: false} - include all properties, exclude bat

Find the second page of 10 users over age 21 in descending order exluding the password property.

User.find({
  where: {
    age: {gt: 21}},
    order: 'age DESC',
    limit: 10,
    skip: 10,
    fields: {password: false}
  },
  console.log
);

Note: See the specific connector's docs for more info.

Model.destroyAll([where], callback)

Delete all Model instances from data source. Note: destroyAll method does not perform destroy hooks.

Product.destroyAll({price: {gt: 99}}, function(err) {
  // removed matching products
});

*NOTE: where is optional and a where object... do NOT pass a filter object

Model.findById(id, callback)

Find instance by id.

User.findById(23, function(err, user) {
  console.info(user.id); // 23
});

Model.findOne(where, callback)

Find a single instance that matches the given where expression.

User.findOne({where: {id: 23}}, function(err, user) {
  console.info(user.id); // 23
});

Model.upsert(data, callback)

Update when record with id=data.id found, insert otherwise. Note: no setters, validations or hooks applied when using upsert.

Custom static methods

Define a static model method.

User.login = function (username, password, fn) {
  var passwordHash = hashPassword(password);
  this.findOne({username: username}, function (err, user) {
    var failErr = new Error('login failed');

    if(err) {
      fn(err);
    } else if(!user) {
      fn(failErr);
    } else if(user.password === passwordHash) {
      MyAccessTokenModel.create({userId: user.id}, function (err, accessToken) {
        fn(null, accessToken.id);
      });
    } else {
      fn(failErr);
    }
  });
}

Setup the static model method to be exposed to clients as a remote method.

loopback.remoteMethod(
  User.login,
  {
    accepts: [
      {arg: 'username', type: 'string', required: true},
      {arg: 'password', type: 'string', required: true}
    ],
    returns: {arg: 'sessionId', type: 'any'},
    http: {path: '/sign-in'}
  }
);

Instance methods

Note: These are the default mixin methods for a Model attached to a data source. See the specific connector for additional API documentation.

model.save([options], [callback])

Save an instance of a Model to the attached data source.

var joe = new User({first: 'Joe', last: 'Bob'});
joe.save(function(err, user) {
  if(user.errors) {
    console.log(user.errors);
  } else {
    console.log(user.id);
  }
});

model.updateAttributes(data, [callback])

Save specified attributes to the attached data source.

user.updateAttributes({
  first: 'updatedFirst',
  name: 'updatedLast'
}, fn);

model.destroy([callback])

Remove a model from the attached data source.

model.destroy(function(err) {
  // model instance destroyed
});

Custom instance methods

Define an instance method.

User.prototype.logout = function (fn) {
  MySessionModel.destroyAll({userId: this.id}, fn);
}

Define a remote model instance method.

loopback.remoteMethod(User.prototype.logout)

Relationships

Model.hasMany(Model, options)

Define a "one to many" relationship.

// by referencing model
Book.hasMany(Chapter);
// specify the name
Book.hasMany('chapters', {model: Chapter});

Query and create the related models.

Book.create(function(err, book) {
  // create a chapter instance
  // ready to be saved in the data source
  var chapter = book.chapters.build({name: 'Chapter 1'});

  // save the new chapter
  chapter.save();

  // you can also call the Chapter.create method with
  // the `chapters` property which will build a chapter
  // instance and save the it in the data source
  book.chapters.create({name: 'Chapter 2'}, function(err, savedChapter) {
    // this callback is optional
  });

  // query chapters for the book using the 
  book.chapters(function(err, chapters) {
    // all chapters with bookId = book.id
    console.log(chapters);
  });

  book.chapters({where: {name: 'test'}, function(err, chapters) {
    // all chapters with bookId = book.id and name = 'test'
    console.log(chapters);
  });
});

Model.belongsTo(Model, options)

A belongsTo relation sets up a one-to-one connection with another model, such that each instance of the declaring model "belongs to" one instance of the other model. For example, if your application includes users and posts, and each post can be written by exactly one user.

    Post.belongsTo(User, {as: 'author', foreignKey: 'userId'});

The code above basically says Post has a reference called author to User using the userId property of Post as the foreign key. Now we can access the author in one of the following styles:

    post.author(callback); // Get the User object for the post author asynchronously
    post.author(); // Get the User object for the post author synchronously
    post.author(user) // Set the author to be the given user

Model.hasAndBelongsToMany(Model, options)

A hasAndBelongsToMany relation creates a direct many-to-many connection with another model, with no intervening model. For example, if your application includes users and groups, with each group having many users and each user appearing in many groups, you could declare the models this way,

    User.hasAndBelongsToMany('groups', {model: Group, foreignKey: 'groupId'});
    user.groups(callback); // get groups of the user
    user.groups.create(data, callback); // create a new group and connect it with the user
    user.groups.add(group, callback); // connect an existing group with the user
    user.groups.remove(group, callback); // remove the user from the group

Validations

Model.validatesFormatOf(property, options)

Require a model to include a property that matches the given format.

User.validatesFormat('name', {with: /\w+/});

Model.validatesPresenceOf(properties...)

Require a model to include a property to be considered valid.

User.validatesPresenceOf('first', 'last', 'age');

Model.validatesLengthOf(property, options)

Require a property length to be within a specified range.

User.validatesLengthOf('password', {min: 5, message: {min: 'Password is too short'}});

Model.validatesInclusionOf(property, options)

Require a value for property to be in the specified array.

User.validatesInclusionOf('gender', {in: ['male', 'female']});

Model.validatesExclusionOf(property, options)

Require a value for property to not exist in the specified array.

User.validatesExclusionOf('domain', {in: ['www', 'billing', 'admin']});

Model.validatesNumericalityOf(property, options)

Require a value for property to be a specific type of Number.

User.validatesNumericalityOf('age', {int: true});

Model.validatesUniquenessOf(property, options)

Ensure the value for property is unique in the collection of models.

User.validatesUniquenessOf('email', {message: 'email is not unique'});

Note: not available for all connectors.

Currently supported in these connectors:

myModel.isValid()

Validate the model instance.

user.isValid(function (valid) {
    if (!valid) {
        console.log(user.errors);
        // => hash of errors
        // => {
        // =>   username: [errmessage, errmessage, ...],
        // =>   email: ...
        // => }
    }
});

loopback.ValidationError

ValidationError is raised when the application attempts to save an invalid model instance.

Example:

{
  "name": "ValidationError",
  "status": 422,
  "message": "The Model instance is not valid. \
     See `details` property of the error object for more info.",
  "statusCode": 422,
  "details": {
    "context": "user",
    "codes": {
      "password": [
        "presence"
      ],
      "email": [
        "uniqueness"
      ]
    },
    "messages": {
      "password": [
        "can't be blank"
      ],
      "email": [
        "Email already exists"
      ]
    }
  },
}

You might run into situations where you need to raise a validation error yourself, for example in a "before" hook or a custom model method.

MyModel.prototype.preflight = function(changes, callback) {
  // Update properties, do not save to db
  for (var key in changes) {
    model[key] = changes[key];
  }

  if (model.isValid()) {
    return callback(null, { success: true });
  }

  // This line shows how to create a ValidationError
  err = new ValidationError(model);
  callback(err);
}

Shared methods

Any static or instance method can be decorated as shared. These methods are exposed over the provided transport (eg. loopback.rest).

Remote methods and hooks

You can expose a Model's instance and static methods to clients. A remote method must accept a callback with the conventional fn(err, result, ...) signature.

Static Methods

loopback.remoteMethod(fn, [options])

Expose a remote method.

Product.stats = function(fn) {
  var statsResult = {
    totalPurchased: 123456
  };
  var err = null;

  // callback with an error and the result
  fn(err, statsResult);
}

loopback.remoteMethod(
  Product.stats,
  {
    returns: {arg: 'stats', type: 'object'},
    http: {path: '/info', verb: 'get'}
  }
);

Options

The options argument is a JSON object, described in the following table.

Option Required? Description
accepts No Describes the remote method's arguments; See Argument description. The callback argument is assumed; do not specify.
returns No Describes the remote method's callback arguments; See Argument description. The err argument is assumed; do not specify.
http No HTTP routing information:
  • http.path: path (relative to the model) at which the method is exposed. May be a path fragment (for example, /:myArg) that will be populated by an arg of the same name in the accepts description. For example, the stats method above will be at the whole path /products/stats.
  • http.verb: HTTP method (verb) from which the method is available (one of: get, post, put, del, or all).
description No A text description of the method. This is used by API documentation generators like Swagger.

Argument description

The arguments description defines either a single argument as an object or an ordered set of arguments as an array. Each individual argument has keys for:

  • arg: argument name
  • type: argument datatype; must be a loopback type.
  • required: Boolean value indicating if argument is required.
  • root: For callback arguments: set this property to true if your function has a single callback argument to use as the root object returned to remote caller. Otherwise the root object returned is a map (argument-name to argument-value).
  • http: For input arguments: a function or an object describing mapping from HTTP request to the argument value, as explained below.

For example, a single argument, specified as an object:

{arg: 'myArg', type: 'number'}

Multiple arguments, specified as an array:

[
  {arg: 'arg1', type: 'number', required: true},
  {arg: 'arg2', type: 'array'}
]

HTTP mapping of input arguments

There are two ways to specify HTTP mapping for input parameters (what the method accepts):

  • Provide an object with a source property
  • Specify a custom mapping function

To use the first way to specify HTTP mapping for input parameters, provide an object with a source property that has one of the values shown in the following table.

Value of source property Description
body The whole request body is used as the value.
form The value is looked up using req.param, which searches route arguments, the request body and the query string.
query An alias for form (see above).
path An alias for form (see above).
req The whole HTTP reqest object is used as the value.

For example, an argument getting the whole request body as the value:

{ arg: 'data', type: 'object', http: { source: 'body' } }

The use the second way to specify HTTP mapping for input parameters, specify a custom mapping function that looks like this:

{
  arg: 'custom',
  type: 'number',
  http: function(ctx) {
    // ctx is LoopBack Context object

    // 1. Get the HTTP request object as provided by Express
    var req = ctx.req;

    // 2. Get 'a' and 'b' from query string or form data
    // and return their sum as the value
    return +req.param('a') + req.param('b');
  }
}

If you don't specify a mapping, LoopBack will determine the value as follows (assuming name as the name of the input parameter to resolve):

  1. If there is a HTTP request parameter args with a JSON content, then the value of args['name'] is used if it is defined.
  2. Otherwise req.param('name') is returned.

Remote hooks

Run a function before or after a remote method is called by a client.

// *.save === prototype.save
User.beforeRemote('*.save', function(ctx, user, next) {
  if(ctx.user) {
    next();
  } else {
    next(new Error('must be logged in to update'))
  }
});

User.afterRemote('*.save', function(ctx, user, next) {
  console.log('user has been saved', user);
  next();
});

Remote hooks also support wildcards. Run a function before any remote method is called.

// ** will match both prototype.* and *.*
User.beforeRemote('**', function(ctx, user, next) {
  console.log(ctx.methodString, 'was invoked remotely'); // users.prototype.save was invoked remotely
  next();
});

Other wildcard examples

// run before any static method eg. User.find
User.beforeRemote('*', ...);

// run before any instance method eg. User.prototype.save
User.beforeRemote('prototype.*', ...);

// prevent password hashes from being sent to clients
User.afterRemote('**', function (ctx, user, next) {
  if(ctx.result) {
    if(Array.isArray(ctx.result)) {
      ctx.result.forEach(function (result) {
        result.password = undefined;
      });
    } else {
      ctx.result.password = undefined;
    }
  }

  next();
});

Context

Remote hooks are provided with a Context ctx object which contains transport specific data (eg. for http: req and res). The ctx object also has a set of consistent apis across transports.

ctx.req.accessToken

The accessToken of the user calling the method remotely. Note: this is undefined if the remote method is not invoked by a logged in user (or other principal).

ctx.result

During afterRemote hooks, ctx.result will contain the data about to be sent to a client. Modify this object to transform data before it is sent.

REST

When loopback.rest is used the following additional ctx properties are available.

ctx.req

The express ServerRequest object. See full documentation.

ctx.res

The express ServerResponse object. See full documentation.