diff --git a/week07/keyword/keyword.md b/week07/keyword/keyword.md new file mode 100644 index 0000000..956a539 --- /dev/null +++ b/week07/keyword/keyword.md @@ -0,0 +1,30 @@ +## 핵심 키워드 + +- 미들웨어 + + 요청과 응답 사이에서 실행되는 함수 + + 요청을 가로채서 로깅, 인증, 데이터 변환 등의 작업을 수행한 후 다음 단계로 전달함 + + ```jsx + app.use((req, res, next) => { + console.log('요청 받음'); + next(); // 다음 미들웨어로 + }); + ``` + +- HTTP 상태 코드 + + 서버의 응답 상태를 나타내는 3자리 숫자 + + - **2xx (성공)**: 200 OK, 201 Created + - **3xx (리다이렉션)**: 301 Moved Permanently, 302 Found + - **4xx (클라이언트 에러)**: 400 Bad Request, 401 Unauthorized, 404 Not Found + - **5xx (서버 에러)**: 500 Internal Server Error, 503 Service Unavailable +- 에러 핸들링(Error Handling) + + 프로그램 실행 중 발생하는 오류를 처리하는 방법 + + - **try-catch**: 예외를 잡아서 처리 + - **에러 미들웨어**: Express에서 전역 에러 처리 + - **Promise rejection**: `.catch()` 또는 `try-catch with async/await` \ No newline at end of file diff --git a/week07/mission/mission.md b/week07/mission/mission.md new file mode 100644 index 0000000..a36b6b2 --- /dev/null +++ b/week07/mission/mission.md @@ -0,0 +1,79 @@ +## 미션 기록 + +### 성공 응답 및 에러 처리 + +```jsx +export const handleAddUserMission = async (req, res, next) => { + try { + const dto = createUserMissionDto(req.body); + const userMission = await addUserMission(dto); + res.status(StatusCodes.CREATED).success(userMission); + } catch (err) { + next(err); + } +}; + +export const handleListUserMissionsInProgress = async (req, res) => { + const usermissions = await listUserMissionsInProgress( + parseInt(req.params.userId), + typeof req.query.cursor === "string" ? parseInt(req.query.cursor) : 0 + ); + res.status(StatusCodes.OK).success(usermissions); +}; + +``` + +POST api (생성) + +- 성공 시 201(CREATED) +- 에러 발생 시 catch(err)로 들어옴 +- catch 블록에서 next(err) 호출 시 Express가 전역 에러 핸들러로 이동(app.use) +- 전역 에러 핸들러에서는 res.error(…)를 통해 클라이언트에 최종 JSON 응답 반환 + +GET api (조회) + +- 성공 시 200(OK) + +응답 형식 + +- 성공 응답: `res.success(data)` +- 실패 응답: `res.error({ errorCode, reason, data })` + +--- + +서비스 내부 동작 + +```jsx +export const addUserMission = async (data) => { + const mission = await getMissionById(data.missionId); + if (!mission) throw new MissionError("해당 미션이 존재하지 않습니다.", data); + + const existing = await getUserMission(data.userId, data.missionId); + if (existing) throw new DuplicateMissionError("이미 도전 중인 미션입니다.", data); + + const userMissionId = await insertUserMission(data); + + const userMission = await getUserMissionById(userMissionId); + return userMission; +}; +``` + +각 서비스 내부에서 에러 발생 시 throw new CustomError() 형태로 커스텀 에러를 던짐 + +에러 발생 시 호출한 컨트롤러의 try-catch 블록으로 전달됨 → next(err) 호출 + +커스텀 에러 + +```jsx +export class DuplicateMissionError extends Error { + errorCode = "M002"; + + constructor(reason, data) { + super(reason); + this.reason = reason; + this.data = data; + } +} +``` + +. \ No newline at end of file