Coder Social home page Coder Social logo

koa-tree-router's Introduction

Koa tree router

Build Status npm npm downloads

Koa tree router is a high performance router for Koa.

Features

  • Fast. Up to 11 times faster than Koa-router. Benchmark

  • Express-style routing using router.get, router.put, router.post, etc.

  • Support for 405 method not allowed

  • Multiple middleware per route

How does it work?

The router relies on a tree structure which makes heavy use of common prefixes, it is basically a compact prefix tree (or just Radix tree).

This module's tree implementation is based on julienschmidt/httprouter.

Installation

# npm
npm i koa-tree-router
# yarn
yarn add koa-tree-router

Usage

const Koa = require("koa");
const Router = require("koa-tree-router");

const app = new Koa();
const router = new Router();
router.get("/", function(ctx) {
  ctx.body = "hello, world";
});

app.use(router.routes());

app.listen(8080);

API

Router([options])

Instance a new router.

const router = require('koa-tree-router')({
  onMethodNotAllowed(ctx){
    ctx.body = "not allowed"
  },
  ignoreTrailingSlash: true
})

on(method, path, middleware)

Register a new route.

router.on('GET', '/example', (ctx) => {
  // your code
})

Shorthand methods

If you want to get expressive, here is what you can do:

router.get(path, middleware)
router.delete(path, middleware)
router.head(path, middleware)
router.patch(path, middleware)
router.post(path, middleware)
router.put(path, middleware)
router.options(path, middleware)
router.trace(path, middleware)
router.connect(path, middleware)

If you need a route that supports all methods you can use the all api.

router.all(path, middleware)

use(middleware)

You can add middleware that is added to all future routes:

router.use(authMiddleware);
router.get("/foo", (ctx) => { /* your code */ });
router.get("/bar", (ctx) => { /* your code */ });
router.get("/baz", (ctx) => { /* your code */ });

This is equivalent to:

router.get("/foo", authMiddleware, (ctx) => { /* your code */ });
router.get("/bar", authMiddleware, (ctx) => { /* your code */ });
router.get("/baz", authMiddleware, (ctx) => { /* your code */ });

Caveat: use must be called before register a new handler. It does not append handlers to registered routes.

routes

Returns router middleware.

app.use(router.routes());

nested routes

A way to create groups of routes without incuring any per-request overhead.

const Koa = require("koa");
const Router = require("koa-tree-router");

const app = new Koa();
const router = new Router();
const group = router.newGroup("/foo");
// add a handler for /foo/bar
group.get("/bar", function(ctx) {
  ctx.body = "hello, world";
});

app.use(router.routes());

app.listen(8080);

Middleware added with use() are also added to the nested routes.

ctx.params

This object contains key-value pairs of named route parameters.

router.get("/user/:name", function() {
  // your code
});
// GET /user/1
ctx.params.name
// => "1"

How to write routes

There are 3 types of routes:

1.Static

Pattern: /static

 /static                   match
 /anything-else            no match

2.Named

Named parameters have the form :name and only match a single path segment:

Pattern: /user/:user

 /user/gordon              match
 /user/you                 match
 /user/gordon/profile      no match
 /user/                    no match

3.Catch-all

Catch-all parameters have the form *name and match everything. They must always be at the end of the pattern:

Pattern: /src/*filepath

 /src/                     match
 /src/somefile.go          match
 /src/subdir/somefile.go   match

Typescript Support

This package has its own declaration files in NPM package, you don't have to do anything extra.

License

MIT

koa-tree-router's People

Contributors

abalabahaha avatar dependabot[bot] avatar lehni avatar saadq avatar steambap avatar talentlessguy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

koa-tree-router's Issues

Why is `koa-tree-router` picking `:param` as a wildcard?

I have the following routes which works just fine.

router.get('/note/:id', middlware);
router.get('/notes', middleware);
router.post('/note', middleware);
router.delete('/', middleware);

when I go another route instance and try registering another route as seen below I get an error.

route2.get('/request-id', middleware);

The error:

                    ^
error: wildcard route ':id' conflicts with existing children in path '/note/:id'
      at insertChild (/Users/username/**/lib/tree.ts:277:15)
      at addRoute (/Users/username/**/lib/tree.ts:229:9)
      at register (/Users/username/**/lib/router.ts:155:5)
      at all (/Users/username/**/lib/cols**.ts:175:9)
      at /Users/username/**/example/note-app/src/app.ts:64:1
272 |           "'"
273 |         );
274 |       }
272 |           "'"
273 |         );
274 |       }
275 | 
276 |       if (n.children.length > 0) {
277 |         throw new Error(
                    ^

Also, I notice if I change the order of this routes it throw the same error:

Changing this from

router.get('/note/:id', middlware);
router.get('/notes', middleware);
router.post('/note', middleware);
router.delete('/', middleware);

To this:

router.get('/notes', middleware);
router.get('/note/:id', middlware);
router.post('/note', middleware);
router.delete('/', middleware);

Doesn it have something to do with this issue

feature request - add `prefix` option to Router constructor

One thing I miss from koa-router is being able to prefix all your routes.

For example:

import Router from 'koa-router'
const router = new Router()

router.get('/api/cars', async ctx => {

})


router.get('/api/bikes', async ctx => {

})

could be simplified to this:

import Router from 'koa-router'
const router = new Router({ prefix: '/api' })

router.get('/cars', async ctx => {

})


router.get('/bikes', async ctx => {

})

This was quite useful when using a webpack dev server where I would proxy all routes starting with /api to my Node server.

Option for ignoring trailing slash

It is useful sometimes not to return 404 if trailing slash exists but not explicitly in route pattern. What about adding ignoreTrailingSlash option while instancing for ignoring trailing slashes?

Define two routes on one single param prefix

Hello! Thank you for this package!

I have an issue defining two subpaths for single-wildcarded route prefix:

const socialTypeWildGroup = authRouteGroup.newGroup('/:socialType')

socialTypeWildGroup.delete('/foo', async (ctx) => {})
socialTypeWildGroup.get('/bar', async (ctx) => {})

The router throws: Error: wildcard route ':socialType' conflicts with existing children in path '/api/auth/:socialType/bar'

What am I doing wrong?

Allow nested routers

Would be helpful to allow nested routers using router.use(...) syntax, similar to koa-router.

Here's an example:

const apiRouter = new Router({ prefix: '/api' })
apiRouter.use(usersRouter.routes())  // assume prefix '/users'
apiRouter.use(todosRouter.routes()) // assume prefix '/todos'
...

app.use(apiRouter.routes())  // would allow /api/users and /api/todos

I personally use awilix to dynamically load a lot of my routers/controllers and then build a parent apiRouter like so (iterating through the IoC container via listModules()).

Getting matched route

Is there a way to get the matched route pattern as opposed to the actual url (ctx.request.url)?

Also this middleware appears near the end of all my middleware (after the ones that need to go before it like logging and permissions). But I'd like to be able to log the matched route pattern in the earlier middleware. Something like a router.getMatchedPattern function we could call at the beginning of our middleware to resolve the matched pattern which we can use throughout the other middleware. What do you think of such feature?

app.use(addToLogger(router.getMatchedPattern())
// lots of other middleware go here
app.use(othermiddleware)
app.use(router.routes())

Middleware after route

I'm trying to migrate a code that is working with @koa/router, but the last middlware doesn't get called when using koa-tree-router:

router.use(...) <= this works
router.get(...)
router.use(...) <= this is never called

Is that a known limitation?

Support auto-generated OPTIONS handler / Distinguish between 501 and 405 errors

First of all, thank you for creating this router! After looking at koa-router's code, I realized that performance should be much better if it was backed by a tree structure and went looking further, and found this!

One feature that koa-router offers that appears to be missing here, but would probably be really easy to implement is the allowedMethods() middleware.

From a quick glance at the following lines it looks like the functionality is mostly there, it would just need to be exposed through a handler:

const allowList = [];
// Search for allowed methods
for (let key in router.trees) {
if (key === ctx.method) {
continue;
}
const tree = router.trees[key];
if (tree.search(ctx.path).handle !== null) {
allowList.push(key);
}
}
ctx.status = 405;
ctx.set("Allow", allowList.join(", "));

Also, it looks like currently when a method is not found, the router always sends a 405 error back (but only if a onMethodNotAllowed() handler is defined, why not always send a default one?), without distinguishing 405 and 501, as koa-router does:

https://github.com/alexmingoia/koa-router/blob/590df78ef38a557e9ce86a14bd9bfe567c5701a1/lib/router.js#L419-L450

Some more information:

https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/405
https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/501

ZijianHe/koa-router#7

Would you accept a PR for this? Do you have any opinions on how it should be controlled through options?

router-benchmark

I've added this router to router-benchmark. Please, check, whether the implementation is reasonable, and, if you desire, add a link to the benchmark in this project's readme.

Type declaration missing '.use'

When using typescript the following code fails to typecheck with:

router.use(...)

Property 'use' does not exist on type 'Router'

Thanks for a Koa Router

There has been a lot of traffic in @koa/router and koa-router these last few days which caused me look into the whole sale of koa-router (which I was using until your project today). Just kind of strange these unknown/private profiles making changes to big projects, for example the sale of koa-router and koajs/router@d0c6d8b.

Anyway, just wanted to say thank you for making a performant koa-router that you've supported for about 4 years now.

Swagger for koa tree router

Is there a possible way to auto-generate swagger using koa tree router,

Swagger-koa uses the default routing mechanism that comes from Koa itself.
In my case we're using koa tree router and the swagger keeps failing to generate modules / routes.

Any idea how to fix it ,
Thanks

Route 404 error when missing trailing slash in URL

The router will fail to find the route handler when the URL being accessed does not end with a trailing slash (/).

Example:

const router = new Router({ prefix: '/users' })
router.get('/', ...)

You can access the GET /users/ route just fine, but GET /users will 404. Just checked koa-router and it will resolve the route properly.

Seems like a bug.

Types are not using Koa parametrized context

Koa is now using parametrized contexts:

https://github.com/DefinitelyTyped/DefinitelyTyped/blob/b081a5b/types/koa/index.d.ts#L689-L705

koa-tree-router loses those typings (its Router class is not parametrized at all).

For example, that's how koa-router handles types:

https://github.com/DefinitelyTyped/DefinitelyTyped/blob/1645790/types/koa-router/index.d.ts#L162

The point is being able to provide State interface and then have typings for ctx.state in the middleware:

import Router from "koa-router"

export interface State {
	foo: string
}

const router = new Router<State>()

router.get("/ping", async ctx => {
	// Here Typescript knows that ctx.state.foo is a string
})

(As you may know, koa-router has been sold, so I'm looking for an alternative—just in case.)

wildcard issue in group router

unable to specify catchall route handler if a named route exist at the same level

issue:

  • it appears i cannot have a catchall route at the same level of a named route?

purpose:

  • I want to catch all invalid requests at URI good/good/badname

problem:

  • if I already have good/good/goodname
  • koa-tree router throws error `error in v1 handler Error:
  • **wildcard route 'notfound' conflicts with existing children in path '/v1/demo/notfound'`'
    //works
   v1RouterGroup.get('/', v1Handler);

   //works
    v1RouterGroup.get('/demo/pkgcheck', demo.pkgCheckHandler.getPkg);

   // does not work
    v1RouterGroup.get('/demo/*notfound', demo.pkgCheckHandler.notFound);

   //works
    v1RouterGroup.get('/demo/someothershit/*notfound', demo.pkgCheckHandler.notFound);

here is a link to the actual code

here is a link to the handler definition

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.