
Security News
The Hidden Blast Radius of the Axios Compromise
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.
apiextender
Advanced tools
This module deals with to extend an API backend that adds a specific feature to an existing API as plugin(add-in, addin, add-on, addon). apiextender let to enable third-party developers to create abilities which extend an application and supports the a
This module allows to extend an API backend, by adding endpoints or modifying existing endpoints' behaviour. This is accomplished in a plug-in fashion. With apiextender you can :
Install apiextender in your project by typing:
$ npm install apiextender
This is an Express module for nodeJs. This section explains how to use it in your code to make your API extensible by plugin.
Just require it:
var apiextender = require('apiextender');
var express=require('express');
var apiextender = require('apiextender');
var app=express();
// make your API extensible by plugin techniques in a simple and fast
// and with one line of code.
apiextender.extend(app); // now your API is exensible
Plugin functions that extends your API must be defined in a file called extend.js,
located in a folder named plugin in the home directory of your application.
To create folder type:
$ mkdir plugin
To create extend.js type:
$ cd plugin
$ vi extend.js
extend.js contains an array of plugin functions. Now we initialize it as an empty plugin function container:
var plugins=[];
module.exports = plugins;
To extend an API endpoint, you must populate the plugins array containing all functions extending the API.
var plugins=[];
module.exports = plugins;
plugins=[] is an array of objects , which are functions that constitutes a plugin. Each function is defined as:
{
"resource":"/resourceToExtend",
"method":"GET",
"mode":"override",
"params":[query],
"extender": function(req,content,cType,callback){
callback(null,{"Content extension"});
}
}
where:
override, before, after, before_after. In detail:
req object that must be passed to the plugin function in reqParams paramfunction(reqParams,content,contentType,callback)
params field.
E.g. if params=["query"], reqParams contains the object {query:req.query}mode param is set to after or before_after.override or beforecontent, e.g. application/json , text/html...override or beforeerror and newContent, defined as:callback(error,newContent)
override, after or before_after
(for the latter, only for what is executed in the after part). before or before_after
(for the latter, only for what is executed in the before part), it is an
object whose keys are appended to Express' req .#### Warning:
If mode is set to before_after, it is mandatory to declare in extender param two functions,
both for the before and after actions.
So the extender parameter is not a function but an object containing two keys:
before actionsafter actions######Example
{
//....
//....
"mode":"before_after"
"extender":{
"before": function(req,content,cType,callback){
// before logic
callback(null,{"Content extension before"});
},
"after": function(req,content,cType,callback){
// after logic
callback(null,{"Content extension after"});
}
}
}
######Example of extend.js plugin definition
var plugins=[
{
"resource":"/resourceToExtend",
"method":"GET",
"mode":"override",
"params":[query],
"extender": function(req,content,cType,callback){
callback(null,{"Content extension"});
}
},
{
"resource":"/OtherResourceToExtend",
"method":"GET",
"mode":"before",
"params":[query],
"extender": function(req,content,cType,callback){
callback(null,{"Content extension"});
}
}
]
extend(app)Function that extends the API. The param app is the application that you want extend.
install(app,extender,save)Function that extends an API at runtime, without stopping and restarting your application.
app is the application that you want extendextender is the plugin function described in section plugin extender structuresave if true, the plugin is saved in the extend.js file, being appended in the plugin array and becoming permanent.######Example:
var express=require('express');
var apiextender = require('apiextender');
var app=express();
apiextender.extend(app); // now your API is extensible
// Define an endpoint wrapping apiextender install function that lets you to extend API on the fly
// The access to this endpoint should be protectd with token privileges
app.post("/installPlugin",function(req,res,next){
// check for tokens
//.....
// install and run the plugin
apiextender.install(app,req.body.pluginExtender,req.body.save || false);
res.send({"status":"installed"});
});
ExamplesExamples: How to set an API extensible by pluginsFrom your application home directory type:
$ cd /Your_App_Home
$ npm install apiextender // install apiextender
$ mkdir plugin // Create plugin container folder
$ cd plugin // go into plugin folder
$ vi extend.js // Create plugin container file
Insert this content in extend.js.
var plugins=[];
module.exports = plugins;
Include the apiextender module in app.js
var express=require('express');
var apiextender = require('apiextender');
var app=express();
apiextender.extend(app);
Examples: How to extend an APISuppose we want to extend this API:
var express=require('express');
var apiextender = require('apiextender');
var app=express();
apiextender.extend(app); // now your API is exensible
app.get('/overrideOriginal', function(req, res){
res.send({"response":"override"});
});
app.get('/beforeOriginal', function(req, res){
var params=req.optionalParams || null;
var response = params!=null ? {"response":"before", "response_before":params} : {"response":"before"}
res.send(response);
});
app.get('/afterOriginal', function(req, res){
res.send({"response":"after"});
});
app.get('/before_afterOriginal', function(req, res){
var params=req.optionalParams || null;
var response = params!=null ? {"response":"before_after", "response_before":params} : {"response":"before_after"}
res.send(response);
});
Override modeWith no plugin function defined, the endpoint response is:
$ curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://hostname/overrideOriginal
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 23
ETag: "35-6BXjKyRXlm+rSEU9a23z/g"
Date: Fri, 11 Nov 2016 13:16:44 GMT
Connection: keep-alive
{"response":"override"} // original response because no extension function
$
Now we extend "/overrideOriginal" endpoint with a plugin, writing a plugin function in extend.js
var plugins=[
{
"resource":"/overrideOriginal", // extend overrideOriginal endpoint
"method":"GET", // extend overrideOriginal endpoint in get method
"mode":"override", // endpoint overrideOriginal must be overrided
"params":[query], // express request "req.query" should be throw to extender function
"extender": function(requestParams,content,cType,callback){ // this is the extender Function definition
// the mode is set to "override" so "content,cType" are both null
var username=requestParams.username || ""; // if username exist is set otherwise use a void string
callback(null,{"response":"Hello " + username + " this is a plugin function that override"});
// ^
// |
// No Error
}
}
];
module.exports = plugins;
Restart your application (or invoke apiextender.install) to apply the plugin function.
If you curl the endpoint, you can notice that the original endpoint is not executed, being overridden by the plugin function:
$ curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://hostname/overrideOriginal
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 60
ETag: "35-6BXjKyRXlm+rSEU9a23z/g"
Date: Fri, 11 Nov 2016 13:16:44 GMT
Connection: keep-alive
{"response":"Hello this is a plugin function that ovveride"} // original response "{"response":"before"}"
// overrided by extension function
$
Before modeWith no plugin function defined, the endpoint response is:
$ curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://hostname/beforeOriginal
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 51
ETag: "35-6BXjKyRXlm+rSEU9a23z/g"
Date: Fri, 11 Nov 2016 13:16:44 GMT
Connection: keep-alive
{"response":"before"} // original response because no extension function
Now we extend "/beforeOriginal" endpoint with a plugin, writing a plugin function in extend.js
var plugins=[
{
"resource":"/beforeOriginal", // extend beforeOriginal endpoint
"method":"GET", // extend beforeOriginal endpoint in get method
"mode":"before", // plugin function must be executed before original endpoint beforeOriginal
"params":[query], // express request "req.query" should be throw to extender function
"extender": function(requestParams,content,cType,callback){ // this is the extender Function definition
// the mode is set to "before" so "content,cType" are both null
var username=requestParams.username || ""; // if username exist is set otherwise use a void string
callback(null,{"optionalParams":"Hello " + username + " this is a plugin function that extend"});
// ^
// |
// No Error
}
}
];
module.exports = plugins;
Restart your application (or invoke apiextender.install) to apply the plugin function.
If you curl the endpoint, you can notice that the original endpoint is extended by the plugin function:
$ curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://hostname/beforeOriginal?username=Alex
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 90
ETag: "35-6BXjKyRXlm+rSEU9a23z/g"
Date: Fri, 11 Nov 2016 13:16:44 GMT
Connection: keep-alive
{"response":"before","response_before":"Hello Alex this is a plugin function that extend"} // original and extended response
After modeWith no plugin function defined, the endpoint response is:
$ curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://hostname/afterOriginal
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 20
ETag: "35-6BXjKyRXlm+rSEU9a23z/g"
Date: Fri, 11 Nov 2016 13:16:44 GMT
Connection: keep-alive
{"response":"after"} // original response because no extension function
$ curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://hostname/afterOriginal?username=Alex
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 20
ETag: "35-6BXjKyRXlm+rSEU9a23z/g"
Date: Fri, 11 Nov 2016 13:16:44 GMT
Connection: keep-alive
{"response":"after"} // original response because no extension function
Now we extend "/afterOriginal" endpoint with a plugin, writing a plugin function in extend.js
var plugins=[
{
"resource":"/afterOriginal", // extend afterOriginal endpoint
"method":"GET", // extend afterOriginal endpoint in get method
"mode":"after", // plugin function must be executed after original endpoint afterOriginal
"params":[query], // express request "req.query" should be throw to extender function
"extender": function(requestParams,content,cType,callback){ // this is the extender Function definition
// the mode is set to "after" so "content,cType" are both not null
if(cType==="application/json"){ // if content is a Json
var username=requestParams.username || ""; // if username exist is set otherwise use a void string
content.after_response="Hello " + username + " this is a plugin function that extend";
}
callback(null,content);
// ^
// |
// No Error
}
}
];
module.exports = plugins;
Restart your application (or invoke apiextender.install) to apply the plugin function.
If you curl the endpoint, you can notice that the original endpoint is extended by the plugin function:
$ curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://hostname/afterOriginal
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 82
ETag: "35-6BXjKyRXlm+rSEU9a23z/g"
Date: Fri, 11 Nov 2016 13:16:44 GMT
Connection: keep-alive
{"response":"after","after_response":Hello this is a plugin function that extend"} // original response extended
$ curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://hostname/afterOriginal?username=Alex
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 87
ETag: "35-6BXjKyRXlm+rSEU9a23z/g"
Date: Fri, 11 Nov 2016 13:16:44 GMT
Connection: keep-alive
{"response":"after","after_response":Hello Alex this is a plugin function that extend"} // original response extended
Examples: before_after modeWith no plugin function defined, the endpoint response is:
$ curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://hostname/before_afterOriginal
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 27
ETag: "35-6BXjKyRXlm+rSEU9a23z/g"
Date: Fri, 11 Nov 2016 13:16:44 GMT
Connection: keep-alive
{"response":"before_after"} // original response because no extension function
$ curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://hostname/before_afterOriginal?username=Alex
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 27
ETag: "35-6BXjKyRXlm+rSEU9a23z/g"
Date: Fri, 11 Nov 2016 13:16:44 GMT
Connection: keep-alive
{"response":"before_after"} // original response because no extension function
Now we extend "/before_afterOriginal" endpoint with a plugin, writing a plugin function in extend.js
var plugins=[
{
"resource":"/before_afterOriginal", // extend before_afterOriginal endpoint
"method":"GET", // extend before_afterOriginal endpoint in get method
"mode":"before_after", // plugin function must be executed before and after original endpoint before_afterOriginal
"params":[query], // express request "req.query" should be throw to extender function
"extender":{
"before": function(requestParams,content,cType,callback){ // this is the extender Function definition
// the mode is set to "before_after" so in before function "content,cType" are both null
var username=requestParams.username || ""; // if username exist is set otherwise use a void string
callback(null,{"optionalParams":"Hello " + username + " this is a plugin function that extend"});
// ^
// |
// No Error
},
"after": function(requestParams,content,cType,callback){ // this is the extender Function definition
// the mode is set to "before _after" so in after function "content,cType" are both not null
if(cType==="application/json"){ // if content is a Json
var username=requestParams.username || ""; // if username exist is set otherwise use a void string
content.after_response="Hello " + username + " this is a plugin function that extend";
}
callback(null,content);
// ^
// |
// No Error
}
}
];
module.exports = plugins;
Restart your application (or invoke apiextender.install) to apply the plugin function.
If you curl the endpoint, you can notice that the original endpoint is extended by the plugin function:
$ curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://hostname/before_afterOriginal
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 154
ETag: "35-6BXjKyRXlm+rSEU9a23z/g"
Date: Fri, 11 Nov 2016 13:16:44 GMT
Connection: keep-alive
{
"response":"before_after",
"response_before":"Hello this is a plugin function that extend", // original and extended response
"response_after":"Hello this is a plugin function that extend"
}
$ curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://hostname/before_afterOriginal?username=Alex
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 164
ETag: "35-6BXjKyRXlm+rSEU9a23z/g"
Date: Fri, 11 Nov 2016 13:16:44 GMT
Connection: keep-alive
{
"response":"before_after",
"response_before":"Hello Alex this is a plugin function that extend", // original and extended response
"response_after":"Hello Alex this is a plugin function that extend"
}
Error throwingWith no plugin function defined, the endpoint response is:
$ curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://hostname/beforeOriginal
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 51
ETag: "35-6BXjKyRXlm+rSEU9a23z/g"
Date: Fri, 11 Nov 2016 13:16:44 GMT
Connection: keep-alive
{"response":"before"} // original response because no extension function
$ // now with username param (no response changes)
$ curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://hostname/beforeOriginal?username=Alex
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 51
ETag: "35-6BXjKyRXlm+rSEU9a23z/g"
Date: Fri, 11 Nov 2016 13:16:44 GMT
Connection: keep-alive
{"response":"before"} // original response because no extension function
Now we extend "/beforeOriginal" endpoint with a plugin, writing a plugin function in extend.js. Starting from the
example Examples:before mode, we edit the plugin function to throw an error if no username field is sent.
var plugins=[
{
"resource":"/beforeOriginal", // extend beforeOriginal endpoint
"method":"GET", // extend beforeOriginal endpoint in get method
"mode":"before", // endpoint beforeOriginal must be overrided
"params":[query], // express request "req.query" should be throw to extender function
"extender": function(requestParams,content,cType,callback){ // this is the extender Function definition
// the mode is set to "override" so "content,cType" are both null
var username=requestParams.username || null; // if username exist is set otherwise use a void string
if(!username)
callback({"error_code":"400", "error_message":"no username field"},null);
else
callback(null,{"response":"Hello " + username + " this is a plugin function that override"});
// ^
// |
// No Error
}
}
];
module.exports = plugins;
Restart your application (or invoke apiextender.install) to apply the plugin function.
If you curl the endpoint, you can notice that the original endpoint is not executed after the plugin function,
because no username field is sent. This is due to the fact that before extension function stops the execution
with an error message to the apiextender callback:
$ curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://hostname/beforeOriginal
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 37
ETag: "35-6BXjKyRXlm+rSEU9a23z/g"
Date: Fri, 11 Nov 2016 13:16:44 GMT
Connection: keep-alive
{"error_message":"no username field"} // only error_message from extended function response
$
$ curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://hostname/beforeOriginal?username=Alex
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 90
ETag: "35-6BXjKyRXlm+rSEU9a23z/g"
Date: Fri, 11 Nov 2016 13:16:44 GMT
Connection: keep-alive
{"response":"before","response_before":"Hello Alex this is a plugin function that extend"} // original and extended response
Examples: A Complete Eexample of plugin extensionWith no plugin function defined, the endpoint response is:
$ curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://hostname/overrideOriginal?username=Alex
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 23
ETag: "35-6BXjKyRXlm+rSEU9a23z/g"
Date: Fri, 11 Nov 2016 13:16:44 GMT
Connection: keep-alive
{"response":"override"} // original response because no extension function
$
$ curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://hostname/beforeOriginal?username=Alex
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 21
ETag: "35-6BXjKyRXlm+rSEU9a23z/g"
Date: Fri, 11 Nov 2016 13:16:44 GMT
Connection: keep-alive
{"response":"before"} // original response because no extension function
$
$ curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://hostname/afterOriginal?username=Alex
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 20
ETag: "35-6BXjKyRXlm+rSEU9a23z/g"
Date: Fri, 11 Nov 2016 13:16:44 GMT
Connection: keep-alive
{"response":"after"} // original response because no extension function
$
$ curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://hostname/before_afterOriginal?username=Alex
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 27
ETag: "35-6BXjKyRXlm+rSEU9a23z/g"
Date: Fri, 11 Nov 2016 13:16:44 GMT
Connection: keep-alive
{"response":"before_after"} // original response because no extension function
Now we extend "/....Original" endpoint with a plugin, writing a plugin function in extend.js.
var plugins=[
{
"resource":"/overrideOriginal", // extend overrideOriginal endpoint
"method":"GET", // extend overrideOriginal endpoint in get method
"mode":"override", // endpoint overrideOriginal must be overrided
"params":[query], // express request "req.query" should be throw to extender function
"extender": function(requestParams,content,cType,callback){ // this is the extender Function definition
// the mode is set to "override" so "content,cType" are both null
var username=requestParams.username || ""; // if username exist is set otherwise use a void string
callback(null,{"response":"Hello " + username + " this is a plugin function that override"});
// ^
// |
// No Error
}
},
{
"resource":"/overrideOriginal", // extend overrideOriginal endpoint
"method":"GET", // extend overrideOriginal endpoint in get method
"mode":"before", // endpoint overrideOriginal must be overrided
"params":[query], // express request "req.query" should be throw to extender function
"extender": function(requestParams,content,cType,callback){ // this is the extender Function definition
// the mode is set to "override" so "content,cType" are both null
var username=requestParams.username || null; // if username exist is set otherwise use a void string
if(!username)
callback({"error_code":"400", "error_message":"no username field"},null);
else
callback(null,{"response":"Hello " + username + " this is a plugin function that override"});
// ^
// |
// No Error
}
},
{
"resource":"/afterOriginal", // extend afterOriginal endpoint
"method":"GET", // extend afterOriginal endpoint in get method
"mode":"after", // plugin function must be executed after original endpoint afterOriginal
"params":[query], // express request "req.query" should be throw to extender function
"extender": function(requestParams,content,cType,callback){ // this is the extender Function definition
// the mode is set to "after" so "content,cType" are both not null
if(cType==="application/json"){ // if content is a Json
var username=requestParams.username || ""; // if username exist is set otherwise use a void string
content.after_response="Hello " + username + " this is a plugin function that extend";
}
callback(null,content);
// ^
// |
// No Error
}
},
{
"resource":"/before_afterOriginal", // extend before_afterOriginal endpoint
"method":"GET", // extend before_afterOriginal endpoint in get method
"mode":"before_after", // plugin function must be executed before and after original endpoint before_afterOriginal
"params":[query], // express request "req.query" should be throw to extender function
"extender":{
"before": function(requestParams,content,cType,callback){ // this is the extender Function definition
// the mode is set to "before_after" so in before function "content,cType" are both null
var username=requestParams.username || ""; // if username exist is set otherwise use a void string
callback(null,{"optionalParams":"Hello " + username + " this is a plugin function that extend"});
// ^
// |
// No Error
},
"after": function(requestParams,content,cType,callback){ // this is the extender Function definition
// the mode is set to "before _after" so in after function "content,cType" are both not null
if(cType==="application/json"){ // if content is a Json
var username=requestParams.username || ""; // if username exist is set otherwise use a void string
content.after_response="Hello " + username + " this is a plugin function that extend";
}
callback(null,content);
// ^
// |
// No Error
}
}
];
module.exports = plugins;
Restart your application (or invoke apiextender.install) to apply the plugin function.
If you curl the endpoint, you can notice that the original endpoint is extended by the plugin function:
$ curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://hostname/overrideOriginal?username=Alex
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 65
ETag: "35-6BXjKyRXlm+rSEU9a23z/g"
Date: Fri, 11 Nov 2016 13:16:44 GMT
Connection: keep-alive
{"response":"Hello Alex this is a plugin function that ovveride"} // original response "{"response":"before"}"
// overrided by extension function
$
$ curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://hostname/beforeOriginal?username=Alex
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 90
ETag: "35-6BXjKyRXlm+rSEU9a23z/g"
Date: Fri, 11 Nov 2016 13:16:44 GMT
Connection: keep-alive
{"response":"before","response_before":"Hello Alex this is a plugin function that extend"} // original and extended response
$
$ curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://hostname/afterOriginal?username=Alex
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 88
ETag: "35-6BXjKyRXlm+rSEU9a23z/g"
Date: Fri, 11 Nov 2016 13:16:44 GMT
Connection: keep-alive
{"response":"after","after_response":Hello Alex this is a plugin function that extend"} // original response extended
$
$ curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://hostname/before_afterOriginal?username=Alex
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 165
ETag: "35-6BXjKyRXlm+rSEU9a23z/g"
Date: Fri, 11 Nov 2016 13:16:44 GMT
Connection: keep-alive
{
"response":"before_after",
"response_before":"Hello Alex this is a plugin function that extend", // original and extended response
"response_after":"Hello Alex this is a plugin function that extend"
}
Extend API on the fly at runtimeTo extend an API on the fly as described in reference section install(app,extender,save), we need to define an endpoint that wraps apiextender install function. Add these code lines to you app.js:
var express=require('express');
var apiextender = require('apiextender');
var app=express();
// .....
// Old app.js logic
// .....
// Define an endpoint that wrap apiextender install function that lets you to extend API on the fly
// The access to this endpoint should be protectd with token privileges
app.post("/installPlugin",function(req,res,next){
// check for tokens
//.....
apiextender.install(app,req.body.pluginExtender,req.body.save || false);
res.send({"status":"installed"});
});
With no plugin function defined, the endpoint response is:
$ curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://hostname/overrideOriginal?username=Alex
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 23
ETag: "35-6BXjKyRXlm+rSEU9a23z/g"
Date: Fri, 11 Nov 2016 13:16:44 GMT
Connection: keep-alive
{"response":"override"} // original response because no extension function
Now we extend "/overrideOriginal" endpoint with a plugin, installed on the fly without defining it in extend.js.
To install, just call /installPlugin in POST:
EXTENDER='{
"pluginExtender":{
"resource":"/overrideOriginal", // extend overrideOriginal endpoint
"method":"GET", // extend overrideOriginal endpoint in get method
"mode":"override", // endpoint overrideOriginal must be overrided
"params":[query], // express request "req.query" should be throw to extender function
"extender": function(requestParams,content,cType,callback){ // this is the extender Function definition
// the mode is set to "override" so "content,cType" are both null
var username=requestParams.username || ""; // if username exist is set otherwise use a void string
callback(null,{"response":"Hello " + username + " this is a plugin function that override"});
// ^
// |
// No Error
}
},
"save":false; // not save extenson plugin
}'
$
$ curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X POST http://hostname/overrideOriginal?username=Alex
-d $EXTENDER
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 22
ETag: "35-6BXjKyRXlm+rSEU9a23z/g"
Date: Fri, 11 Nov 2016 13:16:44 GMT
Connection: keep-alive
{"status":"installed"} // plugin extension installed
Restart your application (or invoke apiextender.install) to apply the plugin function.
Without restarting your application, if you curl the endpoint, you can notice that the original endpoint is extended by the plugin function:
$ curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET http://hostname/overrideOriginal?username=Alex
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 65
ETag: "35-6BXjKyRXlm+rSEU9a23z/g"
Date: Fri, 11 Nov 2016 13:16:44 GMT
Connection: keep-alive
{"response":"Hello Alex this is a plugin function that ovveride"} // original response "{"response":"before"}"
// overrided by extension function
$
MIT License
Copyright (c) 2016 aromanino
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
CRS4 Microservice Core Team (cmc.smartenv@crs4.it)
Alessandro Romanino (a.romanino@gmail.com)
Guido Porruvecchio (guido.porruvecchio@gmail.com)
FAQs
This module deals with to extend an API backend that adds a specific feature to an existing API as plugin(add-in, addin, add-on, addon). apiextender let to enable third-party developers to create abilities which extend an application and supports the a
We found that apiextender demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.

Research
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.

Research
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.