npm package: @ramverk/router
Description: Node compatible HTTP router for Javascript
Author: Tobias Sandelius
Latest version: 0.0.4

# Router

HTTP router for Node.js.

## Status

Under development, not ready for prime-time just yet.

[![Build Status](https://travis-ci.org/ramverk/router.svg?branch=master)](https://travis-ci.org/ramverk/router)
[![Coverage Status](https://coveralls.io/repos/github/ramverk/router/badge.svg?branch=master)](https://coveralls.io/github/ramverk/router?branch=master)
[![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)

## Installation

```
$ npm install @ramverk/router
```

## Usage

Basic usage

```js
const http = require('http')
const { Router } = require('@ramverk/router')

const router = new Router({}, (router) => {
  router.get('/', (req, res, err) => {
    res.end('Hello World')
  })

  router.get('/books/:id', (req, res, err) => {
    const notFound = new Error(`These aren't the droids you're looking for.`)
    notFound.status = 404

    return err(notFound)
  })
})

const handler = router.createHandler()

http.createServer(handler)
    .listen(3000)
```

### Array describing routes

```js
const { Router } = require('@ramverk/router')

const routes = [
  { method: 'GET', path: '/books', endpoint: 'books.index', as: 'books' },
  { method: 'GET', path: '/books/:id', endpoint: 'books.show', as: 'book' },
  { method: 'POST', path: '/books', endpoint: 'books.create' }
]

const router = new Router({ routes })
````

### HTTP verbs

The router supports most of the verbs available.

```js
const { Router } = require('@ramverk/router')

const router = new Router({}, (router) => {
  router.get('/', (req, res, err) => {})
  router.post('/', (req, res, err) => {})
  router.put('/', (req, res, err) => {})
  router.patch('/', (req, res, err) => {})
  router.delete('/', (req, res, err) => {})
  router.options('/', (req, res, err) => {})
  router.head('/', (req, res, err) => {})
  router.trace('/', (req, res, err) => {})
})
```

### Named parameters

In the example `:title` is a *named parameter*. The values are accessible via `req, res, err.request.params` and it contains a `Object<String, String>`.

```js
const { Router } = require('@ramverk/router')

const router = new Router({}, (router) => {
  router.get('/books/:title', (req, res, err) => {})
})
```

Named parameters only match a single path segment:

```
/books/eloquent-javascript          match
/books/confident-javascript         match
/books/confident-javascript.js      no match
/books/eloquent-javascript/reviews  no match
/books                              no match
```

### Catch-All parameters

*catch-all* parameters have the form `*title`. Like the name suggests, they match everything, event new `/` segments. Therefore they must always be at the end of the pattern.

```js
const { Router } = require('@ramverk/router')

const router = new Router({}, (router) => {
  router.get('/books/*title', (req, res, err) => {})
})
```

```
/books/eloquent-javascript          match
/books/confident-javascript         match
/books/confident-javascript.js      match
/books/eloquent-javascript/reviews  match
/books                              no match
```

### Optional segments

Support for optional segments have the form `(i-am-optional)`.

```js
const { Router } = require('@ramverk/router')

const router = new Router({}, (router) => {
  router.get('/books(/:title)', (req, res, err) => {})
})
```

```
/books/eloquent-javascript          match
/books/confident-javascript         match
/books/confident-javascript.js      no match
/books/eloquent-javascript/reviews  no match
/books                              match
```

### Redirects

Make legacy paths point to a new destination.

```js
const { Router } = require('@ramverk/router')

const router = new Router({}, (router) => {
  router.redirect('/legacy-path', '/new-path')
})
```

### Named routes

```js
const { Router } = require('@ramverk/router')

const router = new Router({ scheme: 'https', host: 'ramverk.org' }, (router) => {
  router.get('/books/:id', (req, res, err) => {}, { as: 'book' })
})

router.path('book', { id: 5 }) // => '/books/5'
router.url('book', { id: 5 })  // => 'https://ramverk.org/books/5'
```

### Scoped routes

```js
const { Router } = require('@ramverk/router')

const router = new Router({}, (router) => {
  router.scope({ path: 'animals', as: 'animals' }, (router) => {
    router.scope({ path: 'mammals', as: 'mammals' }, (router) => {
      router.get('/cats', () => {}, { as: 'cats' })
    })
  })
})

router.path('animals-mammals-cats') // => '/animals/mammals/cats'
```

### Endpoints

The resolver supports multiple types of endpoints.

1. The closure

  ```js
  router.get('/books', (req, res, error) => {
    // ...
  })
  ```

2. The Controller.action

  ```js
  // books.js
  class Books {
    index (req, res, error) {
      // ...
    }
  }

  router.get('/books', 'books.index')
  ```

3. The Action

  ```js
  // books/index.js
  class Index {
    action (req, res, error) {
      // ...
    }
  }

  router.get('/books', 'books/index')
  ```

String endpoints uses a root path to locate files. By default it's set to `process.cwd()` but can be changed using the `root:` key in constructor options.

## Release

```
$ git tag X.X.X
$ npm run release
```

## Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/ramverk/router. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.