본문 바로가기
TIL with Programmers

[TIL] 9/6 핸들러, 예외 처리, HTTP 상태코드

by 보먀 2024. 9. 8.
728x90
반응형

1. 핸들러 (Handler)

HTTP request 가 날아오면 자동으로 호출되는 메소드

 

노드에서는 콜백함수로, 콜백함수를 핸들러라고 생각하면 된다. (cf. 스프링에서는 컨트롤러라고 불린다)

즉, HTTPMETHOD 를 사용해서 path(URL) 로 요청이 날라오면 이 핸들러를 실행하겠다는 의미

app.HTTPMETHOD(path, 콜백함수(핸들러) {...})

 

 

 

2. 예외 처리

 

예외 처리를 하지 않고 코드를 짰다.

이 API 에 없는 id 를 요청하면, findFruit 에 undefined 가 들어가게 되고 API 가 제대로된 데이터를 주지 못하게 된다. 현재 클라이언트가 찾는 리소스가 없는 상태이지만 상태코드는 여전히 200 인 것을 확인할 수 있다. 이런 경우 프론트에서 데이터를 제대로 받았다고 오해할 수 있으므로 에러를 터트려(= HTTP 상태코드를 실패로 바꿔주는 것) 프론트에서 명확하게 인지할 수 있도록 예외 처리를 해줘야 한다. 

const fruits = [
    { id: 1, name: 'apple'},
    { id: 2, name: 'orange'},
    { id: 3, name: 'strawberry'},
    { id: 4, name: 'blueberry'}
]

// ...

// 과일 개별 조회, 예외 처리 X
app.get('/fruits/:id', (req, res) => {
    let {id} = req.params;
    id = parseInt(id);
    let findFruit = fruits.find(f => f.id == id);
    res.json(findFruit);
})

 

 

 

2.1. 예외 터트리기 -> res.status(상태코드)

 

res.status(상태코드)

  • 클라이언트에게 전송되는 HTTP 상태코드를 설정
  • ___.send(), ___.json() 등과 함께 사용됨

status 메서드로 원하는 HTTP 상태 코드를 넣고 뒤에 .json 으로 필요한 객체, 문자열 등을 넣어주면 된다. 

const fruits = [
    { id: 1, name: 'apple'},
    { id: 2, name: 'orange'},
    { id: 3, name: 'strawberry'},
    { id: 4, name: 'blueberry'}
]

// ...

// 과일 개별 조회
app.get('/fruits/:id', (req, res) => {
    let {id} = req.params;
    id = parseInt(id);
    let findFruit = fruits.find(f => f.id == id);
    
    if (findFruit) {
        res.json(findFruit);
    } else { // 예외 처리 -> 예외 터트리기 = http status 코드를 성공이 아니라 실패로 바꿔주는 것
        res.status(404).json(
            "전달주신 id로 저장된 과일이 없습니다."
        );
    }
})

 

 

2.2. POST 예외 터트리기

 

POST 에서의 예외처리는 조금 다르다. POST 는 성공 시 상태 코드 201, 실패 시 상태 코드 400 을 돌려줘야 한다. 

  • 201 (등록완료): 성공적으로 요청되었으며, 등록도 성공 (POST)
  • 400 (잘못된 요청): 서버가 요청의 구문을 인식하지 못함 -> 요청한 연산(처리)을 할 때 필요한 데이터(리퀘스트)가 덜 옴

객체의 id 값은 내부적으로 처리해서 넣어주기 때문에, 리퀘스트 바디에 과일의 이름을 제대로 넣어서 보내지 않은 경우 POST 에 실패할 것이다. name 값을 검사해서 name 값이 undefined 인 경우 예외 처리를 해주었다. 

// 과일 등록
app.use(express.json());
app.post('/fruit', (req, res) => {
    const name = req.body.name;
    if (name) {
        let fruit = {
            id: fruits.length+1,
        }
        fruit[name] = name;
        fruits.push(fruit);
        res.status(201).json({
            message: `${name} 생성완료`
        });
    } else { // 예외 처리
        res.status(400).json({
            message: '요청 값을 제대로 보내주세요.'
        });
    }
})

 

요청 실패 시 -> 상태코드 400
요청 성공 시 -> 상태코드 201

 

 

 

3. 자바스크립트 문법

 

3.1. == vs ===

  • == : 값만 비교하고, 자료형이 다르면 자동으로 형 변환을 해서 비교함
  • ===: 값과 자료형을 모두 비교, 자료형이 다르면 형 변환 없이 다르다고 판단

 

== 을 사용해서 비교하면 자료형을 자동으로 변환해서 비교하기 때문에 "같다" 가 출력된다. 

// == 사용

if (1 == "1") {
    console.log("같다")
} else {
    console.log("같지 않다")
}

// 같다

 

=== 을 사용해서 비교하면 자동 형변환되지 않고, 원래의 자료형으로 비교하기 때문에 "같지 않다" 가 출력된다. 

 

 

3.2. find() 

 

find 메서드는 배열에서 조건을 만족하는 첫 번째 요소를 반환하는 메서드로, 조건에 만족하는 요소가 없다면 undefined 를 반환한다. 

array.find(callback(element, index, array) => { ... })

 

- callback 함수는 배열의 각 요소를 대상으로 실행할 함수

  • element: 현재 배열 요소
  • index: 현재 요소의 인덱스
  • array: 호출한 배열 자체

예시 코드

const numbers = [10, 20, 30, 40, 50];

// 25보다 큰 첫 번째 값을 찾음
const result = numbers.find(num => num > 25);

console.log(result); // 30

 

 

 

4. 미니미니 프로젝트 (실습)

 

4.1. 페이지 구성

 
 

 

로그인 페이지

(1) 화면 생성 : API X

(2) 로그인 버튼 클릭 : id, pwd -> 로그인 시켜줄 API

 

회원 가입 페이지

(1) 화면 생성: API X

(2) 회원가입 버튼 클릭: id, pwd, 이름 -> 회원가입 시켜줄 API

 

마이페이지 (회원 탈퇴 페이지)

(1) 화면 생성: 회원 정보 조회 API

(2) 회원 탈퇴 클릭: 회원 탈퇴를 시켜줄 API

 

 

4.2. 회원 API 설계

 

1) 로그인  ->  POST /login

  • req: body(id, pwd)
  • res: `${name}님 환영합니다` 👉 메인 페이지

2) 회원 가입  ->  POST /join

  • req: body(id, pwd, name)
  • res: `${name}님 환영합니다` 👉 로그인 페이지

3) 회원 개별 정보 조회  ->  GET /users/:id

  • req: URL(id)
  • res: id, name

4) 회원 개별 탈퇴  ->  DELETE /users/:id

  • req: URL(id)
  • res: `${name}님 다음에 또 뵙겠습니다.` or 👉 메인 페이지

 

- 로그인 코드

 

1) 사용자가 입력한 id 가 존재하는 id 일 때 (db 에 회원정보 있음 = 회원임)

  • 입력한 비밀번호가 올바른 비밀번호인 경우 -> ${loginUser.name}님 로그인이 성공
  • 입력한 비밀번호가 틀렸을 때 -> 비밀번호가 틀립니다
  • status 201 (POST 성공)

2) 사용자가 입력한 id 가 존재하지 않는 id 인 경우 (db 에 회원정보 없음 = 회원아님)

  • 아이디가 존재하지 않습니다
  • status 404 -> 사용자가  id 를 잘못 입력해서 서버에서 리소스를 찾을 수 없음
// 로그인
app.post('/login', (req, res) => {
    const {userId, pwd} = req.body
    let loginUser = {}
    db.forEach(user => {
        if (user.userId === userId) {
            loginUser = user
        }
    })
    if (isExisted(loginUser)) {
        if (loginUser.pwd === pwd) {
            res.status(201).json({
                message: `${loginUser.name}님 로그인 성공`
            })
        } else {
            res.status(400).json({
                message: '비밀번호가 틀립니다'
            })
        }
    } else {
        res.status(400).json({
            message: '아이디가 존재하지 않습니다'
        })
    }
})

function isExisted(obj) {
    if (Object.keys(obj).length) {
        return true
    } else {
        return false
    }
}

 

 

- 회원 가입 코드

 

1) 리퀘스트 바디의 모든 필드 값이 제대로 들어온 경우 

  • ${user.name}님 환영합니다.
  • status 201 (POST 성공)

2) 리퀘스트 바디의 어떤 필드 값이 제대로 들어오지 않은 경우

  • 입력 값을 다시 확인해주세요
  • status 400 -> id, pwd, name 중 한 개라도 빈 값이면 사용자 입력 오류처리
// 회원 가입
app.post('/join', (req, res) => {
    let {userId, pwd, name} = req.body
    let user = {
        userId: userId,
        pwd: pwd,
        name: name
    }
    if (userId && pwd && name) {
        db.set(id++, user)
        res.status(201).json({
            message: `${user.name}님 환영합니다.`
        })
    } else {
        res.status(400).json({
            message: '입력 값을 다시 확인해주세요'
        })
    }
})

 

 

- 회원 개별 조회 코드

 

1) 회원이 존재하는 경우

  • 유저 정보 돌려줌 (id, name)
  • status 200 (요청 성공)

2) 회원이 존재하지 않는 경우

  • 회원 정보가 없습니다
  • status 404 -> 서버가 요청한 리소스를 찾을 수 없음
// 회원 개별 조회
app.get('/users/:id', (req, res) => {
    let {id} = req.params
    id = parseInt(id)
    let user = db.get(id)
    
    if (user) {
        res.status(200).json({
            id: user.userId,
            name: user.name
        })
    } else {
        res.status(404).json({
            message: '회원 정보가 없습니다.'
        })
    }
})

 

 

- 회원 개별 탈퇴 코드

 

1) 탈퇴 성공

  • ${user.name}님 탈퇴가 완료되었습니다
  • status 200 (요청 성공)

2) 탈퇴 실패

  • 회원 정보가 없습니다
  • status 404 -> 서버가 요청한 리소스를 찾을 수 없음
// 회원 개별 탈퇴
app.delete('/users/:id', (req, res) => {
    let {id} = req.params
    id = parseInt(id)
    let user = db.get(id)

    if (user) {
        db.delete(id)
        res.status(200).json({
            message: `${user.name}님 탈퇴가 완료되었습니다`
        })
    } else {
        res.status(404).json({
            message: '회원 정보가 없습니다.'
        })
    }
})

 

 

4.3. 실습 화면

 

- 회원 가입

 

1) 회원 가입 성공

2) 회원 가입 실패

 

 

 

- 로그인

1) 로그인 성공

2) 로그인 실패

 

 

- 회원 개별 조회

 

1) 조회 성공

2) 조회 실패

 

 

- 회원 개별 탈퇴

 

1) 탈퇴 성공

2) 탈퇴 실패

728x90
반응형