Research
Security News
Threat Actor Exposes Playbook for Exploiting npm to Build Blockchain-Powered Botnets
A threat actor's playbook for exploiting the npm ecosystem was exposed on the dark web, detailing how to build a blockchain-powered botnet.
node-for-speed
Advanced tools
Easy API endpoint management
npm install node-for-speed
const express = require('express')
const nfs = require('node-for-speed')
const server = express()
// ...
await nfs(server)
/*
api/
├── v1/
│ ├── route/
│ │ ├── get.js => GET api/v1/route
│ │ └── post.js => POST api/v1/route
│ └── ...
└── ...
*/
const nfs = require('node-for-speed')
// ...
await nfs(server, config)
// OR
const { NodeForSpeed } = require('node-for-speed')
// ...
await NodeForSpeed.load(server, config)
Where config
is an optional parameter to be "assigned" to your main configuration for the given execution.
NodeForSpeed.config({
loader: 'express', // optional
router: 'express', // optional
paths: [
'path/to/routes',
{
path: 'path/to/other/routes',
prefix: 'v1' // optional
}
],
adapter: 'path/to/adapter', // optional
route: 'path/to/route' // optional
})
All paths passed to the config are relative to your project working directory.
loader
(String)Built in server loader, path to your loader or loader module name.
Available loaders: express
Default: express
router
(String)Built in router, path to your router or router module name. See Router for more details.
Available routers: express
Default: null
paths
(String | Object | Array)Paths to directories containing your endpoints as a string, a branch object (cf. example) or an array containing any of the two.
Every string will be converted into branch.
// branch
{
path: 'path/to/your/routes',
prefix: 'v1' // optional
}
adapter
(String)Path to a custom function, object or Adapter class. See Adapter for more details.
route
(String)Path to a custom Route class. See Route for more details.
.node-for-speed
fileIf provided as JSON, the .node-for-speed
file will be loaded automatically as the node-for-speed module is called.
If provided, the "node-for-speed"
property of your package.json file will be automatically loaded as the node-for-speed module is called. The .node-for-speed
file has a higher priority.
The configuration can be auto-loaded from a module on startup using a config property in either of the two previous cases:
{
config: 'path/to/configuration'
}
Then:
module.exports = {
/* your config in js */
}
Endpoints are simple modules named after the method they address:
// ./api/v1/anything/get.js
module.exports = {
path: 'new', // optional
handler: (request, response) => {
/* ... */
}
// OR
handler: [
...middlewares,
(request, response) => {
/* ... */
}
]
}
// with path
// => GET api/v1/anything/new
// without path
// => GET api/v1/anything
Folder names can be overridden using an index.js file (useful for url params):
// ./api/v1/anything/index.js
module.exports = 'something'
// OR
module.exports = {
path: 'something'
}
// will cause the example above to become
// => GET api/v1/something/new
An endpoint can override a folder name using ~ :
// ./api/v1/anything/get.js
module.exports = {
path: '~/brand/new',
handler: (request, response) => {
/* ... */
}
}
// => GET api/v1/brand/new
An endpoint url can be set manually as follow:
// ./api/v1/nested/route/with/a/twist/get.js
module.exports = {
url: 'api/v1/boom',
handler: (request, response) => {
/* ... */
}
}
// => GET api/v1/boom
// instead of
// => GET api/v1/nested/route/with/a/twist
A loader defines how a route is mounted on your server (or router) and delegates the task an adapter if provider.
module.exports = (server, route, adapter, router) => {
/* ... */
}
The Router
class allows you to define:
class Router {
constructor (server, branch) {
/* ... */
}
handler (route) {
/* ... */
}
}
The purpose of the Route
class is to build your endpoints' path and allow you to extend them as shown in example.
class Route {
constructor ({
adapter, // optional
key, // current path section
filepath, // endpoint location
prefix, // optional path prefix
endpoint, // actual endpoint
parent, // parent route
method, // rest method
branch // branch configuration
}) {
/* ... */
}
}
A route has the following properties:
The complete endpoint path.
The endpoint's handler.
The name of the folder containing the endpoint.
The prefix to prepend to the path.
The actual endpoint.
The parent route object.
The rest method addressed (lowercase).
The endpoint file location.
An adapter customizes the way a route is mounted on your server. It is defined as:
class Adapter {
before (server, options) {
/* ... */
}
handler (server, route, router) {
/* ... */
}
after (server, options) {
/* ... */
}
}
before(server, options)
and after(server, options)
are optional methods called respectively pre and post loading.
In this context options
is defined as:
// Given
NodeForSpeed.config(defaults)
// And
NodeForSpeed.load(server, config)
// Then
options = Object.assign({}, defaults, config)
Given the optional nature of before
and after
, adapters can be expressed under any of the following forms:
// as a function
module.exports = (server, route, router) => { /* ... */ }
// as an object
module.exports = {
before: (server, options) => { // optional
/* ... */
},
handler: (server, route, router) => {
/* ... */
},
after: (server, options) => { // optional
/* ... */
}
}
// as a class extending Adapter
module.exports = class CustomAdapter extends Adapter {
/* ... */
}
In this example, we will customize node-for-speed to attach middlewares to our endpoints given the following project structure:
project/
├── ...
├── custom/
├── middlewares/
├── routes/
│ ├── admin/
│ │ └── ...
│ ├── private/
│ │ └── ...
│ └── public/
│ └── ...
├── ...
├── index.js
├── package.json
├── routes.js
└── ...
Endpoints will be written under the form:
const middleware = require('path/to/middleware')
module.exports = {
use: middleware,
// OR
use: [ middleware ],
handler: (request, response) => {
/* ... */
}
}
There is no need to extend the Route class in this example.
But if, for instance, we wanted to define the middlewares by name rather than by actually attaching them to our endpoints, we would write:
const Route = require('node-for-speed/route')
class MiddlewareRoute extends Route {
constructor (args) {
super(args)
const { endpoint } = args
const { use } = endpoint
const middlewares = Array.isArray(use) ? use : [ use ]
this.use = middlewares.map(this.getMiddleware)
}
getMiddleware (name) {
/* ... */
}
}
module.exports = MiddlewareRoute
Our endpoints would then become:
module.exports = {
use: 'middleware',
// OR
use: [ 'middleware' ],
handler: (request, response) => {
/* ... */
}
}
As we want apply prefix and middlewares at a branch level, we will have the following Router:
const ExpressRouter = require('node-for-speed/router/express')
class MiddlewareRouter extends ExpressRouter {
init (server, router, branch = {}) {
const {
prefix = '',
use
} = branch
if (use instanceof Function || use instanceof Array) {
server.use(prefix, use, router)
}
else {
server.use(prefix, router)
}
}
handler (route) {
const { router } = this
const { path, method, handler, parent, endpoint } = route
const middlewares = []
// get index middlewares
const indexwares = this.getMiddlewares(parent.endpoint)
// get the method middlewares
const methodwares = this.getMiddlewares(endpoint)
if (indexwares.length) {
middlewares.push(...indexwares)
}
if (methodwares.length) {
middlewares.push(...methodwares)
}
if (middlewares.length) {
router[ method ](path, middlewares, handler)
}
else {
router[ method ](path, handler)
}
}
getMiddlewares ({ use } = {}) {
const middlewares = []
if (use instanceof Function) {
middlewares.push(use)
}
else if (use instanceof Array) {
middlewares.push(...use)
}
return middlewares
}
}
module.exports = MiddlewareRouter
In the scenario exposed in the Route section, we would have passed route
and parent
to getMiddlewares
rather than the endpoints.
Let's add error handlers to our server:
module.exports = {
after: server => {
// 404 handler
server.use((request, response, next) => {
response.status(404).send('Page not found')
})
// error handler
server.use((err, request, response, next) => {
/* ... */
response.status(500).send('Something went wrong...')
})
}
}
{
// ...
"node-for-speed": { config: "./routes.js" }
// ...
}
We load the configuration through a module to import middlewares.
const isAuthenticated = require('./middlewares/authenticated')
const isAdmin = require('./middlewares/admin')
module.exports = {
adapter: './custom/adapter',
router: './custom/router',
paths: [
{
path: './public'
},
{
path: './private',
use: isAuthenticated
},
{
path: './admin',
prefix: '/admin',
use: [ isAuthenticated, isAdmin ]
}
]
}
const express = require('express')
const nfs = require('node-for-speed')
const app = express()
/* ... */
nfs(app).then(() => app.listen(3000))
/* ... */
// ./api/v1/anything/rest.js
module.exports = {
index (params) { // GET api/v1/anything
},
get (id, params) { // GET api/v1/anything/:id
},
post (id, data, params) { // POST api/v1/anything/:id
},
put (id, data, params) { // PUT api/v1/anything/:id
},
patch (id, data, params) { // PATCH api/v1/anything/:id
},
delete (id, data, params) { // DELETE api/v1/anything/:id
},
procedure (id, data, params) { // POST api/v1/anything/:id/procedure
}
}
FAQs
Easy API endpoint management
The npm package node-for-speed receives a total of 0 weekly downloads. As such, node-for-speed popularity was classified as not popular.
We found that node-for-speed 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.
Research
Security News
A threat actor's playbook for exploiting the npm ecosystem was exposed on the dark web, detailing how to build a blockchain-powered botnet.
Security News
NVD’s backlog surpasses 20,000 CVEs as analysis slows and NIST announces new system updates to address ongoing delays.
Security News
Research
A malicious npm package disguised as a WhatsApp client is exploiting authentication flows with a remote kill switch to exfiltrate data and destroy files.