When you create model in LoopBack framework, you can inherit from PersistedModel class. This way all the HTTP methods are generated. I am wondering how can I disable certain HTTP methods?
One option is to override functions from PersistedModel with empty logic, but want method to disappear from Swagger API explorer.
When you create model in LoopBack framework, you can inherit from PersistedModel class. This way all the HTTP methods are generated. I am wondering how can I disable certain HTTP methods?
One option is to override functions from PersistedModel with empty logic, but want method to disappear from Swagger API explorer.
Share Improve this question asked Nov 16, 2014 at 17:23 luboskrnacluboskrnac 24.6k10 gold badges86 silver badges93 bronze badges6 Answers
Reset to default 3I did below in model.js files like below. This makes table readonly.
module.exports = function(model) {
var methodNames = ['create', 'upsert', 'deleteById','updateAll',
'updateAttributes','createChangeStream','replace','replaceById',
'upsertWithWhere','replaceOrCreate'
];
methodNames.forEach(function(methodName) {
disableMethods(model,methodName)
});
}
function disableMethods(model,methodName)
{
if(methodName!='updateAttributes')
model.disableRemoteMethod(methodName, true);
else
model.disableRemoteMethod(methodName, false);
}
The only thing which requires additional care is disabling of custom model methods (like User.login). You need to call disableRemoteMethod before explorer middleware: https://github./strongloop/loopback/issues/686
An update on Santhosh Hirekerur answer to make it hide everything on LB3, stop using the deprecated Model.disableRemoteMethod
method and also a more intelligent way to hide updateAttributes
and any other future methods that may work the same.
I check to see if the method is on the prototype and if it is, prefix the name with prototype.
before we disableRemoteMethodByName
:
module.exports = function (model) {
var methodNames = [
'create',
'upsert',
'deleteById',
'updateAll',
'updateAttributes',
'patchAttributes',
'createChangeStream',
'findOne',
'find',
'findById',
'count',
'exists',
'replace',
'replaceById',
'upsertWithWhere',
'replaceOrCreate'
];
methodNames.forEach(function (methodName) {
if (!!model.prototype[methodName]) {
model.disableRemoteMethodByName('prototype.' + methodName);
} else {
model.disableRemoteMethodByName(methodName);
}
});
}
I put the above code in server/middleware/disable-methods.js
and call it from a model like so:
var disableMethods = require('../../server/middleware/disable-methods');
module.exports = function (Model) {
disableMethods(Model);
}
Found answer in documentation. For example this disables PersistedModel.deleteById:
var isStatic = true;
MyModel.disableRemoteMethod('deleteById', isStatic);
So it looks like you it's not possible to disable all DELETE actions at the same time. For example method PersistedModel.deleteAll remains accessible in given example.
Developer must disable each relevant method from PersistedModel class explicitly.
Relevant docs are here
Sections:
- Hiding methods and REST endpoints
- Hiding endpoints for related models
In case of loopback 3
I had the same problem.
My first solution was to manually update the "public":true
items in server/model-configuration.json
but it was overridden anytime I used the Swagger tool to refresh the LoopBack API (with slc loopback:swagger myswaggerfilename
mand from the project root).
I finally wrote a Grunt task as a reliable workaround.
- Run it just after a
slc loopback:swagger
generation or just before running the API live. - you just have to specify the names of the paths I want to expose in the javascript array
list_of_REST_path_to_EXPOSE
- and make sure you are happy with the backup folder for the original
/server/model-config.json
file.
I wanted to share it with you in case:
https://github./FranckVE/grunt-task-unexpose-rest-path-loopback-swagger
Basically:
module.exports = function (grunt) {
grunt.registerTask('unexpose_rest_path_for_swagger_models_v1', function (key, value) {
try {
// Change the list below depending on your API project :
// list of the REST paths to leave Exposed
var list_of_REST_path_to_EXPOSE =
[
"swagger_example-api_v1",
"write_here_the_paths_you_want_to_leave_exposed"
];
// Location of a bakup folder for modified model-config.json (change this according to your specific needs):
var backup_folder = "grunt-play-field/backups-model-config/";
var src_folder = "server/";
var dest_folder = "server/";
var src_file_extension = ".json";
var src_file_root_name = "model-config";
var src_filename = src_file_root_name + src_file_extension;
var dest_filename = src_file_root_name + src_file_extension;
var src = src_folder + src_filename;
var dest = dest_folder + dest_filename;
var free_backup_file = "";
if (!grunt.file.exists(src)) {
grunt.log.error("file " + src + " not found");
throw grunt.util.error("Source file 'model-config.json' does NOT exists in folder '" + src_folder + "'");
}
// timestamp for the backup file of model-config.json
var dateFormat = require('dateformat');
var now = new Date();
var ts = dateFormat(now, "yyyy-mm-dd_hh-MM-ss");
// backup model-config.json
var root_file_backup = src_file_root_name + "_bkp" + "_";
var root_backup = backup_folder + root_file_backup;
free_backup_file = root_backup + ts + src_file_extension;
if (!grunt.file.exists(root_file_backup + "*.*", backup_folder)) {
//var original_file = grunt.file.read(src);
grunt.file.write(free_backup_file, "// backup of " + src + " as of " + ts + "\n");
//grunt.file.write(free_backup_file, original_file);
grunt.log.write("Creating BACKUP"['green'] + " of '" + src + "' " + "to file : "['green'] + free_backup_file + " ").ok();
} else {
grunt.log.write("NO BACKUP created"['red'] + " of '" + src + "' " + "because file : " + free_backup_file + " ALREADY EXISTS ! "['red']).error();
throw grunt.util.error("Destination backup file already exists");
}
// load model-config.json
var project = grunt.file.readJSON(src);//get file as json object
// make modifications in model-config.json
for (var rest_path in project) {
if (rest_path.charAt(0) === "_") {
grunt.log.write("SKIPPING"['blue'] + " the JSON item '" + rest_path + "' belonging to the " + "SYSTEM"['blue'] + ". ").ok();
continue; // skip first level items that are system-related
}
if (list_of_REST_path_to_EXPOSE.indexOf(rest_path) > -1) { //
project[rest_path]["public"] = true;
grunt.log.write("KEEPING"['green'] + " the REST path '" + rest_path + "' " + "EXPOSED"['green'] + ". ").ok();
} else {
project[rest_path]["public"] = false;
grunt.log.writeln("HIDING"['yellow'] + " REST path '" + rest_path + "' : it will " + "NOT"['yellow'] + " be exposed.");
}
}
}
I wanted to hide the PATCH method, but when I was trying to hide it also I got to hide the PUT method , I was using this line :
Equipment.disableRemoteMethod('updateAttributes', false);
but later I found a way to only hide the PATCH method, this line works perfect for me.
Equipment.sharedClass.find('updateAttributes', false).http = [{verb: 'put', path: '/'}];
The above line overrides the original http that updateAttributes method had.
[{verb: 'put', path: '/'}, {verb: 'patch', path: '/'}]