itty-router
Advanced tools
Comparing version 0.8.2 to 0.9.1
@@ -1,18 +0,30 @@ | ||
const Router = () => new Proxy({}, { | ||
get: (o, k) => k === 'handle' | ||
? (c) => { | ||
for ([r, h] of o[(c.method || 'GET').toLowerCase()] || []) { | ||
if (m = (u = new URL(c.url)).pathname.match(r)) { | ||
return h(Object.assign(c, { | ||
params: m.groups, | ||
query: Object.fromEntries(u.searchParams.entries()) | ||
})) | ||
const Router = () => | ||
new Proxy({}, { | ||
get: (o, k) => k === 'handle' | ||
? async (c) => { | ||
for ([r, hs] of o[(c.method || 'GET').toLowerCase()] || []) { | ||
if (m = (u = new URL(c.url)).pathname.match(r)) { // r matched | ||
Object.assign(c, { | ||
params: m.groups, | ||
query: Object.fromEntries(u.searchParams.entries()), | ||
}) | ||
for (h of hs) { | ||
if ((response = await h(c)) !== undefined) return response | ||
} | ||
} | ||
} | ||
} | ||
} : (p, h) => | ||
(o[k] = o[k] || []).push([`^${p.replace('*', '.*').replace(/(\/:([^\/\?]+)(\?)?)/gi, '/$3(?<$2>[^\/]+)$3')}$`, h]) && o | ||
}) | ||
: (p, ...hs) => | ||
(o[k] = o[k] || []).push([ | ||
`^${p | ||
.replace('*', '.*') | ||
.replace(/(\/:([^\/\?]+)(\?)?)/gi, '/$3(?<$2>[^/]+)$3')}$`, | ||
hs, | ||
]) && o, | ||
} | ||
) | ||
module.exports = { | ||
Router | ||
} | ||
Router, | ||
} |
@@ -1,1 +0,1 @@ | ||
const e=()=>new Proxy({},{get:(e,a)=>"handle"===a?a=>{for([r,h]of e[(a.method||"GET").toLowerCase()]||[])if(m=(u=new URL(a.url)).pathname.match(r))return h(Object.assign(a,{params:m.groups,query:Object.fromEntries(u.searchParams.entries())}))}:(r,t)=>(e[a]=e[a]||[]).push([`^${r.replace("*",".*").replace(/(\/:([^\/\?]+)(\?)?)/gi,"/$3(?<$2>[^/]+)$3")}$`,t])&&e});module.exports={Router:e}; | ||
const e=()=>new Proxy({},{get:(e,s)=>"handle"===s?async s=>{for([r,hs]of e[(s.method||"GET").toLowerCase()]||[])if(m=(u=new URL(s.url)).pathname.match(r))for(h of(Object.assign(s,{params:m.groups,query:Object.fromEntries(u.searchParams.entries())}),hs))if(void 0!==(response=await h(s)))return response}:(r,...o)=>(e[s]=e[s]||[]).push([`^${r.replace("*",".*").replace(/(\/:([^\/\?]+)(\?)?)/gi,"/$3(?<$2>[^/]+)$3")}$`,o])&&e});module.exports={Router:e}; |
{ | ||
"name": "itty-router", | ||
"version": "0.8.2", | ||
"version": "0.9.1", | ||
"description": "Tiny, zero-dependency router with route param and query parsing.", | ||
@@ -5,0 +5,0 @@ "main": "dist/itty-router.min.js", |
@@ -30,2 +30,3 @@ ![image](https://user-images.githubusercontent.com/865416/79531114-fa0d8200-8036-11ea-824d-70d84164b00a.png) | ||
- [x] chainable route declarations (why not?) | ||
- [x] multiple (sync or async) handlers for passthrough logic | ||
- [ ] have pretty code (yeah right...) | ||
@@ -67,19 +68,2 @@ | ||
### Within a Cloudflare Function | ||
```js | ||
import { Router } from 'itty-router' | ||
// create a router | ||
const router = Router() // note the intentional lack of "new" | ||
// register some routes | ||
router | ||
.get('/foo', () => new Response('Foo Index!')) | ||
.get('/foo/:id', ({ params }) => new Response(`Details for item ${params.id}.`)) | ||
.get('*', () => new Response('Not Found.', { status: 404 }) | ||
// attach the router handle to the event handler | ||
addEventListener('fetch', event => event.respondWith(router.handle(event.request))) | ||
``` | ||
# Usage | ||
@@ -94,5 +78,6 @@ ### 1. Create a Router | ||
### 2. Register Route(s) | ||
##### `.methodName(route:string, handler:function)` | ||
The "instantiated" router translates any attribute (e.g. `.get`, `.post`, `.patch`, `.whatever`) as a function that binds a "route" (string) to a route handler (function) on that method type. When the url fed to `.handle({ url })` matches the route and method, the handler is fired with the original request/context, with the addition of any parsed route/query params. This 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). | ||
##### `.{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). | ||
```js | ||
// register a route on the "GET" method | ||
router.get('/todos/:user/:item?', (req) => { | ||
@@ -108,3 +93,3 @@ let { params, query, url } = req | ||
##### `.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()`). | ||
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. | ||
```js | ||
@@ -120,2 +105,46 @@ router.handle({ | ||
# Examples | ||
### Within a Cloudflare Function | ||
```js | ||
import { Router } from 'itty-router' | ||
// create a router | ||
const router = Router() // note the intentional lack of "new" | ||
// register some routes | ||
router | ||
.get('/foo', () => new Response('Foo Index!')) | ||
.get('/foo/:id', ({ params }) => new Response(`Details for item ${params.id}.`)) | ||
.get('*', () => new Response('Not Found.', { status: 404 }) | ||
// attach the router handle to the event handler | ||
addEventListener('fetch', event => event.respondWith(router.handle(event.request))) | ||
``` | ||
### Multiple Route Handlers as Middleware | ||
```js | ||
import { Router } from 'itty-router' | ||
// create a router | ||
const router = Router() // note the intentional lack of "new" | ||
// withUser modifies original request, then continues without returning | ||
const withUser = (req) => req.user = { name: 'Mittens', age: 3 } | ||
// requireUser optionally returns (early) if user not found on request | ||
const requireUser = (req) => { | ||
if (!req.user) return new Response('Not Authenticated', { status: 401 }) | ||
} | ||
// showUser returns a response with the user, as it is assumed to exist at this point | ||
const showUser = (req) => new Response(JSON.stringify(req.user)) | ||
router | ||
.get('/pass/user', withUser, requireUser, showUser) // withUser injects user, allowing requireUser to not return/continue | ||
.get('/fail/user', requireUser, showUser) // requireUser returns early because req.user doesn't exist | ||
router.handle({ url: 'https://example.com/pass/user' }) // --> STATUS 200: { name: 'Mittens', age: 3 } | ||
router.handle({ url: 'https://example.com/fail/user' }) // --> STATUS 401: Not Authenticated | ||
``` | ||
## Testing & Contributing | ||
@@ -156,2 +185,3 @@ 1. fork repo | ||
- **v0.9.0** - added support for multiple handlers (middleware) | ||
- **v0.8.0** - deep minification pass and build steps for final module | ||
@@ -158,0 +188,0 @@ - **v0.7.0** - removed { path } from request handler context, travis build fixed, added coveralls, improved README docs |
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
11577
30
185