itty-router
Advanced tools
Comparing version 2.1.1 to 2.1.2
{ | ||
"name": "itty-router", | ||
"version": "2.1.1", | ||
"version": "2.1.2", | ||
"description": "Tiny, zero-dependency router with route param and query parsing.", | ||
@@ -5,0 +5,0 @@ "main": "./dist/itty-router.min.js", |
@@ -24,16 +24,14 @@ ![Logo][logo-image] | ||
// GET index | ||
router.get('/todos', () => new Response('Todos Index!')) | ||
// register some routes | ||
router | ||
.get('/todos', () => new Response('Todos Index!')) // GET index | ||
.get('/todos/:id', request => new Response(`Todo #${request.params.id}`)) // GET item | ||
.delete('/todos', async request => { // POST new item | ||
const content = await request.json() | ||
// GET item with (optional) format | ||
router.get('/todos/:id.:format?', request => { | ||
const { id, format = 'csv' } = request.params | ||
return new Response('Creating a new Todo with following payload: ' + JSON.stringify(content)) | ||
}) | ||
.all('*', () => new Response('Not Found.', { status: 404 })) // 404 otherwise | ||
return new Response(`Getting todo #${id} in ${format} format.`) | ||
}) | ||
// 404/Missing as final catch-all route | ||
router.all('*', () => new Response('Not Found.', { status: 404 })) | ||
// attach the router handle to the event handler | ||
// attach the router "handle" to the event handler | ||
addEventListener('fetch', event => | ||
@@ -45,12 +43,15 @@ event.respondWith(router.handle(event.request)) | ||
# Features | ||
- [x] tiny (~450 bytes) with zero dependencies | ||
- [x] route params, with optionals (e.g. `/api/:foo/:id?.:format?`) | ||
- [x] bonus query parsing (e.g. `?page=3&foo=bar`) | ||
- [x] adds params & query to request: `{ params: { foo: 'bar' }, query: { page: '3' }}` | ||
- [x] multiple (sync or async) [middleware handlers](#middleware) per route for passthrough logic, auth, errors, etc | ||
- [x] extendable via Proxies | ||
- [x] handler functions "stop" at the first handler to return | ||
- [x] supports [nested routers](#nested-routers-with-404-handling) | ||
- [x] supports [base path](#nested-routers-with-404-handling) option to prefix all routes (useful for nested routers) | ||
- [x] chainable route declarations (why not?) | ||
- [x] Tiny (~450 bytes) with zero dependencies | ||
- [x] Full sync/async support. Use it when you need it! | ||
- [x] Route params, with optional param support (e.g. `/api/:collection/:id?`) | ||
- [x] [Format support](#file-format-support) (e.g. `/api/items.:format`) to handle things like `.csv`/`.json` within same route | ||
- [x] Query parsing (e.g. `?page=3&foo=bar` will add a `request.query` object with keys `page` and `foo`) | ||
- [x] Wildcard support for nesting, global middleware, etc. (e.g. `/api/*`) | ||
- [x] Middleware support. Any number of sync/async [middleware handlers](#middleware) may be passed to a route/wildcard. | ||
- [x] Nestable. Supports [nested routers](#nested-routers-with-404-handling) for API branching. | ||
- [x] Supports ANY method (e.g. `router.puppy('/:name', handler)` will match to method `PUPPY`) | ||
- [x] Route match to multiple methods using the ["all" channel](#nested-routers-with-404-handling) | ||
- [x] Define [base path](#nested-routers-with-404-handling) per router to prefix all routes (useful for nested routers) | ||
- [x] Extendable. Use itty as the tiny, zero-dependency internal router to more feature-rich/elaborate routers. | ||
- [x] Chainable route declarations (why not?) | ||
- [ ] have pretty code (yeah right...) | ||
@@ -75,6 +76,2 @@ | ||
##### `.{methodName}(route:string, handler1:function, handler2:function, ...)` | ||
The "instantiated" router translates any attribute (e.g. `.get`, `.post`, `.patch`, `.whatever`) as a function that binds a "route" (string) to route handlers (functions) on that method type (e.g. `router.get --> GET`, `router.post --> POST`). When the url fed to `.handle({ url })` matches the route and method, the handlers are fired sequentially. Each is given the original request/context, with any parsed route/query params injected as well. The first handler that returns (anything) will end the chain, allowing early exists from errors, inauthenticated requests, etc. This mechanism allows ANY method to be handled, including completely custom methods (we're very curious how creative individuals will abuse this flexibility!). The only "method" currently off-limits is `handle`, as that's used for route handling (see below). | ||
**Special Exception - the "all" channel:** Any routes on the "all" channel will match to ANY method (e.g. GET/POST/whatever), allowing for greater middleware support, nested routers, 404 catches, etc. | ||
```js | ||
@@ -86,3 +83,3 @@ // register a route on the "GET" method | ||
console.log('GET TODOS from', url, { user, item }) | ||
console.log({ user, item, query }) | ||
}) | ||
@@ -92,4 +89,5 @@ ``` | ||
### 3. Handle Incoming Request(s) | ||
##### `.handle(request = { method:string = 'GET', url:string })` | ||
The only requirement for the `.handle(request)` method is an object with a valid **full** url (e.g. `https://example.com/foo`). The `method` property is optional and defaults to `GET` (which maps to routes registered with `router.get()`). This method will return the first route handler that actually returns something. For async/middleware examples, please see below. | ||
##### `.handle(request: Request)` | ||
Requests should have both a **method** and full **url**. The `handle` method will then return the first matching route handler that returns something. | ||
```js | ||
@@ -101,4 +99,6 @@ router.handle({ | ||
// matched handler from step #2 (above) will execute, with the following output: | ||
// GET TODOS from https://example.com/todos/jane/13 { user: 'jane', item: '13' } | ||
// Example outputs (using route handler from step #2 above): | ||
// GET /todos/jane/13 --> { user: 'jane', item: '13', query: {} } | ||
// GET /todos/jane --> { user: 'jane', query: {} } | ||
// GET /todos/jane?limit=2&page=1 --> { user: 'jane', query: { limit: '2', page: '2' } } | ||
``` | ||
@@ -136,3 +136,4 @@ | ||
### Middleware | ||
###### Bonus: Any of these handlers may be awaitable async functions! | ||
*Any handler that does NOT return* will effectively be considered "middleware", continuing to execute future functions/routes until one returns, closing the response. | ||
```js | ||
@@ -179,2 +180,12 @@ // withUser modifies original request, but returns nothing (allowing flow to continue) | ||
### File format support | ||
```js | ||
// GET item with (optional) format | ||
router.get('/todos/:id.:format?', request => { | ||
const { id, format = 'csv' } = request.params | ||
return new Response(`Getting todo #${id} in ${format} format.`) | ||
}) | ||
``` | ||
## Testing & Contributing | ||
@@ -181,0 +192,0 @@ 1. fork repo |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
255
17190