feat: add asyncHandler decorator for route error handling

This commit is contained in:
Kirill
2026-05-27 21:33:56 +05:00
parent d254c3c813
commit 36e75ab24a
2 changed files with 45 additions and 0 deletions
@@ -0,0 +1,33 @@
import { describe, it, expect, vi } from 'vitest'
import { asyncHandler } from '../async-handler.js'
describe('asyncHandler', () => {
it('calls the handler and returns result on success', async () => {
const handler = vi.fn().mockResolvedValue({ hello: 'world' })
const request = {}
const reply = { code: vi.fn().mockReturnThis(), send: vi.fn() }
const result = await asyncHandler(handler)(request, reply)
expect(handler).toHaveBeenCalledWith(request, reply)
expect(result).toEqual({ hello: 'world' })
})
it('catches errors and sends 500 with generic message', async () => {
const handler = vi.fn().mockRejectedValue(new Error('boom'))
const request = { log: { error: vi.fn() } }
const reply = { code: vi.fn().mockReturnThis(), send: vi.fn() }
await asyncHandler(handler)(request, reply)
expect(reply.code).toHaveBeenCalledWith(500)
expect(reply.send).toHaveBeenCalledWith({ error: 'Internal server error' })
})
it('uses statusCode from error object when present', async () => {
const err = new Error('Not found')
err.statusCode = 404
const handler = vi.fn().mockRejectedValue(err)
const request = { log: { error: vi.fn() } }
const reply = { code: vi.fn().mockReturnThis(), send: vi.fn() }
await asyncHandler(handler)(request, reply)
expect(reply.code).toHaveBeenCalledWith(404)
expect(reply.send).toHaveBeenCalledWith({ error: 'Not found' })
})
})
+12
View File
@@ -0,0 +1,12 @@
export function asyncHandler(fn) {
return async (request, reply) => {
try {
return await fn(request, reply)
} catch (err) {
request.log.error(err)
const statusCode = err.statusCode || 500
const message = err.statusCode ? err.message : 'Internal server error'
return reply.code(statusCode).send({ error: message })
}
}
}