Comparing version 0.1.0-alpha.0 to 0.2.0
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const timers_1 = require("timers"); | ||
// import * as createDebugger from 'debug' | ||
const TreeRouter = require("find-my-way"); | ||
const dispatcher_1 = require("./dispatcher"); | ||
const createDebugger = require("debug"); | ||
const aldo_http_1 = require("aldo-http"); | ||
const debug = createDebugger('aldo:application'); | ||
/** | ||
* A global facade to manage routes, error handlers | ||
* | ||
* @class Application | ||
* A global facade to manage routes, error handlers, dispatching, etc... | ||
*/ | ||
class Application { | ||
constructor() { | ||
this._context = { app: this }; | ||
this._namedRoutes = new Map(); | ||
this._finally = _respond; | ||
this._catchers = []; | ||
this._posts = []; | ||
this._pres = []; | ||
this._tree = new TreeRouter(); | ||
this._routes = []; | ||
this._preHandlers = []; | ||
this._postHandlers = []; | ||
this._dispatcher = new dispatcher_1.default(_respond); | ||
this._context = Object.create(null); | ||
} | ||
/** | ||
* Add before route middleware | ||
* Add before route handler | ||
* | ||
* @param {Function} fn | ||
* @returns {Application} | ||
* @param fns | ||
*/ | ||
pre(fn) { | ||
this._pres.push(_ensureFunction(fn)); | ||
pre(...fns) { | ||
for (let fn of fns) { | ||
this._preHandlers.push(_ensureFunction(fn)); | ||
debug(`use pre handler: ${fn.name || '<anonymous>'}`); | ||
} | ||
return this; | ||
} | ||
/** | ||
* Add after route middleware | ||
* Add after route handler | ||
* | ||
* @param {Function} fn | ||
* @returns {Application} | ||
* @param fns | ||
*/ | ||
post(fn) { | ||
this._posts.push(_ensureFunction(fn)); | ||
post(...fns) { | ||
for (let fn of fns) { | ||
this._postHandlers.push(_ensureFunction(fn)); | ||
debug(`use post handler: ${fn.name || '<anonymous>'}`); | ||
} | ||
return this; | ||
} | ||
/** | ||
* Add error middleware | ||
* Add an error handler | ||
* | ||
* @param {Function} fn | ||
* @returns {Application} | ||
* @param fns | ||
*/ | ||
catch(fn) { | ||
this._catchers.push(_ensureFunction(fn)); | ||
catch(...fns) { | ||
for (let fn of fns) { | ||
this._dispatcher.onError(_ensureFunction(fn)); | ||
debug(`use error handler: ${fn.name || '<anonymous>'}`); | ||
} | ||
return this; | ||
@@ -55,23 +57,18 @@ } | ||
* | ||
* @param {Function} fn | ||
* @returns {Application} | ||
* @param fn final request handler | ||
*/ | ||
finally(fn) { | ||
this._finally = _ensureFunction(fn); | ||
this._dispatcher.onFinished(_ensureFunction(fn)); | ||
debug(`use final handler: ${fn.name || '<anonymous>'}`); | ||
return this; | ||
} | ||
/** | ||
* Add router's routes into the tree | ||
* Register router's routes | ||
* | ||
* @param {Router} router | ||
* @returns {Application} | ||
* @param routers | ||
*/ | ||
use(router) { | ||
for (let route of router.routes()) { | ||
for (let [method, fns] of route.handlers()) { | ||
this._tree.on(method, route.path, this._compose(fns)); | ||
} | ||
// register named route | ||
if (route.name) | ||
this._namedRoutes.set(route.name, route); | ||
use(...routers) { | ||
for (let router of routers) { | ||
this._routes.push(...router.routes()); | ||
debug('use routes'); | ||
} | ||
@@ -81,57 +78,64 @@ return this; | ||
/** | ||
* Dispatch the request/response to the matched route handler | ||
* | ||
* @param {Request} request | ||
* @param {Response} response | ||
* Return a request handler callback | ||
*/ | ||
dispatch(request, response) { | ||
var { method, url } = request; | ||
var found = this._tree.find(method, url); | ||
var ctx = this._makeContext(request, response); | ||
// debug(`dispatch ${method} ${url}`) | ||
// 404 | ||
if (!found) { | ||
let err = _notFoundError(url); | ||
this._loopError(err, ctx); | ||
return; | ||
} | ||
// add url params to the context | ||
ctx.params = found.params || {}; | ||
// invoke the route handler | ||
found.handler(ctx); | ||
callback() { | ||
this._registerRoutes(); | ||
return (request, response) => { | ||
debug(`dispatching: ${request.method} ${request.url}`); | ||
this._dispatcher.dispatch(this.makeContext(request, response)); | ||
}; | ||
} | ||
async start(arg, options = {}) { | ||
var server = this._server = aldo_http_1.createServer(options, this.callback()); | ||
if (typeof arg === 'number') | ||
arg = { port: arg }; | ||
// listen | ||
await server.start(arg); | ||
debug(`app started with %o`, arg); | ||
return server; | ||
} | ||
/** | ||
* Create a HTTP server and pass the arguments to `listen` method | ||
* Stop listening for requests | ||
*/ | ||
async stop() { | ||
var server = this._server; | ||
await server.stop(); | ||
debug(`app stopped`); | ||
return server; | ||
} | ||
/** | ||
* Extend the app context by adding per instance property | ||
* | ||
* @param {Any...} args | ||
* @returns {Server} | ||
* @param prop | ||
* @param fn | ||
*/ | ||
serve(...args) { | ||
return aldo_http_1.createServer(this.dispatch.bind(this)).listen(...args); | ||
bind(prop, fn) { | ||
_ensureFunction(fn); | ||
var field = `_${prop}`; | ||
Reflect.defineProperty(this._context, prop, { | ||
configurable: true, | ||
enumerable: true, | ||
get() { | ||
if (this[field] === undefined) { | ||
// private property | ||
Reflect.defineProperty(this, field, { | ||
value: fn(this) | ||
}); | ||
} | ||
return this[field]; | ||
} | ||
}); | ||
return this; | ||
} | ||
/** | ||
* Extend the app context by adding more properties | ||
* Extend the app context by adding shared properties | ||
* | ||
* @param {String} prop | ||
* @param {Any} value | ||
* @returns {Application} | ||
* @param prop | ||
* @param value | ||
*/ | ||
set(prop, value) { | ||
var descriptor = { | ||
configurable: true, | ||
enumerable: true | ||
}; | ||
// factory | ||
if (typeof value === 'function') { | ||
let fn = value; | ||
let field = `_${prop}`; | ||
descriptor.get = function _get() { | ||
return this[field] || (this[field] = fn(this)); | ||
}; | ||
return this.bind(prop, value); | ||
} | ||
else { | ||
descriptor.value = value; | ||
} | ||
// define | ||
Object.defineProperty(this._context, prop, descriptor); | ||
this._context[prop] = value; | ||
return this; | ||
@@ -142,4 +146,3 @@ } | ||
* | ||
* @param {String} prop | ||
* @returns {Any} | ||
* @param prop | ||
*/ | ||
@@ -152,4 +155,3 @@ get(prop) { | ||
* | ||
* @param {String} prop | ||
* @returns {Boolean} | ||
* @param prop | ||
*/ | ||
@@ -162,81 +164,35 @@ has(prop) { | ||
* | ||
* @param {Request} request | ||
* @param {Response} response | ||
* @returns {Object} | ||
* @private | ||
* @param request | ||
* @param response | ||
*/ | ||
_makeContext(request, response) { | ||
makeContext(request, response) { | ||
var ctx = Object.create(this._context); | ||
ctx.response = response; | ||
ctx.request = request; | ||
ctx.params = {}; | ||
ctx.app = this; | ||
return ctx; | ||
} | ||
/** | ||
* Compose the middleware list into a callable function | ||
* Construct the routes tree | ||
* | ||
* @param {Array<Function>} fns | ||
* @returns {Function} | ||
* @private | ||
*/ | ||
_compose(fns) { | ||
var handlers = [...this._pres, ...fns, ...this._posts]; | ||
return (ctx) => this._loopMiddleware(ctx, handlers); | ||
} | ||
/** | ||
* Loop over the route middlewares | ||
* | ||
* @param {Object} ctx | ||
* @param {Array<Function>} fns | ||
*/ | ||
_loopMiddleware(ctx, fns) { | ||
var i = 0; | ||
var next = (err) => { | ||
if (!ctx.error && err) { | ||
this._loopError(err, ctx); | ||
return; | ||
_registerRoutes() { | ||
for (let route of this._routes) { | ||
for (let [method, fns] of route.handlers()) { | ||
fns = [...this._preHandlers, ...fns, ...this._postHandlers]; | ||
this._dispatcher.register(method, route.path, fns); | ||
} | ||
var fn = fns[i++]; | ||
if (!fn) { | ||
next = _noop; | ||
fn = this._finally; | ||
} | ||
// async call | ||
timers_1.setImmediate(fn, ctx, next); | ||
}; | ||
next(); | ||
// TODO register named routes | ||
} | ||
// reset the handlers | ||
this._routes = []; | ||
} | ||
/** | ||
* Loop over the error middlewares | ||
* | ||
* @param {Error} err | ||
* @param {Object} ctx | ||
*/ | ||
_loopError(err, ctx) { | ||
// TODO ensure err is an Error instance | ||
// set the context error | ||
ctx.error = err; | ||
this._loopMiddleware(ctx, this._catchers); | ||
} | ||
} | ||
exports.default = Application; | ||
/** | ||
* Create a 404 error instance | ||
* | ||
* @param {String} path | ||
* @returns {Error} | ||
* @private | ||
*/ | ||
function _notFoundError(path) { | ||
var msg = `Route not found for "${path}".`; | ||
var error = new Error(msg); | ||
error.code = 'NOT_FOUND'; | ||
error.expose = true; | ||
error.status = 404; | ||
return error; | ||
} | ||
/** | ||
* Ensure the given argument is a function | ||
* | ||
* @param {Any} arg | ||
* @returns {Function} | ||
* @param arg | ||
* @private | ||
@@ -252,15 +208,7 @@ */ | ||
* | ||
* @param {Object} context | ||
* @param ctx | ||
* @private | ||
*/ | ||
function _respond({ response }) { | ||
response.send(); | ||
function _respond(ctx) { | ||
ctx.response.send(); | ||
} | ||
/** | ||
* Noop | ||
* | ||
* @private | ||
*/ | ||
function _noop() { | ||
// do nothing | ||
} |
@@ -5,7 +5,7 @@ "use strict"; | ||
const assert = require("assert"); | ||
const createDebugger = require("debug"); | ||
const debug = createDebugger('aldo:route'); | ||
const METHODS = ['HEAD', 'GET', 'PATCH', 'POST', 'PUT', 'DELETE', 'OPTIONS']; | ||
/** | ||
* Route container | ||
* | ||
* @class Route | ||
*/ | ||
@@ -16,5 +16,4 @@ class Route { | ||
* | ||
* @param {String} path | ||
* @param {String} [prefix] | ||
* @constructor | ||
* @param path | ||
* @param prefix | ||
*/ | ||
@@ -29,4 +28,2 @@ constructor(path, prefix = '') { | ||
* The route path | ||
* | ||
* @type {String} | ||
*/ | ||
@@ -38,4 +35,2 @@ get path() { | ||
* The route name | ||
* | ||
* @type {String} | ||
*/ | ||
@@ -49,6 +44,6 @@ get name() { | ||
* @param {String} name | ||
* @returns {Route} | ||
*/ | ||
as(name) { | ||
this._name = name; | ||
debug(`set route name to "${this._name}"`); | ||
return this; | ||
@@ -59,4 +54,3 @@ } | ||
* | ||
* @param {String} path | ||
* @returns {Route} | ||
* @param path | ||
* | ||
@@ -67,2 +61,3 @@ * @todo add test case for "/" path | ||
this._prefix = _normalize(path); | ||
debug(`set route prefix to "${this._prefix}"`); | ||
return this; | ||
@@ -72,4 +67,2 @@ } | ||
* Get an iterator of the route handlers | ||
* | ||
* @returns {Array<[String, Array<Function>]>} | ||
*/ | ||
@@ -82,4 +75,3 @@ handlers() { | ||
* | ||
* @param {Function...} fns | ||
* @returns {Route} | ||
* @param fns | ||
*/ | ||
@@ -92,4 +84,3 @@ head(...fns) { | ||
* | ||
* @param {Function...} fns | ||
* @returns {Route} | ||
* @param fns | ||
*/ | ||
@@ -102,4 +93,3 @@ get(...fns) { | ||
* | ||
* @param {Function...} fns | ||
* @returns {Route} | ||
* @param fns | ||
*/ | ||
@@ -112,4 +102,3 @@ post(...fns) { | ||
* | ||
* @param {Function...} fns | ||
* @returns {Route} | ||
* @param fns | ||
*/ | ||
@@ -122,4 +111,3 @@ put(...fns) { | ||
* | ||
* @param {Function...} fns | ||
* @returns {Route} | ||
* @param fns | ||
*/ | ||
@@ -132,4 +120,3 @@ patch(...fns) { | ||
* | ||
* @param {Function...} fns | ||
* @returns {Route} | ||
* @param fns | ||
*/ | ||
@@ -142,4 +129,3 @@ delete(...fns) { | ||
* | ||
* @param {Function...} fns | ||
* @returns {Route} | ||
* @param fns | ||
*/ | ||
@@ -154,4 +140,3 @@ options(...fns) { | ||
* | ||
* @param {Function...} fns | ||
* @returns {Route} | ||
* @param fns | ||
*/ | ||
@@ -166,11 +151,10 @@ all(...fns) { | ||
* | ||
* @param {Array<String>} methods | ||
* @param {Function...} fns | ||
* @returns {Route} | ||
* @param methods | ||
* @param fns | ||
*/ | ||
any(methods, ...fns) { | ||
assert(fns.length, 'At least one route handler is required.'); | ||
fns.forEach((fn) => { | ||
for (let fn of fns) { | ||
assert(typeof fn === 'function', 'Route handler must be a function.'); | ||
}); | ||
} | ||
// wrap the final handler | ||
@@ -181,2 +165,3 @@ fns = _wrapFinalHandler(fns); | ||
assert(METHODS.includes(method.toUpperCase()), `Method '${method}' not accepted.`); | ||
debug(`add handlers for ${method.toUpperCase()} ${this.path}`); | ||
this._handlers.set(method, fns); | ||
@@ -191,4 +176,3 @@ } | ||
* | ||
* @param {String} path | ||
* @returns {String} | ||
* @param path | ||
* @private | ||
@@ -204,6 +188,5 @@ */ | ||
/** | ||
* Wrap the last middleware function | ||
* Wrap the last handler | ||
* | ||
* @param {Array<Function>} handlers | ||
* @returns {Array<Function>} | ||
* @param handlers | ||
* @private | ||
@@ -219,23 +202,12 @@ */ | ||
* | ||
* @param {Function} fn | ||
* @returns {Function} | ||
* @param fn | ||
* @private | ||
*/ | ||
function _wrapper(fn) { | ||
return async (ctx, next) => { | ||
try { | ||
var result = await fn(ctx); | ||
if (result instanceof Error) { | ||
next(result); | ||
return; | ||
} | ||
if (result && !ctx.response.body) { | ||
ctx.response.body = result; | ||
} | ||
next(); | ||
return async (ctx) => { | ||
var result = await fn(ctx); | ||
if (result && !ctx.response.body) { | ||
ctx.response.body = result; | ||
} | ||
catch (error) { | ||
next(error); | ||
} | ||
}; | ||
} |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const route_1 = require("./route"); | ||
const createDebugger = require("debug"); | ||
const debug = createDebugger('aldo:router'); | ||
/** | ||
@@ -12,3 +14,3 @@ * Routes factory and manager | ||
this._prefix = _prefix; | ||
this._middlewares = []; | ||
this._handlers = []; | ||
this._routes = []; | ||
@@ -25,2 +27,3 @@ // | ||
this._prefix = value; | ||
debug(`update route prefix to ${this._prefix}`); | ||
// set the prefix for the registered routes | ||
@@ -47,8 +50,9 @@ for (let route of this._routes) { | ||
route(path) { | ||
let instance = new route_1.default(path, this._prefix); | ||
this._routes.push(instance); | ||
return instance; | ||
var route = new route_1.default(path, this._prefix); | ||
debug(`create route for ${path}`); | ||
this._routes.push(route); | ||
return route; | ||
} | ||
/** | ||
* Use global middlewares | ||
* Use global handlers | ||
* | ||
@@ -59,33 +63,98 @@ * @param {Function...} fns | ||
use(...fns) { | ||
fns.forEach((fn) => { | ||
this._middlewares.push(_ensureFunction(fn)); | ||
}); | ||
for (let fn of fns) { | ||
this._handlers.push(_ensureFunction(fn)); | ||
debug(`use route handler: ${fn.name || '<anonymous>'}`); | ||
} | ||
return this; | ||
} | ||
/** | ||
* Make new route and set the handlers for HEAD method | ||
* | ||
* @param {String} path | ||
* @param {Function...} handlers | ||
* @returns {Route} | ||
*/ | ||
head(path, ...handlers) { | ||
return this.route(path).head(...this._middlewares.concat(handlers)); | ||
return this.route(path).head(...this._handlers.concat(handlers)); | ||
} | ||
/** | ||
* Make new route and set the handlers for GET method | ||
* | ||
* @param {String} path | ||
* @param {Function...} handlers | ||
* @returns {Route} | ||
*/ | ||
get(path, ...handlers) { | ||
return this.route(path).get(...this._middlewares.concat(handlers)); | ||
return this.route(path).get(...this._handlers.concat(handlers)); | ||
} | ||
/** | ||
* Make new route and set the handlers for POST method | ||
* | ||
* @param {String} path | ||
* @param {Function...} handlers | ||
* @returns {Route} | ||
*/ | ||
post(path, ...handlers) { | ||
return this.route(path).post(...this._middlewares.concat(handlers)); | ||
return this.route(path).post(...this._handlers.concat(handlers)); | ||
} | ||
/** | ||
* Make new route and set the handlers for PUT method | ||
* | ||
* @param {String} path | ||
* @param {Function...} handlers | ||
* @returns {Route} | ||
*/ | ||
put(path, ...handlers) { | ||
return this.route(path).put(...this._middlewares.concat(handlers)); | ||
return this.route(path).put(...this._handlers.concat(handlers)); | ||
} | ||
/** | ||
* Make new route and set the handlers for PATCH method | ||
* | ||
* @param {String} path | ||
* @param {Function...} handlers | ||
* @returns {Route} | ||
*/ | ||
patch(path, ...handlers) { | ||
return this.route(path).patch(...this._middlewares.concat(handlers)); | ||
return this.route(path).patch(...this._handlers.concat(handlers)); | ||
} | ||
/** | ||
* Make new route and set the handlers for DELETE method | ||
* | ||
* @param {String} path | ||
* @param {Function...} handlers | ||
* @returns {Route} | ||
*/ | ||
delete(path, ...handlers) { | ||
return this.route(path).delete(...this._middlewares.concat(handlers)); | ||
return this.route(path).delete(...this._handlers.concat(handlers)); | ||
} | ||
/** | ||
* Make new route and set the handlers for OPTIONS method | ||
* | ||
* @param {String} path | ||
* @param {Function...} handlers | ||
* @returns {Route} | ||
*/ | ||
options(path, ...handlers) { | ||
return this.route(path).options(...this._middlewares.concat(handlers)); | ||
return this.route(path).options(...this._handlers.concat(handlers)); | ||
} | ||
/** | ||
* Make new route and set the handlers for accepted methods | ||
* | ||
* @param {String} path | ||
* @param {Function...} handlers | ||
* @returns {Route} | ||
*/ | ||
all(path, ...handlers) { | ||
return this.route(path).all(...this._middlewares.concat(handlers)); | ||
return this.route(path).all(...this._handlers.concat(handlers)); | ||
} | ||
/** | ||
* Make new route and set the handlers for the given HTTP method | ||
* | ||
* @param {Array<String>} methods | ||
* @param {String} path | ||
* @param {Function...} handlers | ||
* @returns {Route} | ||
*/ | ||
any(methods, path, ...handlers) { | ||
return this.route(path).any(methods, ...this._middlewares.concat(handlers)); | ||
return this.route(path).any(methods, ...this._handlers.concat(handlers)); | ||
} | ||
@@ -92,0 +161,0 @@ } |
{ | ||
"name": "aldo", | ||
"version": "0.1.0-alpha.0", | ||
"version": "0.2.0", | ||
"description": "Fast web framework for Node.js", | ||
@@ -9,4 +9,8 @@ "main": "lib/index.js", | ||
"prepublishOnly": "tsc && npm test", | ||
"test": "mocha -r ts-node/register \"src/**/*.spec.ts\"" | ||
"test": "mocha -R dot -r ts-node/register \"test/**/*.ts\"" | ||
}, | ||
"files": [ | ||
"lib", | ||
"index.d.ts" | ||
], | ||
"repository": { | ||
@@ -35,6 +39,8 @@ "type": "git", | ||
"dependencies": { | ||
"@types/debug": "0.0.30", | ||
"@types/node": "^8.9.2", | ||
"aldo-http": "^0.1.3", | ||
"aldo-http": "^0.2.0", | ||
"debug": "^3.1.0", | ||
"find-my-way": "^1.10.1" | ||
} | ||
} |
122
README.md
## Introduction | ||
`Aldo` is another library to build web applications for Node.js. | ||
> This project is under heavy development, and the API may change frequently. | ||
It uses the best parts of `Koa`, `Express` and `Fastify` to make building restful applications fun and easy. | ||
`Aldo` is yet another framework to build Node.js web applications. | ||
It uses the best parts of `Koa` and `Express` to provide a fast engine for your web projects. | ||
`Aldo`'s goal is to provide a secure and solid foundation for your projects, a fast execution and a fluent API. | ||
## Installation | ||
@@ -18,5 +16,4 @@ ```bash | ||
``` | ||
> More tests are comming in the future | ||
## Usage | ||
## Hello world! | ||
```js | ||
@@ -37,5 +34,112 @@ // import the needed parts | ||
// which creates and uses an internal HTTP server | ||
app.serve(3000) | ||
app.start(3000) | ||
``` | ||
## To be continued... | ||
## Request Flow | ||
The request handling logic is similar to the `try..catch..finally` JavaScript block. | ||
In other words, the application will try to call the route handlers one by one to the final handler. | ||
If an error occurs, it will be handled by the error handlers before reaching the final handler which will terminate and send the response to the client. | ||
You can use `.pre`, `.post`, `.use`, `.catch` and `.finally` application's methods to control the flow of request handling. | ||
```js | ||
const app = new Application() | ||
// 1. The `try` block | ||
// attach one or more global handlers before the route | ||
// useful to configure global services like session, cache ...etc | ||
app.pre(...handlers) | ||
// use one or many routers with `.use` | ||
app.use(...routers) | ||
// ... etc | ||
// attach global handlers to be executed after the route handlers | ||
// like saving a cached version, persisting session data, setting more headers ...etc | ||
app.post(...handlers) | ||
// 2. The `catch` block | ||
// attaching error handlers is done as below | ||
app.catch(...handlers) | ||
// 3. The `finally` block | ||
// at last, only one final handler is used | ||
// the default one is simply sending the response | ||
app.finally(finalHandler) | ||
``` | ||
> Since each method controls a processing step, the order doesn't matter any more. | ||
> We can define routes before or after the final handler, it won't create any issue, since the routes are only compiled during the application launch. | ||
Unlike the other web frameworks, each `handler` takes only **one** argument: the **`context`**. This object holds everything you need to handle the incoming HTTP request. | ||
Handlers may return *void* or a promise for asynchronous operations. | ||
So, when the current handler finished its job, the *context* object is passed automatically to the next handler, and so on, till the final handler which terminates and ends the response. | ||
To break the chain, throw an error, to get the first error handler called instead of the next middleware. | ||
```ts | ||
// Handler function signature | ||
declare type Handler = (ctx: Context) => any | ||
``` | ||
## Context | ||
The context object is not a proxy to the request and response properties, it's a simple plain object with only 4 mandatory properties `app`, `request`, `response` and route `params`. | ||
Even the error handlers have the same signature, but with an additonal `error` property. | ||
```ts | ||
declare type Literal = { [x: string]: any } | ||
declare interface Context extends Literal { | ||
response: Response; // Response object provided by the package `aldo-http` | ||
request: Request; // Request object provided by the package `aldo-http` | ||
app: Application; // Application instance | ||
params: Literal; // Route parameters | ||
error?: any; // The error | ||
} | ||
``` | ||
To extend the request context, and add more properties, you can use `app.set(key, value)` or `app.bind(key, factory)` | ||
```js | ||
// set a global value to be available for all requests | ||
app.set('mongo', dbConnection) | ||
// set a per request property using a function to lazily get the value | ||
// This time, each context instance has a distinct `session` property | ||
app.bind('session', () => new Session(options)) | ||
``` | ||
`app.has(key)` and `app.get(key)` are also available to check the existence of a certain field, or to get a previously defined property. | ||
## Router | ||
Each `router` instance control an erea in the application, it acts like a route namespace. | ||
You can use as many routers as you need. For example, a router to manage authentication, another for the API, a private router for admin routing, and so on. | ||
> The order of defining routes is not important any more. Thanks to [find-my-way](https://npmjs.com/find-my-way) witch is a [radix tree](https://en.wikipedia.org/wiki/Radix_tree). | ||
```js | ||
const { Router } = require('aldo') | ||
const { Users } = require('./controllers') | ||
// Let's create an admin area router | ||
// `/admin` is a URL prefix for all routes | ||
const router = new Router('/admin') | ||
// define a single handler for admin home page for the GET method | ||
router.get('/', Users.home) | ||
// we can define multiple handlers per HTTP method for the same route | ||
router | ||
.route('/Users') | ||
.get(Users.show) | ||
.delete(Users.delete) | ||
.post(Users.validate, Users.add) | ||
.put(Users.validate, Users.modify) | ||
``` | ||
## License | ||
[MIT License](https://opensource.org/licenses/MIT) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
27176
825
144
5
11
1
+ Added@types/debug@0.0.30
+ Addeddebug@^3.1.0
+ Added@types/debug@0.0.30(transitive)
+ Addedaldo-http@0.2.2(transitive)
+ Addeddebug@3.2.7(transitive)
+ Addedms@2.1.3(transitive)
- Removedaldo-http@0.1.3(transitive)
Updatedaldo-http@^0.2.0