게임 서버 개발을 하면서 미들웨어와 에러 핸들러는 너무나도 중요한 개념인 것 같아서 다시 공부하게 되었습니다.
1. 미들웨어 (Middleware)
-> 1) 미들웨어 기본 개념
-> 미들웨어란 웹 서버에서 요청을 받을때, 모든 요청에 대한 공통적인 처리를 하고 싶을 수 있습니다. 이 때 필요한 것이 바로 미들 웨어 입니다. 여기서 미들웨어는 서버의 요청 - 응답 과정에서 중간에 위치하여 특정 기능을 수행하는 함수라고 보면 됩니다. 예를 들어, 모든 요청에 대해서 로그를 남기거나, 특정 사용자만 API를 접근(Authentication & Authorization)하게 하고 싶을 때도 미들 웨어를 사용합니다. 또한, 사용자가 웹 페이지에서 Form을 통해 전송한 데이터를 서버에서 쉽게 파싱(Body Parser)하여 사용할 수 있게 해주는 미들웨어도 존재합니다.
-> Express.js의 미들웨어에는 어떤게 있나? 여기서 Express.js의 특징 중 하나인 미들웨어의 지원이 있습니다. 미들 웨어는 Express.js의 핵심 기능 중 하나로, 여러가지 기능을 제공합니다. 예를 들어 Body Parser는 클라이언트의 요청 본문 데이터인 body를 쉽게 파싱할 수 있게 해주는 미들웨어입니다.
app.use(express.urlencoded({ extended: false }));
app.use(express.json());
-> 위에서 urlencoded는 form-urlencoded 라는 규격의 body를 손쉽게 코드에서 사용할 수 있게 도와주는 미들웨어입니다.
-> json: JSON 이라는 규격의 body 데이터를 손쉽게 코드에서 사용할 수 있게 도와주는 미들웨어입니다.
-> 2) 미들웨어는 어떤 경우에 사용하는게 적합한가?
-> 인증 미들웨어로 예를 들면 사용자가 로그인 상태인지 확인하고, 로깅 미들웨어는 클라이언트의 요청에 대한 정보를 기록하며, 에러 핸들링 미들웨어는 에러를 처리하게됩니다.
-> 3) Router와 미들웨어의 차이
-> Router와 미들웨어는 서로 다른 방식처럼 보이지만 Router는 미들웨어 기반으로 구현된 객체이므로 미들웨어와 동일한 방식으로 작동됩니다.
-> 즉, Router는 미들웨어 함수를 특정 경로에 바인딩하는 역할을 하며, 요청이 들어온 URL 경로에 따라 서로 다른 미들웨어를 실행시킬 수 있게 도와줍니다.
-> 4) 자주쓰이는 미들웨어 사용 해석
-> app.use(Middleware) : 모든 요청에서 미들웨어가 실행된다.
-> app.use('/api', Middleware) : /api로 시작하는 모든 요청에서 미들웨어를 실행한다.
-> app.post('/api', Middleware, (req, res, next) => {} ) : /api로 시작하는 POST 요청에서 미들웨어를 실행한다.
2. 데이터 유효성 검증 라이브러리 Joi
-> Joi란?
-> Joi는 JavaScript 유효성 검증을 위한 라이브러리입니다. Joi는 여러 타입과 규칙을 이용해 유효성을 검증할 수 있으며, 유효성 검증에 실패하면 오류를 발생시킵니다.
-> 실제로 요구사항을 토대로 코드를 보면 이해가 쉽습니다.
1. Joi 설치하기
2. Joi를 이용한 Validation 시작하기
3. 문자열 길이 검증하기
4. 이메일 검증하기
5. 비동기로 문자열 길이 검증하기
6. try/catch 설정하기
👉 **할 일 생성 API 유효성 검사 요구사항**
1. `value` 데이터는 **필수적으로 존재**해야한다.
2. `value` 데이터는 **문자열 타입**이어야한다.
3. `value` 데이터는 **최소 1글자 이상**이어야한다.
4. `value` 데이터는 **최대 50글자 이하**여야한다.
5. 유효성 검사에 실패했을 때, 에러가 발생해야한다.
# yarn을 이용해 Joi를 설치합니다.
yarn add joi
import Joi from 'joi';
// 할 일 생성 API의 요청 데이터 검증을 위한 Joi 스키마를 정의합니다.
const createTodoSchema = Joi.object({
value: Joi.string().min(1).max(50).required(),
});
router.post('/todos', async (req, res) => {
try {
// 클라이언트에게 전달받은 데이터를 검증합니다.
const validateBody = await createTodoSchema.validateAsync(req.body);
// 클라이언트에게 전달받은 value 데이터를 변수에 저장합니다.
const { value } = validateBody;
// Todo모델을 사용해, MongoDB에서 'order' 값이 가장 높은 '해야할 일'을 찾습니다.
const todoMaxOrder = await Todo.findOne().sort('-order').exec();
// 'order' 값이 가장 높은 도큐멘트의 1을 추가하거나 없다면, 1을 할당합니다.
const order = todoMaxOrder ? todoMaxOrder.order + 1 : 1;
// Todo모델을 이용해, 새로운 '해야할 일'을 생성합니다.
const todo = new Todo({ value, order });
// 생성한 '해야할 일'을 MongoDB에 저장합니다.
await todo.save();
return res.status(201).json({ todo });
} catch (error) {
console.error(error);
// Joi 검증에서 에러가 발생하면, 클라이언트에게 에러 메시지를 전달합니다.
if (error.name === 'ValidationError') {
return res.status(400).json({ errorMessage: error.message });
}
// 그 외의 에러가 발생하면, 서버 에러로 처리합니다.
return res
.status(500)
.json({ errorMessage: '서버에서 에러가 발생하였습니다.' });
}
});
폴더 구조를 위한 간단한 용어 정리
- app.js
- 전체 어플리케이션의 시작점입니다.
- 미들웨어(Middleware)와 라우터(Router)를 등록하며, 서버를 시작하는 역할을 담당합니다.
- middlewares
- 미들웨어를 정의하기 위해 사용합니다.
- 에러 핸들러, 로깅, 사용자 인증과 같은 미들웨어를 이 폴더에서 관리합니다.
- routes
- Express.js의 라우터(Router)를 관리하기 위해 사용합니다.
- 각 API 경로를 정의하며, 해당 경로에서 실행될 함수를 관리하는 역할을 담당합니다.
- schemas
- MongoDB를 사용하기 위한 mongoose의 스키마(Schema) 및 **모델(Model)**을 정의하기 위해 사용합니다.
- MongoDB 데이터의 구조와 데이터를 처리할 메서드를 정의하는 역할을 담당합니다.
- assets
- 프론트엔드 파일을 서빙하기 위해 사용하는 폴더입니다.
- 웹페이지를 구성하는 HTML, CSS, JavaScript 파일, 이미지 등 여러 파일들이 이 폴더에 위치하게 됩니다.
'TIL' 카테고리의 다른 글
초보자를 위한 깃허브 팀원끼리 연결, PullRequest, Merge 하는 법 (feat. SubBranch, VSCODE) (0) | 2024.09.19 |
---|---|
OSI 7계층 중 전송 계층에 대하여 (0) | 2024.09.11 |
OSI 7계층 네트워크 계층에 대하여 (IP의 개념, 서브넷 마스크, 동적 IP 주소, 라우팅) (0) | 2024.09.09 |
Sparta 챌린지 반 - 기본 실력 체크 2탄 (1) | 2024.09.06 |
Sparta 챌린지 반 - 기본 실력 체크 1탄 (0) | 2024.09.05 |