[프로그래머스] 백엔드기초(10)

Lina Hongbi Ko·2024년 9월 10일
0

Programmers_BootCamp

목록 보기
19/76
post-thumbnail

2024년 9월 10일

✏️ router

: Node.js에서의 라우팅은 request(요청)가 날아왔을 때, 원하는 경로에 따라 적절한 방향으로 경로를 안내해주는 것이다.

  • url, method가 날아오면 이것들에 따라 호출해주는 "콜백함수"가 다름을 안내해줌
  • Routing : Route + ing
  • user과 channel을 합쳐볼 예정
    • routes 폴더 만들고 user-demo.js와 channel-demo.js 파일 옮기기
    • app.js 파일 만들기(대장 파일) & user과 channel은 모듈로 가져오기
// app.js
// 서버 역할

const express = require('express');
const app = express();
app.listen(7777);

const userRouter = require('./routes/user-demo');

app.use("/", userRouter)
// 미들웨어처럼 사용하겠다는 의미
// routes / user-demo.js

const express = require('express');
const router = express.Router();
// express의 라우터 사용

// app -> router 로 모두 바꾸기
router.use(express.json());

.
.
.
// 코드 생략

module.exports = router;

POSTMAN) POST + localhost:7777/join + (raw body) {”userId” : “userId1”, “password” : 1234, “name” : “user1”}

❗️ app.js에서 서버를 구동시켜야함

이제 channel-demo도 연결시켜보자.

// routes / channel-demo.js

const express = require('express');
const router = express.Router();

router.use(express.json());
// 마찬가지로 app -> router로 모두 바꾸기
// refactoring -> F2 눌러서 app => router로 모두 쉽게 바꾸기
// 변수 선언문을 바꿔야 다 바꿀수 있음
router
      .route('/channels')
.
.
.
// 코드 생략
module.exports = router;
// app.js

const express = require('express');
const app = express();
app.listen(7777);

const userRouter = require('./routes/user-demo');
const channelRouter = require('./routes/channel-demo');

app.use("/", userRouter);
app.use("/", channelRouter);

POSTMAN) POST + localhost:7777/channels + (raw body) { “channelTitle” : “쨍순이” }

❗️ API가 나타내고 싶은 객체는 복수형이기 때문에 모듈 이름을 바꿔주는 것이 좋다 -> 파일 이름 바꾸기 : user-demo.js -> users.js / channel-demo.js -> channels.js

❗️ 공통된 url 빼기
- users의 url은 통일 된 url이 없기 때문에 공통 url을 뺄 수 없다
- channels는 공통된 url로 이루어져 있으므로 뺄 수 있음

// app.js

const express = require('express');
const app = express();
app.listen(7777);

const userRouter = require('./routes/users');
const channelRouter = require('./routes/channels');

app.use("/", userRouter)
app.use("/channels", channelRouter)
// routes / channels.js

const express = require('express');
const router = express.Router();

router.use(express.json());

router
	  .route('/')
.
.
.
      .route('/:id')
// 코드 생략

✏️ 각 회원의 채널 ERD 그려보기

: 데이터베이스를 고민해봐야함
따라서, ERD를 그려보면서 데이터를 고민 해봐야 한다

ERD를 보았을 때, 회원은 채널에 대한 관계를 모르고, 채널은 어떤 회원이 있는지 알 수 있음 -> 채널이 회원에 대한 정보 접근 가능

강사님과 ERD를 그려보면서 API를 설계할 때 ERD를 먼저 설계해보고 API를 설계하거나 다시 수정해야하는 것을 알게 되었다. ERD 그리는 것을 좀 연습해봐야겠다.

✏️ 채널 API 설계 수정

: 처음 채널에 대한 API를 설계 했을 때 우리는,

  • 채널 생성

    • POST /channels
    • req: (body) channelTitle
    • res 201: ${channelTitle}님 채널이 만들어졌어요!
  • 채널 전체 조회

    • GET /channels
    • req : X
    • res 200 : 채널 전체 데이터(list)

이렇게 설계 했었다. 하지만 ERD를 그려보면서, id가 아닌 userId를 이용해 회원을 구분해야 하므로 설계를 수정해야한다.

그리고 실제로는 userId값을 body로 받지 않고, header에 숨겨서 token을 이용해 받아온다고 한다. 지금은 실제가 아니니(나중에 실제로 연습한다고 하셨음!) body에 담아서 channelTitle과 userId를 받아 올 것이다.

따라서, API 설계를 수정하자면

  • 채널 생성
    • POST /channels
    • req: (body) channelTitle, userId
    • res 201: ${channelTitle}님 채널이 만들어졌어요!
  • 채널 전체 조회
    • GET /channels
    • req: (body) userId
    • res 200: 채널 전체 데이터(list)

💡 채널 생성 수정

: 채널 생성은 사실 수정할게 없다. 왜냐하면 userId만 추가해서 request에 던져줄 예정(값만 받으면 됨)

// channels.js

router
	 .route('/')
	 .post((res, res) => {
		 if (req.body.channelTitle) {
			 let channel = req.body
			 db.set(id++, channel)
             
			 res.status(201).json({
				 message : `${db.get(id-1).channelTitle}님 환영해요!`
			 })
		 } else {
			 res.status(400).json({
				 meesage : `요청 값을 다시 보내주세요`
			 })
		 }

	 })

POSTMAN)

회원 가입 ⇒ POST + localhost:7777/join + (raw body) {”userId” : ”userId1”, “password” : 1234, “name” : “user1”} 하고,

채널 등록 ⇒ POST + localhost:7777/channels + (raw body) {”channelTitle” : “쨍순이”, “userId” : “userId1”} 하고 send 처리 하면 만들어졌다는 메시지 나옴

채널 개별 조회 ⇒ GET + localhost:7777/channels/1 ⇒ {”channelTitle” : “쨍순이”, “userId” : “userId1”} 나오는 것 확인

그럼 만약, 존재하지 않는 userId를 채널 생성에 넣으면 어떨까?

: 등록하지 않은 userId로 채널이 생성된다. 이렇게 되면, 나중에 map를 이용해서 다 비교해줘야 한다고 하시는데.. 무튼 이건 나중에 살펴볼 예정이고,

지금은 존재하는 userId만 넣어서 조회할 예정.

💡 채널 조회 수정(id 없으면 예외처리)

: 한 회원의 전체 채널들을 조회하는 코드를 수정해보자.

먼저, userId값을 확인해서 조회시키기

// channels.js

router
	 .route('/')
	 .get((req res) => {
		 if(db.size) {
			 const {userId} = req.body;
			 let channels = [];
			 
			 db.forEach(function(value, key) {
				 // value의 userId === userId 비교
				 if (value.userId === userId) {
					 channels.push(value);
				 }
			 })
			 res.status(200).json(channels);
		 } else {
			 res.status(404).json({
				 message : `조회할 채널이 없어요`
			 })
		 }
	 
	 })

POSTMAN) 회원 가입 2명 가입시키고, userId1에 채널 3개 만들고, userId2에 채널 2개 만들고, 전체 채널 조회

그럼 body값에 아무것도 적지 않고, 전체 채널 조회를 하면?
: 아무것도 날아오지 않는다. body값에 userId를 넣지 않았기 때문 그러나 status는 200-> 예외처리 해줘야함

그리고 존재 하지 않는 userId3을 넣어서 가지고 있는 채널들을 검색해본다면?
: 값이 나오고 status도 200 으로 정상적으로 나온다 -> 예외처리 해줘야함

결국, body값에 userId가 없어도 문제, 생성된 채널을 가지고 있지 않은 userId로 검색해도 문제라는 것을 알 수 있다

=> 이 두 부분에 대한 예외 처리 필요

// channels.js

// 예외 처리 2가지
// 1) userId가 body에 없으면
// 이 부분은 고려하지 않아도 됨
// 마이 페이지 -> 채널 관리 버튼을 눌러야하므로
// 이미 로그인 되어있기 때문
			
// 그럼 몇일 지나고, 로그인이 풀린 상태에서 (로그인 만료)
// 채널 관리 버튼을 누르면??
// 이 때는 body값에 userId가 없음
// 요럴 때에는 그럼 로그인 하러 가라고 지시하면 됨
// 로그인 페이지로 이동시키면 되겠지
// 그런데 지금 로그인 페이지가 없으므로, 로그인하라고 메시지를 던질 예정

// 2) userId가 가진 채널이 없으면
// forEach문을 돌았는데 맞는게 없어서 push가 되는게 하나도 없으면
// 404 오류를 보내기

router
	 .route('/')
	 .get((req, res) => {
		 if(db.size) {
			 let channels = [];
			 const {userId} = req.body;
             
			 if(userId == undefined) { // 1) userId가 없으면
				 res.status(404).json({
					 message : `로그인이 필요한 페이지에요`
				 })
			 } else {
				 db.forEach(function(value, key) {
					 if (value.userId === userId) {
						 channels.push(value);
					 }
				 })
				 
				 if(channels.length == 0) { // 2) userId을 가진 채널이 없으면
					 res.status(404).json({
						 message : "조회할 채널이 없어요"
					 })
				 } else {
					 res.status(200).json(channels);
				 }
			 } 
		 } else {
				 res.status(404).json({
					 message : `조회할 채널이 없어요`
				 })
		 }
	 });

POSTMAN) GET + localhost:7777/channels + (body) 아무것도 넣지 않았을 때

POSTMAN) GET + localhost:7777/channels + (body) {”userId” : “userId3”}

📍 예외처리 if문 고도화

: 수많은 if else문 줄이기 (논리연산자, 콜백함수 이용)

// channels.js

router
	 .route('/')
	 .get((req, res) => {
		 const {userId} = req.body;
		 let channels = [];
		 if(db.size && userId) {
				 db.forEach(function(value, key) {
					 if (value.userId === userId) {
						 channels.push(value);
					 }
				 })
				 
				 if(channels.length) {
					 res.status(200).json(channels);
				 } else {
					 notFoundChannel();
				 }
		 } else {
			 notFoundChannel();
		 }
	 })

      function notFoundChannel() {
          res.status(404).json({
              message : `조회할 채널이 없어요`
          });
      }
    })

매개변수를 비구조화해 조금 더 고도화해 볼 수 있을지 생각해보기,
include 함수 이용해보기,
등등 여러 가지 방법을 더 사용해서 코드를 줄일 수 있으면 좋겠다고 하셨음

이 부분은 좀 익숙해지면 찾아서 해봐야겠다..

✏️ 백엔드 기초 마무리

: 앞에서 채널 생성, 전체 채널 조회 API도 수정했기 때문에 다른 API들도 역시 수정 해줘야한다.(회원 테이블에서 id칼럼 삭제함)

앞서 봤던 API는,

  • 로그인
    • POST /login
    • req: (body) id, pwd
    • res 200 : ${name}님 환영합니다 + 메인 페이지
  • 회원 가입
    • POST /join
    • req : (body) userId, name, pwd
    • res 201: ${name}님 환영합니다 + 로그인 페이지
  • 회원 정보 조회
    • GET /users/:id (개별 조회)
    • req : (url) id
    • res 200: userId, name
  • 회원 탈퇴
    • DELETE /users/:id (개별 삭제)
    • req : (url) id
    • res 200 : ${name}님 탈퇴되었습니다 or 메인 페이지

였지만, 다시 수정해서 설계해보자.

  • 로그인

    • POST /login
    • req: (body) useId, pwd
    • res 200 : ${loginUser.name}님 로그인 되었어요
  • 회원 가입

    • POST /join
    • req : (body) userId, name, pwd
    • res 201: ${name}님 환영해요
  • 채널 개별 조회

    • GET /users
    • req: (body) userId // 원래는 header로 숨겨서 받는게 정석!
    • res 200 : usrId, name
  • 채널 개별 삭제

    • DELETE /users
    • req: (body) userId
    • res 200 : ${name}님 다음에 또 봐요!

💡 회원 가입

: userId가 id 대신 key가 되었으므로 가입부터 수정해줘야한다 (데이터를 userId를 사용해서 넣기 때문에)

// users.js

rotuer.post('/join', (req, res) => {
	if(req.body == {}) {
		res.status(400).json({
			message : `입력값을 다시 확인해주세요`
		})
	} else {
		const {userId} = req.body
		db.set(userId, req.body);
		res.status(201).json({
			message : `${db.get(userId).name}님 환영해요`
		})
	}
})

💡 회원 개별 조회

router
	 .route('/users')
	 .get((req, res)=> {
		 let {userId} = req.body;
		 const user = db.get(userId);
		 if(user) {
			 res.status(200).json({
				 useId : user.userId,
				 name : user.name
			 })
		 } else {
			 res.status(404).json({
				 message : `회원 정보가 없어요`
			 })
		 }
	 })

💡 회원 개별 삭제

router
	 .route('/users')
	 .delete((req, res)=> {
		let {userId} = req.body;
		const user = db.get(userId);
		if(user) {
			db.delete(userId);
			res.status(200).json({
				message : `${user.name}님 다음에 또 봐요!`
			})
		} else {
			res.status(404).json({
				message : `회원 정보가 없어요`
			})
		}
	 })

💡 로그인 보충

router.post("/login", function (req, res) {
  const { userId, password } = req.body;
  let loginUser = {};

  db.forEach((user, id) => {
    if (user.userId === userId) {
      loginUser = user;
    }
  });

  if (isExisted(loginUser)) {

    if (loginUser.password === password) {
      res.status(200).json({
	      message : `${loginUser.name}님 로그인 되었어요`
      })
    } else {
      res.status(400).json({
	      message : `비밀번호가 틀렸어요`
      })
    }
  } else {
    res.status(404).json({
	      message : `회원 정보가 없어요`
      })
  }
});

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

개별 삭제. 조회 할 때는 url에 이제 id값을 넣지 않고 body에 userId 넣어서 확인해야함

🍎🍏 오늘의 느낀 점 : 라우터를 사용해 각 파일들을 연결하고, 또 erd를 그려보면서 다시 API를 설계 하면서 데이터베이스를 잘 계획하는게 중요하는구나를 느끼게 되었다. 그리고 예외처리들을 적용해주면서 앞으로 내가 정말 실제로 예외를 처리해 줄 때 많은 것들을 생각해주면서 코드를 짜야겠다는 생각이 들었다.. 클린코드문으로도 적어야하고 생각할 수 있는 다양한 예외들도 다 적어줘야 하니 많은 연습이 필요할 것 같다..!

profile
프론트엔드개발자가 되고 싶어서 열심히 땅굴 파는 자

0개의 댓글