Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / Node.js

Sails API Development (2/2): Custom Methods, Overriding Default Actions, and Related

4.50/5 (2 votes)
2 May 2015CPOL5 min read 19.4K  
Documents the details on possibilities of developing API with Sails, and customizing auto-generated API

Introduction

This article is the 2nd part of a previous article... but is not written with contextual reference to the 1st part. This can be considered as an article on customizing sails API generate, for the Sails Nodejs framework.

Reference: Sails API development (1/2): Datalayer -models, connections, waterline, API -blueprint, and related

What is covered in the article:

  • You have generated API through sails, and attached models, modified the models.
  • We learn about making the API fit into your requirements, namely customizing it, modifying default behaviour.

How to Add Custom Methods / Logic on Your Sails API

Default / Shadow Routes

By default, sails provides the following methods, more details here.

The current version of Sails ships with the following API methods / default blueprint actions:

  • find
  • findOne
  • create
  • update
  • destroy
  • populate
  • add
  • remove

That means, only for the above method calls, your API routes are defined (these default routes are called 'shadow routes' on the blueprint framework.)

To customize what happens when the above methods are called, or to validate input data on API calls, or to override or disable these API end points, we have to customize the default actions/routes, or add new actions.

Customization Techniques Covered

We will explore four customization techniques targeted for sails v0.10.5 below:

Customize Existing API Action/Route

Say, our database has a guid primary key, and we want to check that the call to our API passes a guid parameter.

If not passed, or if we want to generate a guid, we need to add code customization like below.

All shadow route / default API call implementations, are defined under your sails folder \lib\hooks\blueprints\actions (and your sails folder is under your node_modules folder.)

We open the create.js under the directory, and just after getting the request parameters, we add additional code.

/lib/hooks/blueprints/actions/create.js
JavaScript
module.exports = function createRecord (req, res) {

    var Model = actionUtil.parseModel(req);

    // Create data object (monolithic combination of all parameters)
    // Omit the blacklisted params (like JSONP callback param, etc.)
    var data = actionUtil.parseValues(req);

//Harish: 5/2/1015: customized
if(!data.guid) { data.guid = guid(); }   //guid() is a custom function to generate guid in javascript.
console.log(JSON.stringify(data));

...

At the end of create.js, we add the guid method (function guid code taken from http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript).

JavaScript
//Harish: 5/2/2015: generate guid
function guid() {
  function s4() {
    return Math.floor((1 + Math.random()) * 0x10000)
      .toString(16)
      .substring(1);
  }
  return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
    s4() + '-' + s4() + s4() + s4();
}

After the above changes, whenever you call a 'create' action, you will notice your sails window showing the console log, and your model getting the guid parameter.

The above code is written for a model and API call like below:

API call:

http://localhost:1337/monster/create?name=lkjkljlkj

/api/models/monster.js

JavaScript
module.exports = {

  attributes: {
      name: {
      type: 'string',
      columnName: 'name'
    },
    guid: {
      type: 'string',
      unique: true,
      primaryKey: true,
      columnName: 'guid'
    }
  }
};

Override Existing API Action/Route

In a similar way like above, but without touching sails code under your node_modules\sails directory (so that you can upgrade sails later and your customization won't have to be re-written), you could do the customization by overriding the blueprint implementation.

(As suggested here: https://stackoverflow.com/questions/22273789/crud-blueprint-overriding-in-sails-js)

Create a \blueprints folder under your project's \api directory, and create a file like create.js if you want to override the default implementation.

And the hint is: ----------------

You could refer to / make a copy of the default create.js (as used in previous section) and modify.

It should be fine, except that, to ensure blueprint ActionUtil reference works, you may have to add the below line in replacement of the require(actionUtil) line:

JavaScript
actionUtil = require('sails/lib/hooks/blueprints/actionUtil');

-------------------

If your \api\blueprints directory contains only create.js, sails intelligently overrides only the create blueprint method, and not the others.

NOTE

  • One problem though, is that, all overrides are for all API controllers. So if you have 2 APIs in your project like admin.js and user.js, then there is no way you can override admin.js's destroy method alone (as an example).
    • So if you override destroy.js for one API controller, you are overriding it for all of them, and additional code may have to be written (read on to below point).
    • This behaviour is by design.
      • You can use req.options.controller / req.options.model in your overridden code, to decide how your override works for different controllers. These options will return for which model/controller the destroy is called.
  • Currently all overrides related files must be lowercase! (The default actions contains findOne.js, but in /api/blueprints, it needs to be findone.js.)

Disable Existing API Action/Route

You could disable all default blueprint actions for your API by putting the below in your API's controller.

So if you had a monster API, then you would put the below code in /api/controllers/MonsterController.js.

The _config values below, will override global configuration under /config/blueprint.js, for your controller.

JavaScript
module.exports = {
  _config: {
    actions: false,
    shortcuts: false,
    rest: false
  }
}

The above disables all default actions. Mostly, you won't need to do that, since that kind of handicaps the necessity for any auto-generated API itself.

But if you want some API functionality to be secured or protected away from default, the below will help.

How to Disable Only Some of the Default Methods but Not All

Suppose you do not want your API users to delete records.

You could simply override the destroy method by creating an empty destroy.js file under /api/blueprints/destroy.js.

And this will return a 404 for the destroy call.

Note: Overrides apply for all controllers not just one of them, to control that behaviour, read the Note section under 'override existing' section above.

Add New API Action/Route

Again, all you need to do is add a custom method under /api/blueprints folder. If you add abc.js then abc is loaded as an API method through blueprint as mentioned in 'override existing' section above.

Note: For the custom methods which are NOT overrides of the shadow routes, you have to add custom routes.

This is just an easy config line to be added in routes config (as found here).

If you create a /blueprints/foo.js file, you can bind a route to it 
in your /config/routes.js file with (for example):

GET /myRoute': {blueprint: 'foo'}

Sidebar Note: There is an interesting conversation on a similar customization with the core contributors at https://github.com/balderdashy/sails/issues/1653.

Sails Missing Documentation - Some Found Recorded Under github Issues @ https://github.com/balderdashy/sails/issues

In fact, a lot of the missing documentation for sails can be learnt from the sails github issue threads... like hidden functions.

Some amount of detail in this article is based out of information consolidated from there.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)