loopback/docs/api-model-remote.md

6.3 KiB

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.

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, as explained below. The callback is an assumed argument; do not specify.
returns No Describes the remote method's callback arguments, as explained below.. 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).

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 look up the value using the following algorithm (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.user

A Model representing the user calling the method remotely. Note: this is undefined if the remote method is not invoked by a logged in user.

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 ctx properties are available.

ctx.req

The express ServerRequest object. See full documentation.

ctx.res

The express ServerResponse object. See full documentation.