Page Contents

Overview

LoopBack models automatically have a standard set of HTTP endpoints that provide REST APIs for create, read, update, and delete (CRUD) operations on model data. The public property in model-config.json specifies whether to expose the model’s REST APIs, for example:

/server/model-config.json

...
"MyModel": {
  "public": true,
  "dataSource": "db"
},
...

To “hide” the model’s REST API, simply change public to false.

REST paths

By default, the REST APIs are mounted to the plural of the model name; specifically:

  • Model.settings.http.path
  • plural, if defined in the Model definition JSON file.
  • Automatically-pluralized model name (the default). For example, if you have a location model, by default it is mounted to /locations

Using the REST Router

By default, scaffolded applications expose models over REST using the loopback.rest router.

To manually expose a model over REST with the loopback.rest router, use the following code, for example:

/server/server.js

var app = loopback();
app.use(loopback.rest());

// Expose the `Product` model
app.model(Product);

After this, the Product model will have create, read, update, and delete functions working remotely from mobile. At this point, the model is schema-less and the data are not checked.

You can then view generated REST documentation at http://localhost:3000/explorer

LoopBack provides a number of built-in models that have REST APIs. See Built-in models REST API for more information.

Request format

For POST and PUT requests, the request body can be JSON, XML or urlencoded format, with the Content-Type header set to  application/json, application/xml, or application/x-www-form-urlencoded. The Accept header indicates its preference for the response format.

Passing JSON object or array using HTTP query string

Some REST APIs take a JSON object or array from the query string. LoopBack supports two styles to encode the object/array value as query parameters.

  • Syntax from node-querystring (qs)
  • Stringified JSON

For example,

http://localhost:3000/api/users?filter[where][username]=john&filter[where][email]=callback@strongloop.com
http://localhost:3000/api/users?filter={"where":{"username":"john","email":"callback@strongloop.com"}}

The table below illustrates how to encode the JSON object/array can be encoded in different styles:

JSON object/array for the filter object qs style Stringified JSON
{
where: {
  username: 'john',
  email: 'callback@strongloop.com'
  }
}
?filter[where][username]=john
&
filter[where][email]=callback@strongloop.com
?filter={"where":
{"username":"john",
 "email":"callback@strongloop.com"}
}
{
where: {
    username: {inq: ['john', 'mary']}
  }
}
?filter[where][username][inq][0]=john
&filter[where][username][inq][1]=mary
?filter={"where":
  {"username":{"inq":["john","mary"]}}
}
{
  include: ['a', 'b']
}
?filter[include]=a&filter[include]=b
?filter={"include":["a","b"]}

Response format

The response format for all requests is typically a JSON object/array or XML in the body and a set of headers. Some responses have an empty body. For example,

HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Allow-Credentials: true
Content-Type: application/json; charset=utf-8
Content-Length: 59
Vary: Accept-Encoding
Date: Fri, 24 Oct 2014 18:02:34 GMT
Connection: keep-alive

{"title":"MyNote","content":"This is my first note","id":1}

The HTTP status code indicates whether a request succeeded:

  • Status code 2xx indicates success
  • Status code 4xx indicates request related issues.
  • Status code 5xx indicates server-side problems

The response for an error is in the following JSON format:

  • message: String error message.
  • stack: String stack trace.
  • statusCode: Integer HTTP status code.

For example,

{
  "error": {
    "message": "could not find a model with id 1",
    "stack": "Error: could not find a model with id 1\n ...",
    "statusCode": 404
  }
}

Disabling API Explorer

LoopBack API Explorer is great when you’re developing your application, but for security reasons you may not want to expose it in production.

For an application using loopback-component-explorer, to disable explorer in production:

  • Set the NODE_ENV environment variable to “production”.
  • Then in server/component-config.production.json:

server/component-config.production.json

{
  "loopback-component-explorer": null
}

Predefined remote methods

By default, for a model backed by a data source that supports it, LoopBack exposes a REST API that provides all the standard create, read, update, and delete (CRUD) operations.

As an example, consider a simple model called Location (that provides business locations) to illustrate the REST API exposed by LoopBack. LoopBack automatically creates a number of Node methods with corresponding REST endpoints, including:

Model (Node) API HTTP Method Example Path
create() POST /locations
upsert() PUT /locations
upsert() PATCH /locations
exists() GET /locations/:id/exists
findById() GET /locations/:id
find() GET /locations
findOne() GET /locations/findOne
destroyById() or deleteById() DELETE /locations/:id
count() GET /locations/count
prototype.updateAttributes() PUT /locations/:id
prototype.updateAttributes() PATCH /locations/:id
createChangeStream() POST /locations/change-stream
updateAll() POST /locations/update
replaceOrCreate()* POST /locations/replaceOrCreate
replaceById()* POST /locations/:id/replace

* Added in loopback v. 2.30.0

Please note the above table is the default exposed endpoints for LoopBack 2.x, while they are exposed differently in LoopBack 3.x; please see the following table for LoopBack 3.x:

Model (Node) API HTTP Method Example Path
create() POST /locations
replaceOrCreate() PUT /locations
patchOrCreate() PATCH /locations
exists() GET /locations/:id/exists
findById() GET /locations/:id
find() GET /locations
findOne() GET /locations/findOne
destroyById() or deleteById() DELETE /locations/:id
count() GET /locations/count
replaceById() PUT /locations/:id
prototype.patchAttributes() PATCH /locations/:id
createChangeStream() POST /locations/change-stream
updateAll() POST /locations/update
replaceOrCreate() POST /locations/replaceOrCreate
replaceById() POST /locations/:id/replace

As you see the only difference between LoopBack 2.x and 3.0 in default configuration is the behaviour of HTTP PUT endpoints (both PUT /api/my-models and PUT /api/my-models/:id). By default in LoopBack 2.x, these endpoints invoke patch methods and perform a partial update, while in LoopBack 3.0, these methods perform a full replace.

replaceOnPUT flag

Use the replaceOnPUT property in model.json to change the behavior of mapping replace and update methods. If replaceOnPUT is true, replaceOrCreate and replaceById  use the HTTP PUT method; if it is false, updateOrCreate and updateAttributes/patchAttributes use the HTTP PUT method.

The following example illustrates how to set replaceOnPUT in location.json:

...
{
  name: "location",
  plural: "locations",
  relations: {},
  acls: [],
  properties: {  },
  replaceOnPUT: true
}...

Exposing and hiding models, methods, and endpoints

To expose a model over REST, set the public property to true in /server/model-config.json:

...
"Role": {
  "dataSource": "db",
  "public": false
},
...

Hiding methods and REST endpoints

If you don’t want to expose certain create, retrieve, update, and delete operations, you can easily hide them by calling  disableRemoteMethod() on the model.  For example, following the previous example, by convention custom model code would go in the file common/models/location.js. You would add the following lines to “hide” one of the predefined remote methods:

common/models/location.js

var isStatic = true;
MyModel.disableRemoteMethod('deleteById', isStatic);

Now the deleteById() operation and the corresponding REST endpoint will not be publicly available.

For a method on the prototype object, such as updateAttributes():

common/models/location.js

var isStatic = false;
MyModel.disableRemoteMethod('updateAttributes', isStatic);

Here’s an example of hiding all methods of the MyUser model through configuration, except for login and logout:

In server/model-config.json:

"MyUser": {
  "dataSource": "db",
  "public": true,
  "options": {
    "remoting": {
      "sharedMethods": {
        "*": false,
        "login": true,
        "logout": true
      }
    }
  }
}

You can also hide common methods across all models through config.json’s remoting object as follows:

"remoting": {
  "context": false,
  ...
  "sharedMethods": {
    "*": false,
    "login": true,
    "logout": true
  }
}

Alternatively you can also disable remoteMethods through javascript in your myUser.js model:

MyUser.disableRemoteMethod("create", true);
MyUser.disableRemoteMethod("upsert", true);
MyUser.disableRemoteMethod("updateAll", true);
MyUser.disableRemoteMethod("updateAttributes", false);

MyUser.disableRemoteMethod("find", true);
MyUser.disableRemoteMethod("findById", true);
MyUser.disableRemoteMethod("findOne", true);

MyUser.disableRemoteMethod("deleteById", true);

MyUser.disableRemoteMethod("confirm", true);
MyUser.disableRemoteMethod("count", true);
MyUser.disableRemoteMethod("exists", true);
MyUser.disableRemoteMethod("resetPassword", true);

MyUser.disableRemoteMethod('__count__accessTokens', false);
MyUser.disableRemoteMethod('__create__accessTokens', false);
MyUser.disableRemoteMethod('__delete__accessTokens', false);
MyUser.disableRemoteMethod('__destroyById__accessTokens', false);
MyUser.disableRemoteMethod('__findById__accessTokens', false);
MyUser.disableRemoteMethod('__get__accessTokens', false);
MyUser.disableRemoteMethod('__updateById__accessTokens', false);

Read-Only endpoints example

You may want to only expose read-only operations on your model hiding all POST, PUT, DELETE verbs

common/models/model.js

Product.disableRemoteMethod('create', true);				// Removes (POST) /products
Product.disableRemoteMethod('upsert', true);				// Removes (PUT) /products
Product.disableRemoteMethod('deleteById', true);			// Removes (DELETE) /products/:id
Product.disableRemoteMethod("updateAll", true);				// Removes (POST) /products/update
Product.disableRemoteMethod("updateAttributes", false);		// Removes (PUT) /products/:id
Product.disableRemoteMethod('createChangeStream', true);	// removes (GET|POST) /products/change-stream

To disable a REST endpoints for related model methods, use disableRemoteMethod().

For example, if there are post and tag models, where a post hasMany tags, add the following code to /common/models/post.js  to disable the remote methods for the related model and the corresponding REST endpoints: 

common/models/model.js

module.exports = function(Post) {
  Post.disableRemoteMethod('__get__tags', false);
  Post.disableRemoteMethod('__create__tags', false);
  Post.disableRemoteMethod('__destroyById__accessTokens', false); // DELETE
  Post.disableRemoteMethod('__updateById__accessTokens', false); // PUT
};

Hiding properties

To hide a property of a model exposed over REST, define a hidden property. See Model definition JSON file (Hidden properties).