Overview
A remote method is a method of a model, exposed over a custom REST endpoint. Use a remote method to perform operations not provided by LoopBack’s standard model REST API.
Note: The easiest way to define a remote method is by using the command-line remote method generator. For an introductory example of defining a remote method, see Extend your API in Getting Started.
How to add a remote method to a model
To add a remote method to a model:
-
Create a function in the model extension file. The method name determines whether a remote method is static or an instance method. A method name starting with
prototype.
indicates an instance method; otherwise, it’s a static method. NOTE: By default, a remote method is static. You must specifyprototype.
in the method name to create an instance method. -
Register the remote method one of these two ways:
- Register using JSON in the model definition JSON file. For more information, see Registering a remote method in JSON.
- Register using JavaScript code in the model extension file calling
remoteMethod()
. For more information, see Registering a remote method in code.
Example
Tip: See another example of a remote method in Extend your API.
Suppose you have a Person model and you want to add a REST endpoint at /greet
that returns a greeting with a name provided in the request.
You add this code to /common/models/person.js
:
module.exports = function(Person){
Person.greet = function(msg, cb) {
cb(null, 'Greetings... ' + msg);
}
Person.remoteMethod('greet', {
accepts: {arg: 'msg', type: 'string'},
returns: {arg: 'greeting', type: 'string'}
});
};
Now, for example, a request to
POST /api/people/greet
with data {"msg": "John"}
will return:
Greetings... John!
Note: Notice the REST API request above uses the plural form “people” instead of “person”. LoopBack exposes the plural form of model names for REST API routes.
Using async/await
Remote methods can also return a promise instead of using the callback parameter.
module.exports = function(Person){
Person.greet = async function(msg) {
return 'Greetings... ' + msg;
}
Person.remoteMethod('greet', {
accepts: {arg: 'msg', type: 'string'},
returns: {arg: 'greeting', type: 'string'}
});
};
Registering a remote method
There are two ways to register a remote method:
- In code, in the model extension file (
modelName.js
). - In JSON, in the model definition JSON file (
modelName.json
).
Registering a remote method in code
LoopBack models have a remoteMethod()
static method that you use to register a remote method:
Model.remoteMethod(requestHandlerFunctionName, [options])
Where:
model
is the model object to which you’re adding the remote method. In our example,Person
.requestHandlerFunctionName
is a string that specifies name of the remote method, for example'greet'
.options
is an object that specifies parameters to configure the REST endpoint; see Options below.
Registering a remote method in JSON
To register a remote method in the model definition JSON file,
add the method name as a key under methods
. To define an instance method, prepend prototype.
to the method name.
"methods": {
"prototype.getProfile": {
"accepts": [],
"returns": { "arg": "data", "type": "User", "root": true},
"http": {"verb": "get", "path": "/profile"},
"accessScopes": ["read", "read:profile"]
},
"someStaticMethod" : { ... }
The value of each key under methods
is the options object described below.
Options
The options argument is a Javascript object that defines how the remote method works.
Important:
All of the options properties are optional. However, if the remote method requires arguments, you must specify accepts
; if the remote method returns a value, you must specify returns
.
Option | Description | Example |
---|---|---|
accepts |
Defines arguments that the remote method accepts that map to the static method you define. For the example above, the function signature is Person.greet(name, age, callback)...so name is the first argument, age is the second argument and callback is automatically provided by LoopBack (do not specify it in your accepts array). For more information, see Argument descriptions.The default value is the empty array, [ ] .
|
{ ... accepts: [ {arg: 'name', type: 'string'}, {arg: 'age', type: 'number'}, ...], ... } |
accessScopes |
Defines access scopes. A user will be allowed to invoke this remote
method only when their access token was granted at least one of
the scopes defined by `accessScopes` list. See also
Authorization scopes.
The default value is a list with a single scope DEFAULT .
|
accessScopes: [ 'read', 'read:user' ] |
description | Text description of the method, used by API documentation generators such as OpenAPI (formerly Swagger). You can put long strings in an array if needed (see note below). | |
http | Specifies information about the route at which the method is exposed. See http property below. | |
notes | Additional notes, used by OpenAPI (formerly Swagger). You can put long strings in an array if needed (see note below). | |
documented |
If set to false , this method will not be present in generated OpenAPI (formerly Swagger) documentation.
|
|
returns |
Describes the remote method's callback arguments; See Argument descriptions. The err argument is assumed; do not specify.
Default if not provided is the empty array, [] .
|
returns: {arg: 'greeting', type: 'string'} |
Tip: You can split long strings in the description
and notes
options into arrays of strings (lines) to keep line lengths manageable. For example:
[
"Lorem ipsum dolor sit amet, consectetur adipiscing elit,",
"sed do eiusmod tempor incididunt ut labore et dolore",
"magna aliqua."
]
http property
The http
property provides information on HTTP route at which the remote
method is exposed.
Argument descriptions
The accepts
and returns
options properties define either a single argument as an object or an ordered set of arguments as an array.
The following table describes the properties of each individual argument.
Property (key) | Type | Description |
---|---|---|
arg | String | Argument name |
description | String or Array | A text description of the argument. This is used by API documentation generators like OpenAPI (formerly Swagger). You can put long strings in an array if needed (see note above). |
http | Object or Function | For input arguments: a function or an object describing mapping from HTTP request to the argument value. See HTTP mapping of input arguments below. |
http.target | String |
Map the callback argument value to the HTTP response object. The following values are supported.
|
required | Boolean | True if argument is required; false otherwise. |
root | Boolean | 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).
|
type | String | Argument datatype; must be a Loopback type. Additionally, callback arguments allow a special type "file"; see below. |
default | String | Default value that will be used to populate loopback-explorer input fields and swagger documentation. Note: This value will not be passed into remote methods function if argument is not present. |
documented | Boolean | If set to false , this parameter will not be present in generated OpenAPI (formerly Swagger) documentation. |
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'}
]
Returning a file (stream) response
Specify { type: 'file', root: true }
for a callback argument that will be sent directly as the response body. A file argument can be set to one of the following values:
- String
- Buffer
- ReadableStream (anything that exposes
.pipe()
method)
Example:
module.exports = function(MyModel) {
MyModel.download = function(cb) {
// getTheStreamBody() can be implemented by calling http.request() or fs.readFile() for example
getTheStreamBody(function(err, stream) {
if (err) return cb(err);
// stream can be any of: string, buffer, ReadableStream (e.g. http.IncomingMessage)
cb(null, stream, 'application/octet-stream');
});
};
MyModel.remoteMethod('download', {
returns: [
{arg: 'body', type: 'file', root: true},
{arg: 'Content-Type', type: 'string', http: { target: 'header' }}
]
});
};
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
Using an object with a source property
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.body which searches the request body
|
query |
The value is looked up using req.query which searches the query string
|
path |
The value is looked up using req.params which searches the route arguments
|
req | The Express HTTP request object. |
res | The Express HTTP response object. |
context | The whole context object, which holds request and response objects. |
For example, an argument getting the whole request body as the value:
{ arg: 'data', type: 'object', http: { source: 'body' } }
Another example showing the Express HTTP request and response objects:
[
{arg: 'req', type: 'object', 'http': {source: 'req'}},
{arg: 'res', type: 'object', 'http': {source: 'res'}}
]
Using a custom mapping function
The second way to specify HTTP mapping for input parameters is to specify a custom mapping function; for example:
{
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.
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):
- If there is an HTTP request parameter
args
with JSON content, then it uses the value ofargs['name']
. - Otherwise, it uses
req.param('name')
.
Returning data outside of a JSON field
Specifying a return argument with the arg property will automatically return a JSON object with your data stored within a field of the same name.
If you want to return data as the main response, for example an array, you can do so by setting the root property within the returns object and omitting arg.
returns: {type: 'array', root: true}
Setting a remote method route
By default, a remote method is exposed at:
POST http://apiRoot/modelName/methodName
Where
- apiRoot is the application API root path.
- modelName is the plural name of the model.
- methodName is the function name.
Following the above example, by default the remote method is exposed at:
POST /api/people/greet
To change the route, use the http.path
and http.verb
properties of the options argument to remoteMethod()
, for example:
Person.remoteMethod('greet',{
accepts: {arg: 'msg', type: 'string'},
returns: {arg: 'greeting', type: 'string'},
http: {path: '/sayhi', verb: 'get'}
});
This call changes the default route to
GET /api/people/sayhi
So a GET request to http://localhost:3000/api/people/sayhi?msg=LoopBack%20developer
returns:
{"greeting": "Greetings... LoopBack developer"}
Adding ACLs to remote methods
To constrain access to custom remote methods, use the ACL generator in the same way you control access to any model API. The access type for custom remote methods is Execute.
Basic use
For example, to deny invocation of the greet
method used in the examples above:
$ lb acl
[?] Select the model to apply the ACL entry to: Person
[?] Select the ACL scope: A single method
[?] Enter the method name: greet
[?] Select the access type: Execute
[?] Select the role: All users
[?] Select the permission to apply: Explicitly deny access
The tool then creates the following access control specification:
...
"acls": [{
"principalType": "ROLE",
"principalId": "$everyone", // apply the ACL to everyone
"permission": "DENY", // DENY attempts to invoke this method
"property": "greet" // applies the access control to the greet() method
}],
...
Advanced use
Another example, to allow invocation of the a remote method only for the $owner
of that model object:
module.exports = function(YourModel) {
//...
YourModel.remoteMethod(
'someRemoteMethod',
{
accepts: [
{arg: 'id', type: 'number', required: true}
],
// mixing ':id' into the rest url allows $owner to be determined and used for access control
http: {path: '/:id/some-remote-method', verb: 'get'}
}
);
};
Formatting remote method responses
You can reformat the response returned by all remote methods by adding a boot script
that modifies the object returned by app.remotes()
as follows:
module.exports = function(app) {
var remotes = app.remotes();
// modify all returned values
remotes.after('**', function (ctx, next) {
ctx.result = {
data: ctx.result
};
next();
});
};
Disabling a remote method
To disable a remote method use Model.disableRemoteMethod(name, isStatic)
and Model.disableRemoteMethodByName(name)
. For more information, see: