Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 22 additions & 12 deletions src/server/factories/route_finder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,29 @@ export function routeFinder(
* @returns Promise that resolves when route execution completes or rejects with route not found error
*/
return function () {
const url = ctx.request.url()
const method = ctx.request.method()
const hostname = router.usingDomains ? ctx.request.hostname() : undefined
const route = router.match(url, method, ctx.request.parsedUrl.shouldDecodeParam, hostname)
/**
* Sync errors (for example, from a matcher cast) are returned as a
* rejected promise. The middleware runner does not catch a sync
* error from its final handler, so without global middleware the
* error would skip the app error handler.
*/
try {
const url = ctx.request.url()
const method = ctx.request.method()
const hostname = router.usingDomains ? ctx.request.hostname() : undefined
const route = router.match(url, method, ctx.request.parsedUrl.shouldDecodeParam, hostname)

if (route) {
ctx.params = route.params
ctx.subdomains = route.subdomains
ctx.route = route.route
ctx.routeKey = route.routeKey
return route.route.execute(route.route, resolver, ctx, errorResponder)
}
if (route) {
ctx.params = route.params
ctx.subdomains = route.subdomains
ctx.route = route.route
ctx.routeKey = route.routeKey
return route.route.execute(route.route, resolver, ctx, errorResponder)
}

return Promise.reject(new errors.E_ROUTE_NOT_FOUND([method, url]))
return Promise.reject(new errors.E_ROUTE_NOT_FOUND([method, url]))
} catch (error) {
return Promise.reject(error)
}
}
}
36 changes: 36 additions & 0 deletions tests/server.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1080,6 +1080,42 @@ test.group('Server | error handler', () => {
assert.equal(text, 'handled by error handler')
})

test('pass route matching errors to the error handler', async ({ assert }) => {
const app = new AppFactory().create(BASE_URL, () => {})
const server = new ServerFactory().merge({ app }).create()
const httpServer = createServer(server.handle.bind(server))
await app.init()

class ErrorHandler {
report() {}
handle(error: any, { response }: HttpContext) {
response.status(422).send(`handled by error handler: ${error.message}`)
}
}

server.use([])

server.errorHandler(async () => {
return {
default: ErrorHandler,
}
})

server
.getRouter()
.get('/:id', () => 'ok')
.where('id', {
match: /.*/,
cast: () => {
throw new Error('Invalid id')
},
})
await server.boot()

const { text } = await supertest(httpServer).get('/1').expect(422)
assert.equal(text, 'handled by error handler: Invalid id')
})

test('report response serialization errors', async ({ assert }) => {
const app = new AppFactory().create(BASE_URL, () => {})
const server = new ServerFactory().merge({ app }).create()
Expand Down
Loading