@goa/router

1.2.0 • Public • Published

@goa/router

npm version

@goa/router is The Router For Creating Middleware For Goa Apps.

yarn add @goa/router

Table Of Contents

API

The package is available by importing its default class:

import Router from '@goa/router'

The example below creates a really simple router that responds to the GET / and POST /users/:uid requests. Because of allowedMethods, it will also send a response to the OPTIONS request with the allow header.

Example Output
import rqt, { aqt } from 'rqt'
import Goa from '@goa/koa'
import Router from '@goa/router'

const goa = new Goa()
const router = new Router()
router
  .get('/', (ctx) => {
    ctx.body = `Hello world`
  })
  .post('/users/:uid', (ctx) => {
    ctx.body = `You have edited the user ${ctx.params.uid}`
  })
goa.use(router.routes())

goa.use(router.allowedMethods())
# GET /
Hello world

# POST /users/100
You have edited the user 100


# OPTIONS /
HEAD, GET

Router: Router For Goa Apps.

Name Type & Description
constructor new (opts?: !RouterConfig) => Router

Create a new router.

import Goa from '@goa/koa'
import Router from '@goa/router'

const app = new Goa()
const router = new Router()

router.get('/', (ctx, next) => {
  // ctx.router available
})

app
  .use(router.routes())
  .use(router.allowedMethods())
static url (path: string, ...params: !Object[]) => string

Generate URL from url pattern and given params.

const url = Router.url('/users/:id', { id: 1 })
// => "/users/1"
opts !RouterConfig
Stored options passed to the Router constructor.
allowedMethods (options: !AllowedMethodsOptions) => !Middleware

Returns separate middleware for responding to OPTIONS requests with an Allow header containing the allowed methods, as well as responding with 405 Method Not Allowed and 501 Not Implemented as appropriate.

import Goa from '@goa/koa'
import Router from '@goa/router'

const app = new Goa()
const router = new Router()

app.use(router.routes())
app.use(router.allowedMethods())
param (param: string, middleware: !Middleware) => !Router

Run middleware for named route parameters. Useful for auto-loading or validation.

router
  .param('user', (id, ctx, next) => {
    ctx.user = users[id]
    if (!ctx.user) return ctx.status = 404
    return next()
  })
  .get('/users/:user', ctx => {
    ctx.body = ctx.user
  })
  .get('/users/:user/friends', async ctx => {
    ctx.body = await ctx.user.getFriends()
  })
redirect (source: string, destination: string, code?: number) => !Router
Redirect source to destination URL with optional 30x status code. Both source and destination can be route names.
route (name: string) => Layer
Lookup route with given name. If the route is not found, returns null.
url (name: string, ...params: !Object[]) => (string | !Error)

Generate URL for route. Takes a route name and map of named params. If the route is not found, returns an error. The last argument can be an object with the query property.

// To use urls, a named route should be created:
router.get('user', '/users/:id', (ctx, next) => {
  // ...
})

Get the URL by passing a simple parameter

router.url('user', 3)
// => "/users/3"

Get the URL by passing parameters in an object

router.url('user', { id: 3 })
// => "/users/3"

Use the url method for redirects to named routes:

router.use((ctx) => {
  ctx.redirect(ctx.router.url('sign-in'))
})

Pass an object query:

router.url('user', { id: 3 }, { query: { limit: 1 } })
// => "/users/3?limit=1"

Pass an already serialised query:

router.url('user', { id: 3 }, { query: 'limit=1' })
// => "/users/3?limit=1"
use (path: (string | !Array<string> | !Middleware), ...middleware: !Middleware[]) => !Router

Use given middleware. Middleware run in the order they are defined by .use(). They are invoked sequentially, requests start at the first middleware and work their way "down" the middleware stack.

// session middleware will run before authorize
router
  .use(session())
  .use(authorize())
// use middleware only with given path
router.use('/users', userAuth())
// or with an array of paths
router.use(['/users', '/admin'], userAuth())
app.use(router.routes())
prefix (prefix: string) => !Router

Set the path prefix for a Router instance that was already initialized.

router.prefix('/things/:thing_id')
middleware
routesalias
() => !Middleware
Returns router middleware which dispatches a route matching the request.
RouterConfig: Config for the router.
Name Type Description
methods !Array<string> The methods to serve.
Default HEAD, OPTIONS, GET, PUT, PATCH, POST, DELETE.
prefix string Prefix router paths.
routerPath string Custom routing path.

Verbs

Routes are assigned to the router by calling HTTP method verbs on the instance:

router
  .get('/', (ctx, next) => {
    ctx.body = 'Hello World!'
  })
  .post('/users', (ctx, next) => {
    // ...
  })
  .put('/users/:id', (ctx, next) => {
    // ...
  })
  .del('/users/:id', (ctx, next) => {
    // ...
  })
  .all('/users/:id', (ctx, next) => {
    // ...
  })

Additionally, router.all() can be used to match against all methods. router.del() is an alias for router.delete().

When a route is matched, its path is available at ctx._matchedRoute and if named, the name is available at ctx._matchedRouteName.

Route paths will be translated to regular expressions using path-to-regexp.

Query strings will not be considered when matching requests.

Allowed Methods

The router can respond to the OPTIONS request with the allow header.

Example with Boom

const app = new Goa()
const router = new Router()

app.use(router.routes())
app.use(router.allowedMethods({
  throw: true,
  notImplemented: () => new Boom.notImplemented(),
  methodNotAllowed: () => new Boom.methodNotAllowed(),
}))

AllowedMethodsOptions: The options for the allowedMethods middleware generation.

Name Type Description
throw boolean Throw error instead of setting status and header.
notImplemented () => !Error Throw the returned value in place of the default NotImplemented error.
methodNotAllowed () => !Error Throw the returned value in place of the default MethodNotAllowed error.

Named Routes

Routes can optionally have names. This allows generation of URLs and easy renaming of URLs during development.

router.get('user', '/users/:id', (ctx, next) => {
  // ...
})

router.url('user', 3)
// => "/users/3"

Multiple Middleware

Multiple middleware may be passed to the router.

router.get(
  '/users/:id',
  async (ctx, next) => {
    const user = await User.findOne(ctx.params.id)
    ctx.user = user
    await next()
  },
  ctx => {
    console.log(ctx.user)
    // => { id: 17, name: "Alex" }
  }
)

Nested Routes

It's possible to create a Router instance, and then pass another Router instance to its .use call to nest the two.

Source Output
const forums = new Router()
const posts = new Router()

posts.get('/', (ctx) => {
  ctx.body = ctx.params
})
posts.get('/:pid', (ctx) => {
  ctx.body = ctx.params
})
forums.use('/forums/:fid/posts',
  posts.routes(),
  posts.allowedMethods())

goa.use(forums.routes())
// GET /forums/123/posts
{ fid: '123' }

// GET /forums/123/posts/123
{ fid: '123', pid: '123' }

Router Prefixes

Route paths can be prefixed at the router level.

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

router.get('/', (ctx) => {
  // responds to "/users"
  ctx.body = ctx.params
})
router.get('/:id', (ctx) => {
  // responds to "/users/:id"
  ctx.body = ctx.params
})

goa.use(router.routes())
// Request /users
{}
// Request /users/123
{ id: '123' }

URL Parameters

Named route parameters are captured and added to ctx.params.

const router = new Router()

router.get('/:category/:title', (ctx) => {
  // the params are exposed to the context.
  ctx.body = ctx.params
})

goa.use(router.routes())
// Request /programming/how-to-node
{ category: 'programming', title: 'how-to-node' }

Copyright & License

GNU Affero General Public License v3.0

Original Work by Alexander C. Mingoia under MIT License found in COPYING.

There's also a fork in the Koa org.

idiocc © Idio 2019

Package Sidebar

Install

npm i @goa/router

Homepage

www.idio.cc/

Weekly Downloads

5

Version

1.2.0

License

AGPL-3.0

Unpacked Size

229 kB

Total Files

31

Last publish

Collaborators

  • zvr