76 lines
1.8 KiB
JavaScript
76 lines
1.8 KiB
JavaScript
|
const pathToRegexp = require('path-to-regexp')
|
||
|
|
||
|
class Router {
|
||
|
constructor() {
|
||
|
this.handlers = []
|
||
|
}
|
||
|
use(handler) {
|
||
|
this.handlers.push(handler)
|
||
|
return this
|
||
|
}
|
||
|
useRoute(path, handler) {
|
||
|
const keys = []
|
||
|
const re = pathToRegexp(path, keys)
|
||
|
this.use(async (req, res, next) => {
|
||
|
if (re.test(req.pathname)) {
|
||
|
const [_, ...result] = re.exec(req.pathname)
|
||
|
const params = {}
|
||
|
for (let i = 0; i < result.length; i++) {
|
||
|
params[keys[i].name] = result[i]
|
||
|
}
|
||
|
req.params = params
|
||
|
await handler(req, res, next)
|
||
|
}
|
||
|
})
|
||
|
return this
|
||
|
}
|
||
|
useRouteWithVerb(verb, path, handler) {
|
||
|
verb = verb.toUpperCase()
|
||
|
this.useRoute(path, async (req, res, next) => {
|
||
|
if (req.method === verb) {
|
||
|
await handler(req, res, next)
|
||
|
}
|
||
|
})
|
||
|
return this
|
||
|
}
|
||
|
useWithVerb(verb, handler) {
|
||
|
verb = verb.toUpperCase()
|
||
|
this.use(async (req, res, next) => {
|
||
|
if (req.method === verb) {
|
||
|
await handler(req, res, next)
|
||
|
}
|
||
|
})
|
||
|
return this
|
||
|
}
|
||
|
async handle(request) {
|
||
|
const responseCtx = {
|
||
|
body: '',
|
||
|
headers: {}
|
||
|
}
|
||
|
const requestCtx = Object.assign({}, request, new URL(request.url))
|
||
|
const createNext = n => async () => {
|
||
|
const fn = this.handlers[n]
|
||
|
if (!fn) return
|
||
|
let gotCalled = false
|
||
|
const next = createNext(n + 1)
|
||
|
await fn(requestCtx, responseCtx, () => {
|
||
|
gotCalled = true
|
||
|
return next()
|
||
|
})
|
||
|
if (!gotCalled) {
|
||
|
return next()
|
||
|
}
|
||
|
}
|
||
|
await createNext(0)()
|
||
|
return responseCtx.response ? responseCtx.response : new Response(responseCtx.body, responseCtx)
|
||
|
}
|
||
|
}
|
||
|
for (const verb of ['get', 'options', 'head']) {
|
||
|
Router.prototype[verb] = function(path, handler) {
|
||
|
if (handler) this.useRouteWithVerb(verb, path, handler)
|
||
|
else this.useWithVerb(verb, path) // when there is only 1 argument, path is handler
|
||
|
return this
|
||
|
}
|
||
|
}
|
||
|
module.exports = Router
|