Custom application logic for Loopback models

This post is the continuation of the previous one
What if you want to customize your REST API or add different methods for it?When building an application, you’ll generally need to implement custom logic to process data and perform other operations before responding to client requests.
In Loopback there are 3 ways to do this:
  1. Adding logic to models
  2. Defining boot scripts
  3. Defining middleware
For this post I'm explaining about the first one, Adding logic to models. There are 3 types to add custom application logic to model.
  • Remote Method
  • Remote Hook
  • Operation Hook

Remote Method :

A remote-method is nothing but nodejs function mapped to REST endpoints. You can create remote-method by cli or typing by yourself (click here to know how). 
In the previous post, I used memory db. For this one, I'm going to use MongoDB as datasource. You need to install loopback-connector-mongodb to connect to MongoDB.
npm install loopback-connector-mongodb --save
Then you need to add datasource :
lb datasource
Enter the datasource name and select MongoDB connector from the list. Then, configure the MongoDB database configuration.
After adding datasource, create a model as described in the previous post (select the freshly created datasource).
Now, for creating remote-method, run this command :
lb remote-method
Select the model, in which you want the remote-method, enter the name of remote-method, enter endpoints (you can set multiple endpoints for the same remote-method) to be mapped to this remote-method, select method type (get, post, put, delete) and set arguments to be passed with the appropriate type.

? Select the model: library
? Enter the remote method name: test
? Is Static? Yes
? Description for method: 

Let's configure where to expose your new method in the public REST API.
You can provide multiple HTTP endpoints, enter an empty path when you are done.
? Enter the path of this endpoint: /test
? HTTP verb: post

Let's add another endpoint, enter an empty name when done.
? Enter the path of this endpoint: 

Describe the input ("accepts") arguments of your remote method.
You can define multiple input arguments.
Enter an empty name when you've defined all input arguments.
? What is the name of this argument? name
? Select argument's type: string
? Is this argument required? Yes
? Please describe the argument: 
? Where to get the value from? (auto)

* @param {string} name
* @param {Function(Error)} callback

library.test = function (name, callback) {

At last, there is a sample code given in cli, copy that and paste it into your model.js. You can write your logic instead of // TODO. If you are returning anything in response, you have to set return type in the model.json. If you are returning an Object set type "object" and if there is no root in an object or other type set root to "true". 

"returns": {
"type": "object",
"root": true

To return response use callback(). callback accepts two arguments, first as error and second as success. If there is some logical error you just use this callback(error), otherwise callback(null,success).
This remote-method is now listed in loopback explorer.

Remote Hook :

Basically, hooks in loopback used to do something before the method executes or after the method executes. Sometimes you got some parameters with a blank value, then you have to set the default value for them, so you can use before hook. Just like that, sometimes you have to process something after the method is done executing, so you use after hook.
This runs before the remote method :

modelName.beforeRemote( methodName, function( ctx, next) {

This runs after the remote method :

modelName.afterRemote( methodName, async function( ctx) {

Remote hooks are provided with a Context ctx object that contains transport-specific data (for HTTP: req and res). The ctx object also has a set of consistent APIs across transports.
The context object passed to afterRemoteError() hooks has an additional property ctx.error set to the Error reported by the remote method.

Operation Hook :

Operation hooks are not tied to a particular method, but rather are triggered from all methods that execute a particular high-level create, read, update, or delete operation. These are all methods of PersistedModel that application models inherit.

So, basically, if you want to check the data passed in the built-in create operation, use before create-hook. Similarly, after the create operation, on the basis of the response you need to add some logs or want to perform some action using after create-hook.
These are the operation hooks supported in loopback :
access, before save, after save, before delete, after delete, loaded, persist
Here is how you use these hooks. I am using only after save and before save here, for example, you can use any of above you need. This is after save method,

Library.observe('after save', function (ctx, next) {
ctx.instance //the request data
ctx.Model.modelName //name of the model

Here's before save,

Transaction.observe('before save', async function (ctx, next) {
ctx.instance //the request data
ctx.Model.modelName //name of the model

Here's the link for the official documentation:

Happy Coding