Ch 03. 서버 미들웨어와 에러 처리
API 핸들러가 요청을 받기 전, 모든 요청을 가로채서 공통 처리를 하고 싶을 때가 있습니다. 접근 로그를 남기거나, 인증 토큰을 검사하거나, 특정 헤더를 추가하는 작업입니다. 이 역할을 서버 미들웨어가 담당합니다.
서버 미들웨어 작성
서버 미들웨어는 server/middleware/ 폴더에 파일을 만들면 됩니다. API 핸들러보다 먼저 실행되고, 반환값 없이 종료하면 다음 미들웨어 또는 핸들러로 넘어갑니다.
// server/middleware/logger.tsexport default defineEventHandler((event) => { console.log(`[${new Date().toISOString()}] ${event.method} ${event.path}`)})
이 파일을 만들면 모든 HTTP 요청마다 시각과 메서드, 경로가 콘솔에 출력됩니다. return 없이 끝나므로 요청 처리는 이어서 진행됩니다.
여러 미들웨어 파일이 있으면 파일 이름의 알파벳 순서로 실행됩니다. 01.auth.ts, 02.logger.ts처럼 앞에 번호를 붙여 실행 순서를 명확히 하는 것이 좋습니다.
createError로 HTTP 에러 던지기
Nitro에서 에러를 응답할 때는 createError를 사용합니다. HTTP 상태 코드와 메시지를 함께 설정할 수 있고, Nuxt가 자동으로 JSON 형식으로 응답합니다.
usePrisma()는 Ch 04에서 server/utils/prisma.ts로 정의합니다. 자동 임포트 덕분에 API 핸들러에서 별도 import 없이 바로 사용할 수 있습니다.
// server/api/posts/[id].tsexport default defineEventHandler(async (event) => { const id = Number(getRouterParam(event, 'id')) try { const post = await usePrisma().post.findUnique({ where: { id } }) if (!post) { throw createError({ statusCode: 404, statusMessage: '게시글을 찾을 수 없습니다.' }) } return post } catch (error) { throw createError({ statusCode: 500, statusMessage: '서버 오류가 발생했습니다.' }) }})
createError에는 세 가지 주요 옵션이 있습니다.
| 옵션 | 설명 |
|---|---|
statusCode |
HTTP 상태 코드 (404, 401, 500 등) |
statusMessage |
상태 코드와 함께 반환되는 짧은 메시지 |
data |
추가 에러 정보 (선택 사항) |
클라이언트에서 에러 처리하기
useFetch나 $fetch로 API를 호출할 때 에러가 발생하면 error 객체에 상태 코드와 메시지가 담겨 옵니다.
const { data, error } = await useFetch('/api/posts/999')if (error.value?.statusCode === 404) { console.log('게시글이 없습니다.')}
$fetch를 직접 사용할 때는 try-catch로 처리합니다.
try { const post = await $fetch('/api/posts/999')} catch (err: any) { if (err.statusCode === 404) { console.log('게시글이 없습니다.') }}
미들웨어와 createError를 조합하면 공통 인증 검사와 일관된 에러 응답을 깔끔하게 구성할 수 있습니다. 각 핸들러에서 중복 코드를 작성하는 대신 미들웨어 한 곳에서 처리하는 것이 유지보수에 훨씬 유리합니다.