핸들러와 미니 프로젝트

Younha Lee·2026년 1월 27일

TIL

목록 보기
19/67

이번 시간에는 핸들러와 조금 더 진화된 예외처리를 해보려합니다. 그리고 JS의 ===== 의 차이, 미니 프로젝트 기획과 API 설계 및 구현을 해볼 예정이에요.

핸들러(Handler)

HTTP Request가 오면 자동으로 호출되어 실행되는 메서드(Method)를 의미합니다.
Spring과 NestJS의 컨트롤러, express에서 콜백함수를 말합니다.
예시로 express에서 사용하는 get, post 등의 함수에서 url(path) 뒤에 오는 함수를 의미해요.

if문 리팩토링

클린코드적 관점에서 if문 안에는 부정을 검증하기보다 긍정을 검증하는 것이 좋다고해요.
하지만 저는 if문에서 else를 사용하는 것을 좋아하지 않아서, 보통 if문으로 부정을 검증하고 에러를 반환하는 것을 선호해요.
earyly return 패턴을 사용하면 메인 비즈니스 로직을 들여쓰기 없이 작성할 수 있고, 예외를 먼저 작성하기 때문에 else 를 찾을 필요 없다는 점에서 좋다고 생각했어요.

// Node.js의 표준 콜백 패턴
fs.readFile('file.txt', (err, data) => {
    // 1. 에러(부정적인 상황)가 있는지 먼저 확인하고 끝냄
    if (err) return console.error(err);

    // 2. 그게 아니라면(긍정적인 상황) 로직 진행
    console.log(data);
});

Node.js의 표준 패턴도 이처럼 early return 을 기반으로 작성해요.
강의에서는 else 문을 사용해서 예외처리를 하지만 저는 다르게 작성했기 때문에 근거를 여기에 남기고 싶었어요.

JS

Array의 find()

Array에 객체를 저장하는 경우 원하는 객체를 찾을 때 반복문(for문)을 사용하거나 forEach 함수를 사용해야 합니다. 하지만 그렇게 사용하면 코드가 길어질 수 있기 때문에 Array의 find() 함수를 이용하면 됩니다.

앞서 원하는 객체라고 했지만 원하는 조건에 대한 요소를 찾을 때 사용한다고 생각하시면 됩니다.

const arr = [{id:1,name:'1'},{id:2,name:'2'},{id:3,name:'3'},{id:4,name:'4'}];
let findThing;

arr.forEach(el=>{
  if(el.id === 1) findThing = el;
});

console.log(findThing); // {id:1,name:'1'}

findThing = arr.find(el=>el.id === 1);

console.log(findThing); // {id:1,name:'1'}

== vs ===

JS에서는 값을 비교할 수 있는 연산자가 두 가지 있습니다.

== : 값을 비교할 때 자료형을 신경쓰지 않는다.
=== : 값을 비교할 때 자료형까지 신경쓴다.
console.log(1 == '1'); // true
console.log(1 === '1'); // false

  • 두 연산자를 적절히 잘 활용하면 쉽게 코드를 작성할 수 있습니다.

예외처리

예외가 발생할만한 부분을 예상해서 상황에 따라 처리하는 것이 예외처리입니다.

Express에서는 조건문(if~else문)을 통해 상황을 나누어서 상황에 따라 다르게 처리할 수 있습니다. 추가적으로 응답할 때 보내는 HTTP Status Code를 개발자가 원하는 대로 조절할 수 있습니다. 이를 잘 활용한다면 예외가 발생했을 때 좀 더 쉽게 처리할 수 있어요.

// POST 책 하나 등록(생성)
app.post("/book", (req, res) => {
  const name = req.body.name;
  // 책의 이름이 필수인 경우 이름이 있는지 확인
  if (name) { 
    // 있다면 '작성됨'을 의미하는 201 코드와 함께 메시지 전송
    const id = db.size + 1;
    db.set(id, req.body);

    res.status(201).json({
      message: `add new book ${db.get(id).name}`,
      ...req.body,
    });
  } else { 
    // 없다면 '잘못된 요청'을 의미하는 400 코드와 함께 메시지 전송
    res.status(400).json({
      message: "plz check your data that you want to add",
    });
  }
});

미니 프로젝트(나만의 유튜브)

기획 & API 설계

회원(유저)

  • 로그인 : POST, '/login', req: body{email,pw} res: 200 'success'→ main page로
  • 회원가입 : POST, '/register', req: body{email,pw,nickname} res: 201'success' → login page로
  • 정보 조회 : GET, '/users/:id', req: params{id} res: 200'success'
  • 탈퇴 : DELETE, '/users/:id', req: params{id} res: 204 'success'

유튜브 채널

  • 등록: POST, '/youtubers', req: body{channelName} res: 201 'success'
  • 수정: PATCH, '/youtubers/:youtubeId', req: body{channelName} res: 200'success'
  • 삭제: DELETE, '/youtubers/:youtubeId', res: 204 'success'

구현

'/register' 회원가입

// 회원가입
app.post('/register', (req,res) => {
    const { email, password, nickname } = req.body;
    // validation
    if (!email || !password || !nickname) return res.status(400).send("모든 필드를 입력해주세요.");

    let duplicate = Array.from(db.values()).find(user => user.email === email);
    // 409 Conflict
    if (duplicate) return res.status(409).send("이미 존재하는 이메일입니다.");

    db.set(id++, { email, password, nickname });
    res.status(201).json({
        "message": `${nickname}님 환영합니다.`
    });

회원가입의 경우 body에 제대로 값을 담았는지(dto 검증), 이미 있는 email인지 확인하도록 했어요. email 정규식이나, password 길이 검증은 고도화할 때 추가하기로 했어요.

회원 개별 조회

// 회원 개별 조회
app.get('/users/:id', (req,res) => {
    const id = parseInt(req.params.id);
    const user = db.get(id);
    if (!user) return res.status(404).json({ "message": `${id} User Not Found`})
    res.json(user)
});

회원 개별 탈퇴

// 회원 개별 탈퇴
app.delete('/users/:id', (req,res) => {
    const id = parseInt(req.params.id);
    const user = db.get(id);
    if (!user) return res.status(404).json({ "message": `${id} User Not Found`})
    db.delete(id);
    res.status(204).end();
});

Delete 메소드의 성공 body로 204 no content를 사용했어요.

회원 전체 조회

// 회원 전체 조회
app.get('/users', (req,res) => {
    res.json(Array.from(db.values()));
})

강의에서는 같은 /users/:id 를 사용하는 GET과 DELETE를 함께 체이닝으로 구현할 수 있었어요.

profile
할 땐 하고 놀 땐 노는 일일놀놀입니다.

0개의 댓글