TIL - 에러 핸들링과 퀴즈 리뷰

sumin·2022년 6월 13일
💡 강의노트와 세션 영상을 들은 후 다시 복습하기 위해 기록!!

📌 Error Handling

  • 사용자가 서비스를 이용하는 동안 발생할 수 있는 에러를 미리 사전에 예측하여, 이용자의 사용 흐름이 막히지 않도록 유도하는 과정이 에러 핸들링이라고 한다

✔ 에러 핸들링(Error Handling)

  • 개발자가 의도하지 않고(오타 등등) 컴퓨터가 자바스크립트 문법을 실행하는 과정 자체에서 더 이상 진행할 수 없어서 발생하는 에러
const numberOne = 1
consloe.log(numberOne) // 함수 이름 오류 `console.log`

✔ 예외 핸들링(Exception Handling)

  • 개발자가 의도적으로 발생시키는 예외 사항
  • 컴퓨터 언어 입장에서는 에러가 아닌 개발자의 의도와 다른 방향으로 유저가 서비스를 이용하는것을 막기 위해 예외 처리를 해주는 것을 예외 핸들링이라고 한다
1. 회원가입에 사용되는 이메일에 `@` 가 들어가지 않으면 `에러 반환`
2. 비밀번호가 10자 미만이라면 `에러 반환`
3. 이미 가입되어 있는 계정으로 가입 시도를 할 때 `에러 반환`
  • 잘못된 방식으로 서비스를 이용하기 전에 예외 상황을 미리 일으켜 에러를 발생시키고 클라리언트(프론트엔드) 개발자에게 에러 상황 에러 코드로 알린다 프론트엔드 개발자는 에러를 반환받아서, 사용자(고객)에게 적절한 안내 문구를 띄워준다
const { email, password } = req.body

if (!email.includes('@')) {
  return new Error('EMAIL_INVALID')
}

if (password.length < 10) {
  return new Error('PASSWORD_INVALID')
}
...

💥 throw와 try-catch

✔ throw

  • 일반적으로 예외 상황에 에러를 발생시키는 방법은 throw이다
    어떤 에러인지를 설명하기 위해 message 부분이 필수로 들어간다
  • throw는 여기 이 지점에서 특정 에러가 발생했음을 알리고, 이 에러가 발생하면 상위 모듈은 그에 맞는 액션을(코드) 취한다 -> try-catch에서 수행하도록 설계되어있음

✔ try-catch

  • try-catch문은 잠재적인 에러가 발생할 가능성이 있는 부분에서 에러를 처리하기 위한 용도로 사용, try 블록에는 에러가 발생할 가능성이 있는 코드를 넣어두고, catch 블록에는 에러가 발생했을 때를 대비한 행동을 넣어둔다
try {
  const a = someFunc(); // <-- 함수 실행이 잘못될 확률이 있으므로 try 내부에 존재.
  let aDouble = a + a; // <-- 변수 할당이 잘못되어 있을 확률이 있으므로 try 내부에 존재.
  let nothing = 1 + 4; // <-- try에 있을 필요가 없음.
} catch {}
try {
  const { email, password } = req.body

  if (!email.includes('@')) {
    const error = new Error('EMAIL_INVALID')
    error.statusCode = 400
    throw error
  }

  if (password.length < 10) {
    const error = new Error('PASSWORD_INVALID')
	error.statusCode = 400
	throw error
  }
...
} catch (err) {
  console.log(err) 
  // 어떠한 형태의 에러가 발생하든, 에러를 콘솔에 찍어서 개발자에게 보여줍니다.
  return res.json({
}

user-signup-server.js

app.post("/users/signup", async (req, res) => {
  try {
    const { name, nickname, email, password } = req.body;
    
    const dataUsers = await prisma.$queryRaw`
    SELECT * FROM users;`;

    if (password.length < 8) {
      const pwErr = new Error("PASSWORD_TOO_SHORT");
      pwErr.statusPwErr = 400;
      throw pwErr;
    }

    for (let i = 0; i < dataUsers.length; i++) {
      if (dataUsers[i].nickname === nickname || dataUsers[i].email === email) {
        const overlapErr = new Error("EXSITING_USER");
        overlapErr.statusOverlap = 409;
        throw overlapErr;
      }
    }

    const createdUser = await prisma.$queryRaw`
      INSERT INTO users(name, nickname, email, password) 
      VALUES (${name}, ${nickname}, ${email}, ${password});`;

    return res.status(201).json({ message: "SIGNUP_SUCCESS" });
  } catch (err) {
    console.log(err);
    console.log("비밀번호 에러 status : ", err.statusPwErr);
    console.log("중복사용자 에러 status : ", err.statusOverlap);
    return res
      .status(err.statusPwErr || err.statusOverlap || 500)
      .json({ message: err.message });
  }
}); //회원가입

📌 node.js Quiz 리뷰

01. express

app.get("/", (_, res) => {
  res.send('server on');
});
  • 변수에 _(언더바)쓴 이유
    이름이 아닌 순서에 영향을 받는 매개변수 이기 때문에
    (requset, response) 등 다양한 이름 가능! req를 쓰지 않기 때문에 -(언더바)를 사용한 것이고, 뒤에 변수는 res가 될 수 있는 것이다
HTTP는 요청, 응답 형태의 통신, 즉 클라이언트가 요청을 해야 서버가 응답을 보내준다
라우터로 method와 url을 대기해서 어떤 방식으로 응답을 줄 것인지 콜백 함수로 표현하는 것이다
JSON : 데이터의 포맷, 형태 (html 등등)

app.method('path', handler function)

Express 모듈을 임포트 한 후 함수를 실행해서 app 이란 변수에 담는 것이 컨벤션 이다
클라이언트의 요청을 처리하는 http server application 이라고 볼 수 있음

  1. 요청을 받을 http method로 함수를 app 에 붙인다.
  2. 요청을 받을 endpoint url 을 string 으로 첫번째 인자에 넣는다.
  3. 두번째 인자는 요청과 응답을 인자로 받는 콜백함수이다.
    즉, 각각의 메소드와 엔드포인트에 대해 처리하는(핸들링) 함수가 된다.

처음 sql을 사용할 때 데이터를 삭제했다가 수정하고 다시 create하는 형식으로 만들어 졌었다


04. CURD (create) 문제

▽ 멘토님 풀이

//Create Transfer Object(DTO) : 데이터 전송 객체
// : 상위함수에서 하뉘 함수로 데이터를 전송함
app.post('/feed', (req, res) => {
	const createFeedDto = req.body; 
  // body 형태는 README.md에서 확인해주세요.
  // feed를 생성할 수 있게 매개변수를 넘겨주세요.
  createFeed(createFeedDto);
	res.status(201).json({ message: 'created' });
});

▽ 내가 한 풀이

app.post('/feed', (req, res) => {
	req.body; 
  // body 형태는 README.md에서 확인해주세요.
  // feed를 생성할 수 있게 매개변수를 넘겨주세요.
	createFeed(readFeedById);
	res.status(201).json({ message: 'created' });
});

05. CURD (update) 문제

mock-database.js

  • 첫번째 방법 : feeds를 삭제하고 다시 create해서 update 하기
// db feeds 테이블에 데이터(row)가 하나 존재한다고 가정합니다.
const feeds = [
  {
    id: 1,
    author: {
      profileImage: 'profile image url',
      name: 'Andre Tan'
    },
    title: '첫번째 피드 제목입니다.',
    content: '피드 내용입니다. 현재 목 데이터베이스를 이용하여 구현하고 있습니다.',
    images: [
      'feed image url 1',
      'feed image url 2'
    ]
  }
];

let insertId = 2; // auto_increment

function readFeedById(id) {
	return feeds.find((feed) => (feed.id == id));
}

function readFeeds() {
	return feeds;
}
//(3) 함수 생성
function createFeedWithAutoIncrement(createFeedDto){
	createFeed(insertId++, createFeedDto)
}


//(2) feed가 생성될 때마다 id도 ++되어야 하기 때문에 그에 해당하는 함수를 만들어 주어야 한다
function createFeed(id, createFeedDto) { //(2)-1 id 추가
  const { author, title, content, images } = createFeedDto;

	feeds.push({
		id, //(2)-2 id: insertId++ -> id : id
		author,
		title,
		content,
		images
	});
}

function deleteFeed(id) {
  const deleteId = feeds.findIndex((feed) => feed.id == id);

  feeds.splice(deleteId);
}

function updateFeed(id, updateFeedDto) {
  // 여기를 구현해주세요.
  
  //1. 삭제하고 수정해서 다시 create하기
  // deleteFeed(id)
  // createFeed(updateFeedDto) (x)
  // 왜냐면 ID가 바뀌기 때문 -> 32번째 줄 id: insertId++,
  // 리팩토링을 해주어야 함
  
  //(4) createFeed에 id 추가
  deleteFeed(id)
  createFeed(id, updateFeedDto)
}

module.exports = { readFeedById, readFeeds, createFeed, deleteFeed, updateFeed };
  • 두번째 방법 : ID를 이용해서 index를 찾은 뒤 바꾸는 방법 (선택한 방법)
// db feeds 테이블에 데이터(row)가 하나 존재한다고 가정합니다.
const feeds = [
  {
    id: 1,
    author: {
      profileImage: 'profile image url',
      name: 'Andre Tan'
    },
    title: '첫번째 피드 제목입니다.',
    content: '피드 내용입니다. 현재 목 데이터베이스를 이용하여 구현하고 있습니다.',
    images: [
      'feed image url 1',
      'feed image url 2'
    ]
  }
];

let insertId = 2; // auto_increment

function readFeedById(id) {
	return feeds.find((feed) => (feed.id == id));
}

function readFeeds() {
	return feeds;
}

function createFeed(createFeedDto) {
  const { author, title, content, images } = createFeedDto;

	feeds.push({
		id: insertId++,
		author,
		title,
		content,
		images
	});
}

function deleteFeed(id) {
  const deleteId = feeds.findIndex((feed) => feed.id == id);

  feeds.splice(deleteId);
}

function updateFeed(id, updateFeedDto) {
  // 여기를 구현해주세요.
  const feedIndex = feeds.findIndex(feed => feed.id == id)
  //(1) findIndex()로 feeds 안에 있는 데이터들을 순회하며, 
  // 객체 하나하나를 feed라는 콜백 매개 변수 안에 넣는다 
  //-> feed의 id가 updateFeed의 id와 같으면 index를 반환해 준다
  feeds[feedIndex] = {...updateFeedDto, id}
  //(2) 해당 feeds의 index로 변경해 주면 feeds 안에 데이터가 updateDto로 바뀐다. 
  //그리고 안에 id가 없기 때문에 id를 뒤에 담아주어야 한다
  // * 스프레드 연산자가 앞에 있는 이유는 뒤쪽으로 오면 덮어씌워질 수 있기 때문에 주의해야 한다!
}

module.exports = { readFeedById, readFeeds, createFeed, deleteFeed, updateFeed };

app.js

const express = require('express');
const { updateFeed } = require('./mock-database');

const app = express();

app.use(express.json());

app.get("/", (_, res) => {
  res.send('server on');
});

app.put('/feed/:id', (req, res) => {
  // id 와 body를 이용하여 feed를 수정해주세요.
  const { id } = req.params;
  // req.body라고 해도 상관없지만 나중에 많은 데이터를 생성하고
  // 가독성을 높이기 위해 변수에 담아 주는 것이 좋다!
  const updateFeedDto = req.body;
  updateFeed(id, updateFeedDto)
  res.json({message : "success"})
});

module.exports = app;

이번 Node.js의 퀴즈는 어렵지 않았지만, 문제를 이해하는 데 시간이 너무 오래 걸렸다... 아 그걸 어려웠다고 하는건가 ㅎㅎ;;;; 자바스크립트에 약한 내 탓이라고 생각된다 ㅎ 공부를 더 열심히 해야겠다.😂😂😂

0개의 댓글