Node For Speed
Easy API endpoint management
Getting started
npm install node-for-speed
const express = const nfs = const server = // ... await /*api/├── v1/│ ├── route/│ │ ├── get.js => GET api/v1/route│ │ └── post.js => POST api/v1/route│ └── ...└── ... */
Usage
const nfs = // ...await // OR const NodeForSpeed = // ...await NodeForSpeed
Where config
is an optional parameter to be "assigned" to your main configuration for the given execution.
Configuration
programmatic
NodeForSpeed
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
file
If provided as JSON, the .node-for-speed
file will be loaded automatically as the node-for-speed module is called.
package.json
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.
as module
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:
moduleexports = /* your config in js */
Endpoint
Endpoints are simple modules named after the method they address:
// ./api/v1/anything/get.js moduleexports = path: 'new' // optional { /* ... */ } // OR handler: ...middlewares { /* ... */ } // 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 moduleexports = 'something' // OR moduleexports = 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 moduleexports = path: '~/brand/new' { /* ... */ } // => GET api/v1/brand/new
An endpoint url can be set manually as follow:
// ./api/v1/nested/route/with/a/twist/get.js moduleexports = url: 'api/v1/boom' { /* ... */ } // => GET api/v1/boom// instead of// => GET api/v1/nested/route/with/a/twist
Customization
Loader
A loader defines how a route is mounted on your server (or router) and delegates the task an adapter if provider.
module { /* ... */}
Router
The Router
class allows you to define:
- how a router is built based on your configuration
- how a router is attached to your server
- how a route is mounted
{ /* ... */ } { /* ... */ }
Route
The purpose of the Route
class is to build your endpoints' path and allow you to extend them as shown in example.
{ /* ... */ }
A route has the following properties:
path
The complete endpoint path.
handler
The endpoint's handler.
key
The name of the folder containing the endpoint.
prefix
The prefix to prepend to the path.
endpoint
The actual endpoint.
parent
The parent route object.
method
The rest method addressed (lowercase).
filepath
The endpoint file location.
Adapter
An adapter customizes the way a route is mounted on your server. It is defined as:
{ /* ... */ } { /* ... */ } { /* ... */ }
before(server, options)
and after(server, options)
are optional methods called respectively pre and post loading.
In this context options
is defined as:
// GivenNodeForSpeed// AndNodeForSpeed// Thenoptions = Object
Given the optional nature of before
and after
, adapters can be expressed under any of the following forms:
// as a functionmodule { /* ... */ }
// as an objectmoduleexports = { // optional /* ... */ } { /* ... */ } { // optional /* ... */ }
// as a class extending Adaptermoduleexports = /* ... */
Example
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
└── ...
Endpoint
Endpoints will be written under the form:
const middleware = moduleexports = use: middleware // OR use: middleware { /* ... */ }
Route
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 = { superargs const endpoint = args const use = endpoint const middlewares = Array ? use : use thisuse = middlewares } { /* ... */ } moduleexports = MiddlewareRoute
Our endpoints would then become:
moduleexports = use: 'middleware' // OR use: 'middleware' { /* ... */ }
Router
As we want apply prefix and middlewares at a branch level, we will have the following Router:
const ExpressRouter = { const prefix = '' use } = branch if use instanceof Function || use instanceof Array server else server { const router = this const path method handler parent endpoint = route const middlewares = // get index middlewares const indexwares = this // get the method middlewares const methodwares = this if indexwareslength middlewares if methodwareslength middlewares if middlewareslength router method path middlewares handler else router method path handler } { const middlewares = if use instanceof Function middlewares else if use instanceof Array middlewares return middlewares }} moduleexports = MiddlewareRouter
In the scenario exposed in the Route section, we would have passed route
and parent
to getMiddlewares
rather than the endpoints.
Adapter
Let's add error handlers to our server:
moduleexports = { // 404 handler server // error handler server }
Configuration
package.json
// ... "node-for-speed": config: "./routes.js" // ...
We load the configuration through a module to import middlewares.
routes.js
const isAuthenticated = const isAdmin = moduleexports = adapter: './custom/adapter' router: './custom/router' paths: path: './public' path: './private' use: isAuthenticated path: './admin' prefix: '/admin' use: isAuthenticated isAdmin
index.js
const express = const nfs = const app = /* ... */ /* ... */
Roadmap
In progress
- code sample
- document branch as a module
- document branch handlers (middlewares)
- openapi path parameters
- swagger generated API documentation
Planned
- static endpoints (e.g. routes/404.html)
- document custom endpoint filenames
- Built-in loaders: koa, hapi
- rest file
// ./api/v1/anything/rest.js moduleexports = { // GET api/v1/anything } // GET api/v1/anything/:id { // POST api/v1/anything/:id } { // PUT api/v1/anything/:id } { // PATCH api/v1/anything/:id } { // DELETE api/v1/anything/:id } { // POST api/v1/anything/:id/procedure }