(handler: RouteHandler<T>)
| 45 | * - Attaches `x-request-id` response header |
| 46 | */ |
| 47 | export function withRouteHandler<T>(handler: RouteHandler<T>): RouteHandler<T> { |
| 48 | return async (request: NextRequest, context: T) => { |
| 49 | const requestId = generateRequestId() |
| 50 | const startTime = Date.now() |
| 51 | const method = request?.method ?? 'UNKNOWN' |
| 52 | const path = |
| 53 | request?.nextUrl?.pathname ?? new URL(request?.url ?? '/', 'http://localhost').pathname |
| 54 | |
| 55 | return runWithRequestContext({ requestId, method, path }, async () => { |
| 56 | let response: NextResponse | Response |
| 57 | try { |
| 58 | response = await handler(request, context) |
| 59 | } catch (error) { |
| 60 | const duration = Date.now() - startTime |
| 61 | const message = getErrorMessage(error, 'Unknown error') |
| 62 | const typedStatus = readTypedErrorStatus(error) |
| 63 | if (typedStatus !== undefined) { |
| 64 | if (typedStatus >= 500) { |
| 65 | logger.error('Unhandled route error', { duration, status: typedStatus, error: message }) |
| 66 | } else { |
| 67 | logger.warn('Typed route error', { duration, status: typedStatus, error: message }) |
| 68 | } |
| 69 | response = NextResponse.json({ error: message, requestId }, { status: typedStatus }) |
| 70 | } else { |
| 71 | logger.error('Unhandled route error', { duration, error: message }) |
| 72 | response = NextResponse.json( |
| 73 | { error: 'Internal server error', requestId }, |
| 74 | { status: 500 } |
| 75 | ) |
| 76 | } |
| 77 | response?.headers?.set('x-request-id', requestId) |
| 78 | return response |
| 79 | } |
| 80 | |
| 81 | const status = response?.status ?? 0 |
| 82 | const duration = Date.now() - startTime |
| 83 | |
| 84 | if (status >= 500) { |
| 85 | logger.error('Server error response', { status, duration }) |
| 86 | } else if (status >= 400) { |
| 87 | logger.warn('Client error response', { status, duration }) |
| 88 | } else if (status > 0) { |
| 89 | logger.info('OK', { status, duration }) |
| 90 | } |
| 91 | |
| 92 | response?.headers?.set('x-request-id', requestId) |
| 93 | return response |
| 94 | }) |
| 95 | } |
| 96 | } |
no test coverage detected