[TIL] 24.09.02 MON

GDORI·2024년 9월 2일
0

TIL

목록 보기
29/79
post-thumbnail

오늘은 Node 강의 입문주차 일부를 듣고 실습해보는 시간을 가졌다. 전체적인 흐름은 이해가 되나 보지 않고 코딩할 정도는 아직 먼 것 같다.

[ 오늘 푼 알고리즘 문제 ]

12977. 소수 만들기
161989. 덧칠하기

간단한 express 서버

HTTP 요청을 받기 위하여 express 라이브러리를 활용해 서버를 만들어줍니다.

import express from 'express'

const app = express();
// express의 인스턴스를 app으로 지정합니다.
const port = 3000;
// 포트는 3000번입니다.

app.use(express.json());
app.use(express.urlencoded({extended : true}));
// express에서 들어오는 요청의 데이터를 파싱하는 
// 미들웨어로 JSON과 URL-encoded 형식의 데이터를 처리합니다.

const router = express.Router();
// router 객체를 생성합니다.
// router는 자체적으로 미들웨어를 가질 수 있으며,
// 특정 경로와 관련된 요청을 독립적으로 처리합니다.

router.get('/', (req, res) => {
	return res.json({ message : 'Hi' });
});
// root로 접속하였을 때 json을 리스폰 합니다.

app.use('/api', router);
// /api 에 대한 요청을 router 미들웨어로 처리합니다.

app.listen(PORT, ()=>{
	console.log(PORT, '포트 연결 성공'
});
// 항시 포트를 추적하다가 맞는 PORT의 요청이 들어왔을 경우 
//로그를 출력하고 명령을 수행합니다.

asset 파일 서빙

프론트엔드 파일을 담고 있는 asset 폴더를 Express 서버에서 접근할 수 있게 정적 파일 미들웨어를 사용합니다.

app.use(express.static('./assets'));
// static Middleware를 사용하여 정적 파일을 제공합니다.

Todo 사이트 Schema 설계

  1. 할 일 추가하기
  2. 할 일 조회하기
  3. 할 일 수정하기
  4. 할 일 순서 변경하기
  5. 할 일 완료하기
  6. 할 일 완료 해제하기

기능을 바탕으로 필요한 데이터 도출

  1. 할 일 추가하기, 조회하기, 수정하기
  • 해야할 일에 대한 내용을 담을 문자열 형식의 필드 필요
  1. 할 일 순서 변경하기
  • 해야할 일의 순서를 저장할 숫자 형식의 필드 필요
  1. 할 일 완료, 완료해제하기
  • 완료 날짜를 저장할 Date 형식의 필드 필요
  • 완료 시 날짜, 미완료 시 NULL

Todo Schema 모델

// schemas/todo.schema.js

import mongoose from 'mongoose';

const TodoSchema = new mongoose.Schema({
  value: {
    type: String,
    required: true, // value 필드는 필수 요소입니다.
  },
  order: {
    type: Number,
    required: true, // order 필드 또한 필수 요소입니다.
  },
  doneAt: {
    type: Date, // doneAt 필드는 Date 타입을 가집니다.
    required: false, // doneAt 필드는 필수 요소가 아닙니다.
  },
});

// TodoSchema를 바탕으로 Todo모델을 생성하여, 외부로 내보냅니다.
export default mongoose.model('Todo', TodoSchema);

할 일 추가 API 구현


// routes/todos.router.js

import Todo from '../schemas/todo.schema.js';
// 스키마 모델을 불러옵니다.


router.post('/todos', async (req, res) => {
  // 클라이언트에게 전달받은 value 데이터를 변수에 저장합니다.
  const { value } = req.body;
  // 구조분해할당으로 JSON에 들어있는 value에 대한 값을 value 변수에 할당합니다.
  
    // value가 존재하지 않을 때, 클라이언트에게 에러 메시지를 전달합니다.
  if (!value) {
    return res
      .status(400)
      .json({ errorMessage: '해야할 일 데이터가 존재하지 않습니다.' });
  }
  
  
  // Todo모델을 사용해, MongoDB에서 'order' 값이 가장 높은 '해야할 일'을 찾습니다.
  const todoMaxOrder = await Todo.findOne().sort('-order').exec();
  // exec를 사용하는 이유는 promise를 반환받기 위함이며, 사용하지 않으면 await가 무용지물 됩니다.
  // findOne은 단 하나의 검색 결과만 가져옵니다.
  // -order를 했을 경우 내림차순으로 조회합니다.
  

  // 'order' 값이 가장 높은 도큐멘트의 1을 추가하거나 없다면, 1을 할당합니다.
  const order = todoMaxOrder ? todoMaxOrder.order + 1 : 1;

  // Todo모델을 이용해, 새로운 '해야할 일'을 생성합니다.
  const todo = new Todo({ value, order });

  // 생성한 '해야할 일'을 MongoDB에 저장합니다.
  await todo.save();

  // 성공했을 경우 스테이터스와 JSON을 반환합니다.
  return res.status(201).json({ todo });
});

export default router;

할 일 조회 API 구현


router.get('/todos', async (req, res) => {
  // Todo모델을 이용해, MongoDB에서 'order' 값이 가장 높은 '해야할 일'을 찾습니다.
  const todos = await Todo.find().sort('-order').exec();

  // 찾은 '해야할 일'을 클라이언트에게 전달합니다.
  return res.status(200).json({ todos });
});

할 일 순서 변경 API 구현


// routes/todos.router.js

router.patch('/todos/:todoId', async (req, res) => {
  // 변경할 '해야할 일'의 ID 값을 가져옵니다.
  const { todoId } = req.params;
  // '해야할 일'을 몇번째 순서로 설정할 지 order 값을 가져옵니다.
  const { order } = req.body;

  // 변경하려는 '해야할 일'을 가져옵니다. 만약, 해당 ID값을 가진 '해야할 일'이 없다면 에러를 발생시킵니다.
  const currentTodo = await Todo.findById(todoId).exec();
  if (!currentTodo) {
    return res
      .status(404)
      .json({ errorMessage: '존재하지 않는 todo 데이터입니다.' });
  }

  if (order) {
    // 변경하려는 order 값을 가지고 있는 '해야할 일'을 찾습니다.
    const targetTodo = await Todo.findOne({ order }).exec();
    if (targetTodo) {
      // 만약, 이미 해당 order 값을 가진 '해야할 일'이 있다면, 해당 '해야할 일'의 order 값을 변경하고 저장합니다.
      targetTodo.order = currentTodo.order;
      await targetTodo.save();
    }
    // 변경하려는 '해야할 일'의 order 값을 변경합니니다.
    currentTodo.order = order;
  }

  // 변경된 '해야할 일'을 저장합니다.
  await currentTodo.save();

  return res.status(200).json({});
});

할 일 삭제하기


// routes/todos.router.js

/** 할 일 삭제 **/
router.delete('/todos/:todoId', async (req, res) => {
  // 삭제할 '해야할 일'의 ID 값을 가져옵니다.
  const { todoId } = req.params;

  // 삭제하려는 '해야할 일'을 가져옵니다. 만약, 해당 ID값을 가진 '해야할 일'이 없다면 에러를 발생시킵니다.
  const todo = await Todo.findById(todoId).exec();
  if (!todo) {
    return res
      .status(404)
      .json({ errorMessage: '존재하지 않는 todo 데이터입니다.' });
  }

  // 조회된 '해야할 일'을 삭제합니다.
  await Todo.deleteOne({ _id: todoId }).exec();

  return res.status(200).json({});
});

주의할 점

router handler callback 에 async function을 사용하면, 서버가 종료될 위험이 있습니다. async에서 발생되는 에러를 처리하는 코드가 없기 때문에 try-catch 구문을 사용하여 처리해야 합니다.

try-catch 구문을 사용한 에러방지


router.get('/todos', async(req, res) => {
  try{
    const todos = await Todo.find().sort('-order').exec();

  	return res.status(200).json({ todos });
  	
  }catch(error){
  	console.error(error);
    return res.status(500).json({errorMessage : "서버 오류"});
  }
  
});

라이브러리를 사용한 에러방지

다른 방법으로는 express-async-handler 를 사용하는 방법이 있습니다.

import asyncHandler from 'asyncHandler';

router.get('/todos', asyncHandler(async (req, res) => {
 
  const todos = await Todo.find().sort('-order').exec();
  
  return res.status(200).json({ todos });
}));
profile
하루 최소 1시간이라도 공부하자..

0개의 댓글