@goa/router
v1.2.0
Published
The Router For Creating Middleware For Goa Apps.
Downloads
16
Readme
@goa/router
@goa/router
is The Router For Creating Middleware For Goa Apps.
yarn add @goa/router
Table Of Contents
- Table Of Contents
- API
- Verbs
- Allowed Methods
- Named Routes
- Multiple Middleware
- Nested Routes
- Router Prefixes
- URL Parameters
- Copyright & License
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.
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.
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())
Generate URL from url pattern and given params
.
const url = Router.url('/users/:id', { id: 1 })
// => "/users/1"
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())
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()
})
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 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())
Set the path prefix for a Router instance that was already initialized.
router.prefix('/things/:thing_id')
| 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.
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.