포스트

2024.05.01 프로그래머스-CRUD 맛보기2

핸들러

  • Request 가 발생 했을 때, http method와 url 에 따라 호출 되는 함수(기능)
  • 핸들러 안에서 예외처리까지 수행해야 한다.

express 로 god 멤버 요청해보기

  • 그룹 god 의 멤버를 조회 할 객체를 만들어 놓고, 해당 객체에 접근하는 api 코드들을 작성한다.
    1. 전체 멤버조회
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
      const express = require("express");
      const app = express();
      const PORT = 3000;
        
      const members = [
        { id: 1, name: "박준형", position: "래퍼" },
        { id: 2, name: "데니안", position: "래퍼" },
        { id: 3, name: "윤계상", position: "래퍼" },
        { id: 4, name: "손호영", position: "리드보컬" },
        { id: 5, name: "김태우", position: "메인보컬" },
      ];
        
      app.listen(PORT, () => {
        console.log(`Server listen : ${PORT}`);
      });
        
      // member 전체 조회
      app.get("/members", (req, res) => {
        res.json(members);
      });
        
    
    • 만약 전체 멤버 변수에 멤버가 없다면? 에 대한 예외 처리도 추가해주어야 한다.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
      // member 전체 조회
      app.get("/members", (req, res) => {
        if (members.length === 0) {
          res.status(200); // member의 내부 정보가 없는 것이므로 응답코드는 200
          res.send("member 정보가 없습니다.");
        } else {
          res.json(members);
        }
      });
        
    

express로 각 멤버 세부정보 조회

  • ‘/members/:id’ 로 GET 요청이 올때, id 에 해당하는 멤버의 정보만 조회하는 API 코드를 작성한다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    
      // member 개별적으로 조회
      app.get("/members/:id", (req, res) => {
        // 개별적으로 조회하기 위해선 json Array로 선언된 members의 각 요소에 올바르게 접근해야한다.
        const { id } = req.params;
        /**
         * 내가 생각한 json array 에서 요소 찾는 법
         * 배열에서 findeIndex를 통해 해당 요소의 Index 반환 (false 일때 -1 이 반환됨)
         */
        const memberIndex = members.findIndex((member) => member.id === +id); //id는 string으로 넘어오므로 숫자 형변환
        console.log(`찾는멤버 ID : ${id}, 멤버 인덱스 : ${memberIndex}`);
        
        if (memberIndex > -1) {
          //찾는 member 가 존재하는 상태
          const member = members[memberIndex]; // 찾는 멤버 할당
          res.json(member);
        } else {
      	  // 찾는 member가 없을 때
      	  // Not Found Status 인 404 할당
      		res.status(404).send("찾는 멤버가 없습니다."); //res 체이닝
        }
      });
        
    
    • findIndex method를 통해, 해당멤버가 존재하는지 부터 검사한다.
      • 이때 동등비교를 === 를 사용했는데, 이 엄격한 동등비교는 타입변환을 강제하지 않기때문에, +id 로 값을 비교하였다.
    • findIndex를 사용한 이유는, false 일 때 -1이 반환되는데, -1이 아닐때에만 새로운 변수를 사용 (메모리사용) 을 위해 findIndex를 사용했다.

express 로 새로운 멤버 등록 api 코드 작성하기

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
app.post("/members/:id", (req, res) => {
  // id, name, position 을 member에 push 해야 한다.

  // body와 id 할당
  const { id } = req.params;
  const { name, position } = req.body;
  console.log(name, position);

  if (!name || !position) {
    res.status(400).send("올바른 정보를 입력해주세요, name & position");
    return;
  }

  /**
   * 처리할 예외 사항
   * 이미 있는 id를 '등록' 하는 것은 PUT으로 해야한다.
   * 때문에 Post로 오는 중복 id 에 대한 요청은 400(Bad Request) 로 처리
   */
  if (members.findIndex((member) => member.id === +id) > -1) {
    res.status(400).send("이미 등록되어있는 멤버입니다.");
    return;
  } else {
    const newMember = {
      id,
      name,
      position,
    };
    members.push(newMember);
    res.status(200).json(newMember);
    return;
  }
});

  • 이미 있는 멤버에 대해서는 put 요청으로 수정을 해주는 것이 올바르다고 생각하여, 중복 Id 의 POST 요청에서는 예외로 지정하였다.
  • 또한 넘어오는 body 인 name, position 이 없으면, undefined로 할당 되기 때문에, 예외로 처리 하였다.

새로운 프로젝트 만들기

  • 팬카페 컨셉의 사이트
  • 회원은 여러명의 아티스트의 팬이 될 수 있다.
  • https://github.com/ykdman/fantom

기능

회원

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

팬 되기

  • 회원이 팬을 맺은 아티스트를 위한 팬 개인의 기록소 만들기
  • 기록소 수정
  • 기록소 삭제

API 설계

회원

  • 로그인 POST‘/login’
    • req : body (id, pw)
    • res : ‘로그인 성공’
    • redirect : main page
  • 회원 가입 POST‘/signup’
    • req : body (id, pwd, name)
    • res : 회원가입을 환영합니다.
    • redirect : ?
  • 회원 정보 조회 GET‘/users/:id’
    • req : params (id)
    • res : json (id, pwd?, name)
    • redirect :
  • 회원 탈퇴 DELETE‘/users/:id’
    • req : params (id)
    • res : message 탈퇴가 완료되었습니다.

ArichiTecture

  • 소스 구성
  • src
    • model : 데이터 저장소
    • controllers : 핸들러 함수 저장소
    • index.js : 서버 코드

회원가입 api 작성

  • method : POST
  • user.controller.js
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
/** user.controller.js*/
const db = require("../model/data.js");

/**
 * user 회원 가입 API : POST
 * @param {Request} req
 * @param {Response} res
 * @returns {Response}
 */
const signupUser = (req, res) => {
  const { id, pwd, name } = req.body;
  const validReq = validRequest([id, pwd, name]);

  if (!validReq) {
    res.status(400).send("올바른 가입정보를 입력하세요");
    return;
  }

  const existId = db.get(id);
  if (existId) {
    res.status(400).send(`이미 존재하는 아이디 입니다. : ${id}`);
    return;
  } else {
    const newUser = {
      pwd,
      name,
    };
    db.set(id, newUser);
    res.status(200).json({ id, ...newUser, message: "회원가입 완료" });
  }
};

module.exports = {
  loginUser,
  signupUser,
};
  • index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const express = require("express");
const app = express();
const PORT = 3000;

// controllers
const userControllers = require("./controllers/user.contorller.js");

app.listen(PORT, () => {
  console.log(`server listen : ${PORT}`);
});

// body Parser
app.use(express.json());

// middlw Ware (logger)
app.use((req, res, next) => {
  const start = Date.now();
  console.log(`start: ${req.method} ${req.url}`);
  next(); // router 실행
  const diffTime = Date.now() - start;
  console.log(`end: ${req.method} ${req.baseUrl}${req.url} ${diffTime}ms`);
});

app.post("/signup", userControllers.signupUser);
  • 추가적으로 body 유효성 검증을 위한 util 함수를 하나 user.controller.js에 작성하였다.
1
2
3
4
5
6
7
8
9
function validRequest() {
  for (const item of [...arguments]) {
    if (typeof item === "undefined") {
      return false;
    }
  }

  return true;
}

로그인 API 작성

  • method : POST
  • user.controller.js
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
/** user.controller.js*/

/**
 * user 로그인 API : POST
 * @param {Request} req
 * @param {Response} res
 * @returns {Response}
 */
const loginUser = (req, res) => {
  const { id, pwd } = req.body;
  console.log(typeof pwd);
  const validReq = validRequest([id, pwd]);
  const idExist = db.get(id);

  // 계정정보를 올바르게 입력 안했을때
  if (!validReq) {
    res.status(400).send("올바른 로그인 정보를 입력해주세요");
    return;
  }

  // db가 비어있거나, 일치하는 id 가 없을 때
  if (db.size === 0 || !idExist) {
    res.status(404).send("해당 ID가 존재하지 않습니다.");
    return;
  }

  // ID 존재 상황
  if (idExist) {
    const dbUser = db.get(id);
    console.log(dbUser);
    if (dbUser && dbUser.pwd === pwd) {
      res.status(200).send(`${id} : ${dbUser.name} 님 로그인을 환영합니다.`);
    } else {
      res.status(400).send("비밀번호가 일치하지 않습니다.");
    }
  }
};
  • index.js 작성
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
const express = require("express");
const app = express();
const PORT = 3000;

// controllers
const userControllers = require("./controllers/user.contorller.js");

app.listen(PORT, () => {
  console.log(`server listen : ${PORT}`);
});

// body Parser
app.use(express.json());

// middlw Ware (logger)
app.use((req, res, next) => {
  const start = Date.now();
  console.log(`start: ${req.method} ${req.url}`);
  next(); // router 실행
  const diffTime = Date.now() - start;
  console.log(`end: ${req.method} ${req.baseUrl}${req.url} ${diffTime}ms`);
});

app.post("/signup", userControllers.signupUser);

// login 
app.post("/login", userControllers.loginUser);

회원 개별 조회 API 작성

  • method : GET
  • user.controller.js
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
/**
 * 회원 개별 조회 API : GET
 * @param {Request} req
 * @param {Response} res
 */
const getUser = (req, res) => {
  const { id } = req.params;
  const dbUser = db.get(id);

  //db에 회원 id가 없는 경우
  if (!dbUser) {
    res.status(404).send(`${id} 회원이 존재하지 않습니다.`);
  }
  const user = {
    id,
    pwd: dbUser.pwd,
    name: dbUser.name,
  };
  res.status(200).json(user);
};

module.exports = {
  loginUser,
  signupUser,
  getUser,
};
  • index.js
1
app.get("/users/:id", userControllers.getUser);

개별 회원 삭제 API

  • method : POST
  • user.controller.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
 * 개별 회원 탈퇴 API : DELETE
 * @param {Request} req
 * @param {Response} res
 */
const deleteUser = (req, res) => {
  const { id } = req.params;
  const validReq = validRequest([id]);
  if (!validReq) {
    res.status(400).send("올바른 id를 입력해주세요");
  }

  const dbUser = db.get(id);

  // 올바른 user 존재 시 삭제
  if (dbUser) {
    const userDeleteState = db.delete(id);
    if (userDeleteState) {
      res.status(200).send(`${id} 회원이 정상적으로 탈퇴 되었습니다.`);
    } else {
      res.status(505).send(`${id}의 탈퇴가 이루어지지 않았습니다.`);
    }
  }
};
  • index.js 라우터 코드 추가
1
app.delete("/users/:id", userControllers.deleteUser);
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.