{base_path}/executeaction
API Options
Option | Type | Default | Description |
---|---|---|---|
model | String |
null |
Model name to work on, [Mendatory] |
read | JSON |
{} | options for model to be used to apply action on, [Optional] |
read.modeloptions | JSON |
Options to pass to your model define above | |
read.modelscope | String |false |
false to use unscoped model and avoid any default scope applied on model, or use define scope to use as string |
|
action_to_execute | String |
null |
Action to perform on defined model supported default actions are - vnatk_add : pass arg_item data to create a new record of given model. - vnatk_edit : pass arg_item data to edit model record, arg_item must have primary/autoincrement value availabe, model will be loaded by that value and all other values passed will be updated on model. - vnatk_delete : pass arg_item data to delete model record, arg_item must have primary/autoincrement value availabe, model will be loaded by that value and then destroys. - {Any User Defined Method Name} : pass arg_item data to your method defined in Model class/declatation. Actions retuns data of added/edited/deleted item, but in any case modeloptions contains some condition that is changed due to editing, |
arg_item | JSON |
null |
Argument passed for your action, for vnatk_edit and vnatk_delete actions, arg_item must have id or your primary key value to pick correct record, while for vnatk_add action data passed will be used to create fill in model.create . |
Pre defined actions
vnatk_add
Create single record of any model in flat manner (To create deep relational records please see vnatk_autoimport
)
let createRecordOption = {
model: 'User',
modelscope: false, // After create re-load record unscoped
action_to_execute: {execute: 'vnatk_add', name: 'vnatk_add'},
arg_item: {
name : 'Foo',
bar: 'Bar'
},
}
// Calling by axios
service.post('/vnatk/executeaction',crudOptions).then(response=>{
// newly created record loaded with default modelscope if modelscope is not set to false.
})
vnatk_edit
Edit any record by sending data along with id field value. this action updates flat record of any model, to update nested related complex condition based data, please see vnatk_autoimport
.
let createRecordOption = {
model: 'User',
modelscope: false, // After update re-load record unscoped
action_to_execute: {execute: 'vnatk_edit', name: 'vnatk_edit'},
arg_item: {
id: 1
name : 'Foo',
bar: 'Bar'
},
}
// Calling by axios
service.post('/vnatk/executeaction',crudOptions).then(response=>{
// newly created record loaded with default modelscope if modelscope is not set to false.
})
vnatk_delete
Delete any record by sending model and its id field value.
Do not worry about misuse of the APIs, you have full controll over who can actually execute these apis. Please visit safety and security
section.
let createRecordOption = {
model: 'User',
modelscope: false, // After update re-load record unscoped
action_to_execute: {execute: 'vnatk_delete', name: 'vnatk_delete'},
arg_item: {
id: 1
},
}
// Calling by axios
service.post('/vnatk/executeaction',crudOptions).then(response=>{
// sends success message on complete
})
vnatk_autoimport
The most interesting action that actually can replace vnatk_add
and vnatk_edit
both in one go with more control over what you want to do.
As the name suggests, this action can import multiple records in one go, including nested deep relational structured json data.
The strcuture of API payload is as follows
{
action_to_execute: { execute: 'vnatk_autoimport', name: 'vnatk_autoimport' },
importdata: importdata, // Array of objects, each object represents one record, flat or nested
model: String, // model name to start import into
transaction: String // ("row" or "file"), to make transaction all record based or one transaction per recrod
}
here importdata object is JSON data with following special properties to define action for data
-
$vnatk_data_handle
: How you want to handle specific record, you can use the option nested for each nested data also. Possible values arealwaysCreate
[default]: Record is always insertedfindOrCreate
: Find by matching all values that are passed or by using$vnatk_find_options
if defined to find, if not found, create a new record.findAndUpdateOrCreate
: Find by matching all values that are passed or by using$vnatk_find_options
if defined to find and then update changed values passed in object (field:value), if not found, create a new record.findToAssociate
: For nested records, try find existing record, if found use its relational key to associate with parent record or produce error if not found.associateIfFound
: For nested records, try find existing record, if found use its relational key to associate with parent record or ignore if not found
-
$vnatk_find_options
: Use this as where condition in sequelize models to find if vnatk_data_handle is to find record first $vnatk_cache_records
: Under development: To cache any record if already found, to avoid multiple database queires.$vnatk_update_data
: Under development: update values defined here instead all values passed to create if not found.
vnatk_autoimport example
Lets consider a data structure first, and then import/add/edit data based on VES executeaction
api on vnatk_autoimport
action.
//Gorup.js model
module.exports = (sequelize, DataTypes) => {
const Group = sequelize.define('Group', {
name: DataTypes.STRING,
}, {});
Group.associate = function (models) {
Group.hasMany(models.User, {
foreignKey: 'groupId',
as: 'GroupUsers'
})
};
return Group;
};
// User.js
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define('User', {
firstName: DataTypes.STRING,
lastName: DataTypes.STRING,
email: DataTypes.STRING,
password: DataTypes.STRING
}, {});
User.associate = function (models) {
// associations can be defined here
User.belongsTo(models.Group, {
foreignKey: 'groupId',
as: 'Group'
})
User.hasMany(models.Project, {
foreignKey: 'adminId',
as: 'ProjectsOwned'
})
User.belongsToMany(models.Project, {
foreignKey: 'adminId',
as: 'Projects',
through: models.UserProjects
})
};
return User;
};
// Skill.js
module.exports = (sequelize, DataTypes) => {
const Skill = sequelize.define('Skill', {
name: DataTypes.STRING,
}, {});
Skill.associate = function (models) {
// associations can be defined here
Skill.belongsTo(models.User, {
foreignKey: 'userId',
as: 'SkillOwner'
})
};
return Skill;
};
// Project.js
module.exports = (sequelize, DataTypes) => {
const Project = sequelize.define('Project', {
title: DataTypes.STRING,
imageUrl: DataTypes.STRING,
description: DataTypes.TEXT,
adminId: DataTypes.INTEGER
}, {});
Project.associate = function (models) {
Project.belongsTo(models.User, {
foreignKey: 'adminId',
onDelete: 'CASCADE',
as: 'ProjectAdmin'
})
Project.belongsToMany(models.User, {
foreignKey: 'adminId',
onDelete: 'CASCADE',
as: 'ProjectUsers',
through: models.UserProjects
})
};
return Project;
};
// UserProjects.js
module.exports = (sequelize, DataTypes) => {
const UserProjects = sequelize.define('UserProjects', {
assignedOn: DataTypes.DATE,
remarks: DataTypes.STRING,
isDone: DataTypes.BOOLEAN,
}, {});
UserProjects.associate = function (models) {
UserProjects.belongsTo(models.Project, {
foreignKey: 'projectId'
});
UserProjects.belongsTo(models.User, {
foreignKey: 'userId'
});
UserProjects.hasMany(models.UserProjectRemarks, {
foreignKey: 'userProjectId'
});
};
return UserProjects;
};
// UserProjectRemarks.js
module.exports = (sequelize, DataTypes) => {
const UserProjectRemarks = sequelize.define('UserProjectRemarks', {
remarks: DataTypes.STRING,
}, {});
UserProjectRemarks.associate = function (models) {
UserProjectRemarks.belongsTo(models.UserProjects, {
foreignKey: 'userProjectId',
as: 'ProjectRemarks'
})
};
return UserProjectRemarks;
};
Quite a complex structure to start with, but the power of VES only comes to proper view with such an example.
Lets create/import a record for this strcuture with following JSON payload. read comments to understand each line well.
let CreateOrImport = {
model: 'User',
modelscope: false, // After update re-load record unscoped
action_to_execute: {execute: 'vnatk_autoimport', name: 'vnatk_autoimport'},
transaction: 'file',
importdata: [{
$vnatk_data_handle = "findOrCreate"; // find as per below vnatk_find_options, if not found create by field values
$vnatk_find_options: {
modeloptions:{
where:{
email: 'foo@bar.com'
// group_id: true // To include belongsTo Group's id in where condition, actual Id will be taken in true's place
}
},
modelacope: false // to avoid any default acope in case
},
firstName: 'UserFirstName',
lastName: 'UserLastName',
email: 'foo@bar.com',
password: 'anyPassword'
// This User belongs to a Group that we also want to findOrCreate
// Belongs to are defined as Object, Once found/created Group id will be associated with User as well
Group: {
$vnatk_data_handle = "findOrCreate"; // find as per below vnatk_find_options, if not found create by field values
$vnatk_find_options:{
modeloptions: {
where:{
name: 'MyFirstGroup'
}
},
modelscope: false // To use unscoped model (in case defaultscope is set to active only)
},
name: 'MyFirstGroup'
}
// Lets add some hasMany records for this User
// has Many records are always passed as Array of Objects
Skills: [
{
name: 'skill_1',
$vnatk_data_handle: "findOrCreate", // Since no $vnatk_find_options is passed all fields (here is only one) will be used to find record
}
{
name: 'skill_2',
$vnatk_data_handle: "findOrCreate", // Since no $vnatk_find_options is passed all fields (here is only one) will be used to find record
}
]
// User has two relations with Projects, as HasMany ProjectsOwned and belongsToMany as Projects
// lets define HasMany data first.
// following key must match 'as' prperty defined in sequleize model relation.
ProjectsOwned: [
{
title: 'Project Title 1',
description: 'Project Description',
code: 'PRJ1',
$vnatk_data_handle: "findAndUpdateOrCreate", // if found, update admin Id to this user id
$vnatk_find_options: {
modeloptions: {
where:{
code: 'PRJ1',
}
},
modelscope: false,
},
$vnatk_update_data: {
code: 'PRJ1',
description: 'Project Description',
},
},
{
title: 'Project Title 2',
description: 'Project Description 2',
code: 'PRJ2',
$vnatk_data_handle: "findAndUpdateOrCreate", // if found, update admin Id to this user id
$vnatk_find_options: {
modeloptions: {
where:{
code: 'PRJ2',
}
},
modelscope: false,
},
}
// User belongs To many Projects with Through relation, lets create them as well
// belongs to are also defined as Array of Objects, where object denotes through table and that consists of belongsTo record entry, User id will be inserted automatically by VES
// following key must match 'as' prperty defined in sequleize model relation.
Projects: [
{
$vnatk_data_handle: "findOrCreate", // find will be based on relational keys here
assignedOn: "1970-01-01", // fields in through table
isDone: false, // field in through table
Project: {
// through model belongsTo Project is defined here
title: 'Project title 1',
$vnatk_data_handle: "findOrCreate",
$vnatk_find_options: {
modeloptions: {
where:{
code: 'PRJ1',
}
},
},
},
// Projects many to many relation also contains hasMany relation of remarks
UserProjectRemarks:[
{
// Since no $vnatk_data_handle is defined it is assumed to be alwaysCreated
remarks: 'Remark one',
},
{
// Since no $vnatk_data_handle is defined it is assumed to be alwaysCreated
remarks: 'Remark two',
}
]
},
{
$vnatk_data_handle: "findOrCreate", // find will be based on relational keys here
assignedOn: "1970-01-01", // fields in through table
isDone: true, // field in through table
Project: {
// through model belongsTo Project is defined here
title: 'Project Title 3',
$vnatk_data_handle: "findOrCreate",
$vnatk_find_options: {
modeloptions: {
where:{
code: 'PRJ3',
}
},
},
},
UserProjectRemarks:[
{
remarks: 'remark 3'
}
]
}
]
]
}],
}
// Calling by axios
service.post('/vnatk/executeaction',crudOptions).then(response=>{
// response contains information about your import data
})
Since importdata
is an array, you can send multiple records each with nested data to have your records created or imported as well. vnatk-vue
, allows you to convert csv/excel flat data to convert in this nested way by rowformatter
option in import
and then the same action is executed.
User defined methods
In case you want to execute any other method in your model you can simple change your action_to_execute.execute property to method name and arg_item will be passed to the method of your model
// Considering your model do have a method named sendEmail accepting some parameter as object.
let createRecordOption = {
model: 'User',
modelscope: false, // After update re-load record unscoped
action_to_execute: {execute: 'sendEmail'},
arg_item: { // this object will be passed to your method
user_email: 'foo@bar.com'
},
}
// Calling by axios
service.post('/vnatk/executeaction',crudOptions).then(response=>{
// sends success message on complete
})
Safety and Security
vnatk-express-sequelize, while provide you endpoints to do almost anything without writing code, also provides you three levels of access controls (more are under development) - By providing access token checker middelware
var express = require('express');
var router = express.Router();
const vnatk = require('vnatk-express-sequelize');
// THIS LINE TO USE AUTHENTICATION CHECKER
router.use(require('./middleware/adminTokenChecker'));
const Models = require('../../models');
module.exports = vnatk({
Models: Models,
router: router
});
- Providing whiteList/Blacklist models
Example: in your vnatk routes file plass options as follows
var express = require('express');
var router = express.Router();
const vnatk = require('vnatk-express-sequelize');
router.use(require('./middleware/adminTokenChecker'));
const Models = require('../../models');
module.exports = vnatk({
Models: Models,
router: router,
// allow only following models
whitelistmodels:['Products','Cart'],
// do not allow following models
blacklistmodels:['Orders','Payments']
});
- Providing each actions authorization function in model itself
Example
Each action checks for can_{action}
function in model, if found, the function is called by passing request object
. on receiving ===
true only then the related action is executed.
four default actions for basic VES options are vnatk_add
, vnatk_edit
, vnatk_delete
and vnatk_autoimport
. To make authorization related to these actions you may created can_vnatk_add
, can_vnatk_edit
, can_vnatk_delete
and can_vnatk_autoimport
function in models respectiley.
Under development: Authorization and ACL based on each Model or record is under development