Post

데브코스 TIL - Day 19

23년 12월 13일 강의를 들은 내용을 기록한 글입니다.

핸들러(handler)

HTTP 요청이 날아오면 자동으로 호출되는 메소드

node.js

  • 콜백 함수로 사용
1
2
// http Method로 path(url)이 날아오면 handler를 실행하겠다.
app.httpMethod(path, handler);

자바스크립트에서의 =====의 차이

| == | === | | :———————————-: | :————————————-: | | 비교 연산자 | 엄격한 비교 연산자 | | 값의 종류(Type)는 상관없이 값만 비교 | 값과 값의 종류(Type)가 모두 같은지 비교 |

1
2
3
4
5
6
if (1 == "1") {
  console.log("같다");
} else {
  console.log("같지 않다.");
}
// 같다
1
2
3
4
5
6
if (1 === "1") {
  console.log("같다");
} else {
  console.log("같지 않다.");
}
// 같지 않다.

실습 1 - 배열에서 하나의 아이템 찾기

1
2
3
4
5
6
7
8
9
10
11
app.get("/fruits/:id", (req, res) => {
  const { id } = req.params;
  const fruit = fruits[+id - 1];
  if (fruit) {
    res.send(fruit);
  } else {
    res
      .status(404)
      .send({ message: "입력하신 id와 일치하는 과일이 없습니다." });
  }
});

결과

  • 전체조회 json-배열

  • 개별조회 과일 개별 조회 일치하는과일없을때

만약 id가 숫자가 1,2,3,4와 같이 간단한 숫자가 아닌 문자열로 전달된다면?

index값으로는 찾을 수 없음!!!
객체의 id와 일치하는지를 확인하고, 일치하는 아이템을 반환하도록 설정

  • find(): 제공된 테스트 함수를 만족하는 첫 번째 요소를 반환
  • find mdn 문서
1
2
3
4
5
6
7
8
9
10
11
app.get("/fruits/:id", (req, res) => {
  const { id } = req.params;
  const fruit = fruits.find((f) => f.id === +id);
  if (fruit) {
    res.send(fruit);
  } else {
    res
      .status(404)
      .send({ message: "입력하신 id와 일치하는 과일이 없습니다." });
  }
});

결과 map 채널 타이틀 없을 때

Error Handling

Express Error Handling - express 공식문서

데이터 처리를 성공하지 않았을 때의 예외 상황을 컨트롤할 때 사용하고,
클라이언트와 소통을 정확하게 하기 위해 HTTP STATUS CODE를 사용함

※ 자주 사용하는 HTTP 상태 코드는 알고 있으면 좋음

상태 코드내용
2**성공
200조회/수정/삭제 성공
201등록 성공
4**클라이언트 에러 응답
400요청한 연산(처리)를 할 때 필요한 데이터가 오지않았을 때
404찾는 리소스가 없음
5**서버 에러 응답
500서버가 죽었을 때
1
2
3
4
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(HTTP STATUS CODE).send( 전달할 데이터 );
});
1
2
3
4
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).send("Something broke!");
});

실습 2 - 유튜버 데모 파일 - 예외 고도화하기

상태코드 확인용 - mdn 공식문서

전체 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// express 모듈 셋팅
const express = require("express");
const app = express();

app.listen(3000);

//  데이터 세팅
const db = new Map();
let id = 1;

const youtuber1 = {
  channelTitle: "십오야",
  subscriber: 5930000,
  videoNum: 993
};
const youtuber2 = {
  channelTitle: "뜬뜬",
  subscriber: 1510000,
  videoNum: 168
};

db.set(id++, youtuber1);
db.set(id++, youtuber2);

app.use(express.json()); // http 외 모듈인 '미들웨어':json 설정

// 전체 조회
app.get("/youtubers", (req, res) => {
  let youtubers = {};
  db.forEach((values, key) => (youtubers[key] = values));
  if (db.size > 0) {
    res.json(youtubers);
  } else {
    res.status(400).json({ message: "조회할 유튜버가 없습니다." });
  }
});

// 전체 삭제
app.delete("/youtubers", (req, res) => {
  if (db.size > 0) {
    db.clear();
    res.send({ message: "유튜버가 전체 삭제되었습니다." });
  } else {
    res.status(404).send({ message: "삭제할 유튜버가 없습니다." });
  }
});

// 개별 등록
app.post("/youtubers", (req, res) => {
  const { channelTitle } = req.body;
  if (channelTitle) {
    db.set(id++, { channelTitle, sub: 0, videoNum: 0 });
    res.status(201).send({
      message: `${db.get(id - 1).channelTitle}님, 유튜버가 되신걸 환영합니다!`
    });
  } else {
    res.status(404).send({ message: "채널명이 제대로 입력되지 않았습니다." });
  }
});

// 개별 조회
app.get("/youtubers/:id", function (req, res) {
  const { id } = req.params;
  const youtuber = db.get(parseInt(id));
  if (youtuber) {
    res.send(youtuber);
  } else {
    res.status(404).send("찾을 수 없는 유튜버입니다.");
  }
});

// 개별 삭제
app.delete("/youtubers/:id", (req, res) => {
  const { id } = req.params;
  const youtuber = db.get(Number(id));
  if (youtuber) {
    db.delete(Number(id));
    res.send({ message: `${youtuber.channelTitle}님, 탈퇴에 성공했습니다.` });
  } else {
    res
      .status(404)
      .send({ message: "찾을 수 없는 유튜버입니다. 탈퇴에 실패했습니다." });
  }
});

// 개별 수정
app.put("/youtubers/:id", (req, res) => {
  const { id } = req.params;
  const { channelTitle: newChannelTitle } = req.body;
  const youtuber = db.get(Number(id));
  if (youtuber) {
    db.set(Number(id), { ...youtuber, channelTitle: newChannelTitle });
    res.send({
      message: `${youtuber.channelTitle}님, 채널명이 ${newChannelTitle}으로 변경되었습니다`
    });
  } else {
    res.status(404).send({ message: `일치하는 유튜버가 없습니다.id = ${id}` });
  }
});

프로젝트 - 유튜브 운영하는 것처럼 해보기

  • 회원 API

    • 로그인
    • 회원가입
    • 회원 탈퇴
    • 회원 정보 조회
  • 채널 API

    • 채널 생성
    • 채널 수정
    • 채널 삭제
    • 채널

※ 회원은 계정 1개당 채널 100개를 가질 수 있다.

페이지별 필요한 API 확인하기 (회원)

■ 회원가입 페이지

회원가입페이지

  • data: id, pwd, 이름
  • 화면 렌더할 때는 API가 필요하지 않음
  • 회원가입 버튼 클릭 → 입력한 id, pwd, 이름로 회원 가입할 API

■ 로그인 페이지

로그인페이지

  • data: id, pwd
  • 화면 렌더할 때는 API가 필요하지 않음
  • 로그인 버튼 클릭 → 입력한 id, pwd로 로그인할 API

■ 회원정보 페이지(마이페이지)

마이페이지

  • data: id, 이름
  • 화면 렌더할 때 회원 정보 API가 필요함 (개별 회원정보 조회)
  • 회원탈퇴 버튼 클릭 → 회원 탈퇴시켜줄 API

회원 API 설계하기

  1. 로그인 (POST /login)

    • req: body(id, pwd), id와 pwd는 숨겨져야하는 데이터이기때문
    • res:
      • ${name}님 환영합니다.
      • 메인페이지 출력
  2. 회원가입 (POST /join)

    • req: body(id, pwd,name),id와 pwd, name는 숨겨져야하는 데이터이기때문
    • res:
      • ${name}님 환영합니다.
      • 로그인페이지 출력
  3. 회원 탈퇴 (DELETE /members/:id)

    • req: req.params (id)
    • res:
      • ${name}님 탈퇴가 완료되었습니다.
      • 메인페이지 출력
  4. 회원 정보 조회 (GET /members/:id)

    • req: req.params (id)
    • res: id, name

실습 코드 (회원가입 구현, 회원 개별 조회, 회원 개별 삭제)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
const express = require("express");
const app = express();

const db = new Map();

app.use(express.json());

// 회원가입
app.post("/join", (req, res) => {
  const { id, pwd, name } = req.body;
  if (id.length > 0 && pwd.length > 0 && name.length > 0) {
    db.set(id, { id, pwd, name });
    const member = db.get(id);
    res.status(201).send({ message: `${member.name}님, 환영합니다.` });
  } else {
    res
      .status(400)
      .send({ message: "잘못된 요청입니다. 입력값을 다시 확인해주세요" });
  }
});

//로그인
app.post("/login", (req, res) => {
  const { id, pwd } = req.body;
  if (id && pwd) {
    const member = db.get(id);
    if (member) {
      const memberPwd = member.pwd === pwd;
      if (memberPwd) {
        const member = db.get(id);
        res.status(200).send({ message: `${member.name}님, 환영합니다.` });
      } else {
        res.status(400).send({ message: "비밀번호가 일치하지 않습니다." });
      }
    } else {
      res.status(200).send({ message: "일치하는 아이디가 없습니다." });
    }
  } else {
    res.status(400).send({ message: "잘못된 요청입니다." });
  }
});

// 회원 개별 조회
app.get("/members/:id", (req, res) => {
  const { id } = req.params;
  const member = db.get(id);
  if (member) {
    res.status(200).send({ id, name: member.id });
  } else {
    res.status(404).send({ message: "일치하는 아이디가 없습니다." });
  }
});

// 회원 탈퇴
app.delete("/members/:id", (req, res) => {
  const { id } = req.params;
  const member = db.get(id);
  if (member) {
    db.delete(id);
    res
      .status(200)
      .send({ message: `${member.name}님 탈퇴가 완료되었습니다.` });
  } else {
    res.status(404).send({ message: "일치하는 아이디가 없습니다." });
  }
});

app.listen(3000);
This post is licensed under CC BY 4.0 by the author.