Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

koa2-router

Package Overview
Dependencies
Maintainers
1
Versions
17
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

koa2-router - npm Package Compare versions

Comparing version 1.0.9 to 1.1.0

101

lib/index.js

@@ -35,2 +35,3 @@ /*!

var toString = Object.prototype.toString
var featureSymbol = Symbol('koa2-router')

@@ -50,3 +51,3 @@ /**

/**
* Add baseUrl/params to the
* Add baseUrl/params/matched to the
* prototype of request and context in app

@@ -64,3 +65,3 @@ *

const request = app.request
if (!request.hasOwnProperty('baseUrl')) {
if (!request.hasOwnProperty(featureSymbol)) {
Object.defineProperties(request, {

@@ -78,2 +79,6 @@ baseUrl: {

set: function(matched) { return this.req.matched = matched }
},
[featureSymbol]: {
value: 'koa2-router',
writable: false,
}

@@ -85,2 +90,3 @@ })

.access('matched')
.getter(featureSymbol)
}

@@ -90,2 +96,3 @@ }

/**
* @alias module:koa2-router
* Initialize a new `Router` with the given `options`.

@@ -108,2 +115,3 @@ *

patchPrototype(ctx.app)
// initialize ctx.req with `originalUrl`, `baseUrl`, `params`

@@ -227,34 +235,12 @@ const req = ctx.req

// store options for OPTIONS request
// only used if OPTIONS request
var matched = []
// save point
var restoreCtx = restore(undefined, ctx, 'baseUrl', 'params', 'url')
// save point 1
var restore1 = restore(ctx, 'baseUrl', 'params', 'url')
// detect router match
var notMatched = false
try {
// dispatch into the current router
await this.dispatch(ctx, matched, function() {
notMatched = true
})
await this.dispatch(ctx, upstream)
} finally {
// restore point 1
restore1()
// restore point
restoreCtx()
}
if (notMatched) {
if (matched.length) ctx.matched = matched
// save point 2
var restore2 = restore(ctx, 'baseUrl', 'params', 'url')
try {
// go upstream
await upstream()
} finally {
// restore point 2
restore2()
}
}
}

@@ -325,5 +311,16 @@

Router.prototype.dispatch = function dispatch(ctx, matched, done) {
Router.prototype.dispatch = function dispatch(ctx, done) {
var self = this
var matched = []
// collect methods of which route matches
// the path but not method
done = wrap(done, function(fn) {
if (matched.length) ctx.matched = matched
return fn()
})
// restore properties in context
done = restore(done, ctx, 'baseUrl', 'params', 'url')
debug('dispatching %s %s%s', ctx.method, ctx.baseUrl, ctx.url)

@@ -426,4 +423,23 @@

if (route) {
return layer.handle(ctx, next)
// .all(.get/.post/...) middlewares
// call next() after layer.handle
// finishes its route's dispatching
var isNextCalled = false
function onNextCalled() {
isNextCalled = true
}
function tryNext() {
// only call next if next() is called
// within route middlewares, and ctx
// is not responded
if (!isNextCalled || isResponded(ctx)) return
return next()
}
return layer.handle(ctx, onNextCalled)
.then(tryNext)
}
// .use middlewares
return trim_prefix(layer, layerPath, path, next)

@@ -742,3 +758,3 @@ }).catch(function(e) {

// save obj props for restoring after a while
function restore(obj) {
function restore(fn, obj) {
var props = new Array(arguments.length - 1)

@@ -757,2 +773,4 @@ var vals = new Array(arguments.length - 1)

}
return fn && fn.apply(this, arguments)
}

@@ -791,1 +809,20 @@ }

}
/**
* Wrap a function
*
* @private
*/
function wrap(old, fn) {
return function proxy() {
var args = new Array(arguments.length + 1)
args[0] = old
for (var i = 0, len = arguments.length; i < len; i++) {
args[i + 1] = arguments[i]
}
return fn.apply(this, args)
}
}

@@ -106,12 +106,3 @@ /*!

// detect route match
var notMatched = false
await this.dispatch(ctx, function() {
notMatched = true
})
if (notMatched) {
await upstream()
}
await this.dispatch(ctx, upstream)
}

@@ -118,0 +109,0 @@

{
"name": "koa2-router",
"version": "1.0.9",
"version": "1.1.0",
"description": "A express-liked router component for koa2",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -6,2 +6,4 @@ # koa2-router

## Features
## Getting Started

@@ -22,3 +24,3 @@ You can follow the instructions below to setup a router component in koa@2 environment.

* Import component
```
```javascript
const Router = require('koa2-router');

@@ -28,8 +30,8 @@ ```

* Create a router
```javascript
const router = new Router(opts);
```
const router = Router(opts);
```
* Mount a router to a koa application
```
```javascript
const app = new Koa();

@@ -40,10 +42,10 @@ app.use(router);

* Mount a router to another router
```
const router2 = Router();
```javascript
const router2 = new Router();
router2.use(...);
router.use('/users', router2);
router.all('/users', router2);
```
* Use http method to handle request
```
```javascript
router2.get('/:userId', ctx => ctx.body = `hello user ${ctx.params.userId}`);

@@ -53,11 +55,11 @@ ```

* Use params middleware like express
```
```javascript
const router3 = Router();
router3.params('userName', (ctx, next, userName, key) => (ctx[key] = userName, next()))
.get('/:userName', async ctx => ctx.body = await ctx.db.getStaffFromName(ctx.userName));
router.use('/staff', router3);
router.all('/staff', router3);
```
* Use route to make a rest api
```
```javascript
const route = router3.route('/:id');

@@ -69,3 +71,3 @@ route

* exit route or router without exception
```
```javascript
route

@@ -79,9 +81,127 @@ .all(async (ctx, next) => {

route3.use('/admin', (ctx, next) => {
if (ctx.authenticate.userRoles.includes('admin')) return next();
else throw 'router'; // exit this router3 without any exception
})
route3.all('/admin', (ctx, next) => {
if (ctx.authenticate.userRoles.includes('admin')) return next();
else throw 'router'; // exit this router3 without any exception
})
.post('/posts', async ctx => ctx.body = await ctx.db.createPost(ctx.request.body, ctx.authenticate.userId));
```
* implement Method Not Allowed and Not Implemented
```javascript
router.all('/api', router3, router3.allowMethods(opts))
```
`opts` the allowMethods options
`opts.throw` [boolean] default false, set to true to throw errors
`opts.methodNotAllowed` [function(ctx, methods)] set if throw a custom 405 error
`opts.notImplemented` [function(ctx)] set if throw a custom 501 error
## Nested Router Spec
In this module, router is a specific **function** instance which can be constructed via `router = new Router(opts)` or `router = Router(opts)`, and can be directly used as a `Koa.Middleware` function - `app.use(router)`.
We create a router model called **Express Liked Router Model**. The router constructed via this mechanism, implements everything that `express.Router` also dose, like `Router.use()`, `Router[method]()` `Router.params()` `Router.route()`.
But there is an issue about that mode, how nested router stack being built for an asynchronized middleware system.
Nested routers are supported, but in a different way. Considering the entering and exiting order of the stack, we have consulted and borrowed the middlewares in Golang: within that a new `Group` midleware is presented, and it can make a branching stack. So we borrowed this design and setup new rules in nested routers in order to constraint excuting orders:
1. Middleares using `.use` only insert pure `middlewares` to the original stack
> in `Router.use(path, middlewares)`, `middlewares` are inserted into
> the parent's middlewares thus when the last one invokes `next`, it
> will continue `enter` the next one of the parent router, until all
> things done, then it will `leave` from the bottom to the top of the
> parent router's stack
Let's see an example
```js
var router = new Router('A')
var nested = new Router('B')
router.use(async (ctx, next) => {
console.log('enter parent')
await next()
console.log('leave parent')
})
// use `.use so nested mw is bundled together with the parent`
router.use('/stuff', nested)
router.use(async (ctx, next) => {
console.log('prepare')
await next()
console.log('post')
})
router.use(ctx => {
console.log('output body')
ctx.body = 'success'
})
nested.use(async (ctx, next) => {
console.log('enter nested')
await next()
console.log('leave nested')
})
```
**GET /stuff** and watch the console
```bash
> enter parent
> enter nested
> prepare
> output body
> post
> leave nested
> leave parent
> HTTP/1.1 200 OK
> success
```
2. Middlewares using `[method]` `.all` or `.route` makes a branching stack of route nested in the parent stack
> in this situation, middlewares are bundled into another one, and
> if the one is matched both in method & route, calling `next` in the
> last middlewares of the nested router will `leave` the nested router > stack from bottom to the top first, and then if nothing is responded > before that, it enters the next middleware of the parent stack
Let's see another example, almost the same as above one
```js
var router = new Router('A')
var nested = new Router('B')
router.use(async (ctx, next) => {
console.log('enter parent')
await next()
console.log('leave parent')
})
// use `.all` instead of `.use`
router.all('/stuff', nested)
router.use(async (ctx, next) => {
console.log('prepare')
await next()
console.log('post')
})
router.use(ctx => {
console.log('output body')
ctx.body = 'success'
})
nested.use(async (ctx, next) => {
console.log('enter nested')
await next()
console.log('leave nested')
})
```
**GET /stuff** and watch the console
```bash
> enter parent
> enter nested
> leave nested
> prepare
> output body
> post
> leave parent
> HTTP/1.1 200 OK
> success
```
The order of entering/leaving differs from the above example, because we make a branching stack nested in the router, and it will leave the branching stack before go over the next. It is just like the `Group` in the project [gobwas/glob](https://github.com/gobwas/glob) powered by golang
## Running tests

@@ -97,2 +217,3 @@ You should clone thie repository down to your file system, and execute

* Thanks to the [router](https://github.com/pillarjs/router) project
* Thanks to the [gobwas/glob](https://github.com/gobwas/glob) project

@@ -99,0 +220,0 @@ ## License

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc