3부: Express 오류 처리 방법: 중앙 집중식 오류 처리
이전 글:
https://johnny-developer-story.tistory.com/13
이 글에서는 Express.js 애플리케이션에서 중앙 집중식으로 오류를 처리하는 방법을 자세히 설명합니다.
1. 중앙 집중식 오류 처리의 필요성
대규모 애플리케이션에서는 오류 처리를 중앙 집중식으로 관리하는 것이 좋습니다. 이렇게 하면 코드의 재사용성을 높이고, 오류 처리 로직을 한 곳에서 관리할 수 있어 유지보수가 용이해집니다.
2. 중앙 집중식 오류 처리 예제
중앙 집중식 오류 처리를 위해 별도의 모듈로 오류 처리 미들웨어를 정의하고 이를 애플리케이션에 사용합니다.
예제: 중앙 집중식 오류 처리 모듈
다음은 errorHandler.ts
파일에 중앙 집중식 오류 처리 미들웨어를 정의하고 이를 app.ts
에서 사용하는 예제입니다.
//CustomErrorContent.ts
export type CustomErrorContent = {
message: string
context?: { [key: string]: any }
}
//CustomError.ts
export abstract class CustomError extends Error {
abstract readonly statusCode: number
abstract readonly errors: CustomErrorContent[]
abstract readonly logging: boolean
constructor(message: string) {
super(message)
// Only because we are extending a built in class
Object.setPrototypeOf(this, CustomError.prototype)
}
}
// errorHandler.ts
export const errorHandler = (err: Error, _: Request, res: Response, next: NextFunction) => {
// Handled errors
if (err instanceof CustomError) {
const { statusCode, errors, logging } = err
if (logging) {
console.error(
JSON.stringify(
{
code: err.statusCode,
errors: err.errors,
stack: err.stack,
},
null,
2,
),
)
}
return res.status(statusCode).json({ errors })
}
if (err instanceof ZodError) {
console.error(JSON.stringify(err, null, 2))
return res.status(400).json({
message: 'Invalid request data',
errors: err,
})
}
if (err instanceof Error) {
if (err.name === 'ENOENT') {
return res.status(404).json({ message: 'File not found' })
}
console.error(JSON.stringify(err, null, 2))
return res.status(500).json({ message: err.message })
}
// Unhandled errors
console.error(JSON.stringify(err, null, 2))
return res.status(500).json(String(err))
}
// app.ts
const express = require('express');
const errorHandler = require('./errorHandler');
const app = express();
// 경로 및 미들웨어 설정
app.get('/', (req, res) => {
res.send('Hello World');
});
app.get('/error', (req, res, next) => {
next(new Error('This is a forced error.'));
});
// 중앙 집중식 오류 처리 미들웨어 사용
app.use(errorHandler);
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
위 예제에서 errorHandler.ts 파일은 모든 오류를 처리하는 미들웨어를 정의합니다. app.ts에서는 이 미들웨어를 app.use를 통해 애플리케이션에 적용하여 중앙 집중식으로 오류를 처리합니다.
3. 중앙 집중식 오류 처리의 이점
코드 재사용성
중앙 집중식 오류 처리를 사용하면 동일한 오류 처리 로직을 여러 곳에서 반복할 필요가 없습니다. 이는 코드의 재사용성을 높여줍니다.
유지보수 용이성
모든 오류 처리 로직이 한 곳에 집중되어 있어 유지보수가 용이합니다. 오류 처리 로직을 수정해야 할 때, 한 곳만 수정하면 되기 때문에 전체 애플리케이션의 오류 처리 방식을 일관되게 유지할 수 있습니다.
일관된 오류 응답
중앙 집중식 오류 처리를 통해 애플리케이션은 일관된 형식으로 오류 응답을 반환할 수 있습니다. 이는 클라이언트가 오류를 처리하는데 도움을 주고, 디버깅을 용이하게 합니다.
4. 중앙 집중식 오류 처리와 사용자 정의 오류 클래스 결합
중앙 집중식 오류 처리와 사용자 정의 오류 클래스를 결합하여 더욱 세밀하고 일관된 오류 처리를 구현할 수 있습니다.
예제: 사용자 정의 오류 클래스와 중앙 집중식 오류 처리 결합
다음은 사용자 정의 오류 클래스를 중앙 집중식 오류 처리와 결합하여 사용하는 예제입니다.
//CustomErrorContent.ts
export type CustomErrorContent = {
message: string
context?: { [key: string]: any }
}
//CustomError.ts
export abstract class CustomError extends Error {
abstract readonly statusCode: number
abstract readonly errors: CustomErrorContent[]
abstract readonly logging: boolean
constructor(message: string) {
super(message)
// Only because we are extending a built in class
Object.setPrototypeOf(this, CustomError.prototype)
}
}
// errorHandler.ts
export const errorHandler = (err: Error, _: Request, res: Response, next: NextFunction) => {
// Handled errors
if (err instanceof CustomError) {
const { statusCode, errors, logging } = err
if (logging) {
console.error(
JSON.stringify(
{
code: err.statusCode,
errors: err.errors,
stack: err.stack,
},
null,
2,
),
)
}
return res.status(statusCode).json({ errors })
}
if (err instanceof ZodError) {
console.error(JSON.stringify(err, null, 2))
return res.status(400).json({
message: 'Invalid request data',
errors: err,
})
}
if (err instanceof Error) {
if (err.name === 'ENOENT') {
return res.status(404).json({ message: 'File not found' })
}
console.error(JSON.stringify(err, null, 2))
return res.status(500).json({ message: err.message })
}
// Unhandled errors
console.error(JSON.stringify(err, null, 2))
return res.status(500).json(String(err))
}
// BadRequestError.ts
export class BadRequestError extends CustomError {
private static readonly _statusCode = 400
private readonly _code: number
private readonly _logging: boolean
private readonly _context: { [key: string]: any }
constructor(params?: { code?: number; message?: string; logging?: boolean; context?: { [key: string]: any } }) {
const { code, message, logging } = params || {}
super(message || 'Bad request')
this._code = code || BadRequestError._statusCode
this._logging = logging || false
this._context = params?.context || {}
Object.setPrototypeOf(this, BadRequestError.prototype)
}
get errors() {
return [{ message: this.message, context: this._context }]
}
get statusCode() {
return this._code
}
get logging() {
return this._logging
}
}
// app.ts
import 'express-async-errors' // 비동기 오류를 잡아주는 라이브러리 (try/catch, next를 사용할 필요없음)
// 개발자가 작성한 코드에서 놓치는 오류를 잡아줌(예: 순서가 보장되지 않은 비동기 함수안에 동기 함수)
process.on('unhandledRejection', (reason: string, p: Promise<any>) => {
console.error(`Unhandled Rejection at: ${p}, reason: ${reason}`)
})
const express = require('express');
const errorHandler = require('./errorHandler');
const app = express();
// 경로 및 미들웨어 설정
app.get('/', (req, res) => {
res.send('Hello World');
});
app.get('/error', (req, res, next) => {
next(throw new BadRequestError({ code: 401, message: 'Unauthorized' }) );
});
// 중앙 집중식 오류 처리 미들웨어 사용
app.use(errorHandler);
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
'express-async-errors'와 unhandledRejection error는 아래 글에서 포스팅 했습니다.
https://johnny-developer-story.tistory.com/14
위 예제에서는 사용자 정의 오류 클래스를 정의하고, 중앙 집중식 오류 처리 모듈에서 이를 처리합니다. 이를 통해 애플리케이션은 더욱 명확하고 일관된 방식으로 오류를 처리할 수 있습니다.
errorhandler에서 zodError type은, zod라는 typescript에서 유효성 검사를 할 수 있는 유용한 라이브러리입니다. 기회가 된다면 포스팅 하도록 하겠습니다.
'서버 > Express' 카테고리의 다른 글
Express 오류 처리 방법: 완벽 가이드 (0) | 2024.06.26 |
---|