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: '요청 값을 제대로 보내주세요.'
});
}
})
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) 탈퇴 실패
![]() |
![]() |
'TIL with Programmers' 카테고리의 다른 글
[TIL] 9/10 라우팅, 예외처리 (0) | 2024.09.10 |
---|---|
[TIL] 9/9 API 설계 - 회원 API, 채널 API (0) | 2024.09.09 |
[회고록] 풀 사이클 개발 데브코스 4주차 회고 (1) | 2024.09.08 |
[TIL] 9/5 api GET/DELETE/PUT, 리팩터링, forEach, map, HTTP 상태코드 (0) | 2024.09.05 |
[TIL] 9/4 GET, POST, API, postman (2) | 2024.09.04 |