[23.10.29] TIL

yy·2023년 10월 29일

개발일지

목록 보기
16/122

오늘 할 일

(미완) 1. node 1주차 실습 진행 (todolist만들기CRUD)

참고: Node.js 입문 2주차

Todolist 만들기

필요한 기능 살펴보기

✔️ 1. 할 일 추가하기
✔️ 2. 할 일 목록 보기
✔️ 3. 할 일 내용 변경하기
✔️ 4. 할 일 순서 변경하기
✔️ 5. 할 일 완료하기
✔️ 6. 할 일 완료 해제하기
✔️ 7. 할 일 삭제

🧠 기능 구현

1. 새 폴더 생성 -> yarn init -y 로 프로젝트 초기화

2. yarn add express mongoose 설치

3. ES6를 사용할거니까 package.json에 "type": "module" 를 추가

4. 만들 기능 API 확인


5. 스키마(모델) 만들기

// schemas/index.js
import mongoose from 'mongoose';
const connect = () => {
  mongoose
    .connect(
      // <password>을 빼고 비번 넣기
      'mongodb+srv://sparta-user:<password>@express-mongo.5vbi9ch.mongodb.net/?retryWrites=true&w=majority', 
      {
        dbName: 'todo_memo', // todo_memo 데이터베이스명을 사용합니다.
      },
    )
    .then(() => console.log('MongoDB 연결에 성공하였습니다.'))
    .catch((err) => console.log(`MongoDB 연결에 실패하였습니다. ${err}`));
};
mongoose.connection.on('error', (err) => {
  console.error('MongoDB 연결 에러', err);
});
export default connect;

// schemas/todo.schema.js
import mongoose from "mongoose";
const TodoSchema = new mongoose.Schema({
  value: {
    type: String,
    require: true
  },
  order: {
    type: Number,
    require: true
  },
  doneAt: {
    type: Date,
    require: false
  }
});

// 프론트엔드 서빙을 위한 코드입니다. 모르셔도 괜찮아요!
TodoSchema.virtual('todoId').get(function () {
  return this._id.toHexString();
});
TodoSchema.set('toJSON', {
  virtuals: true,
});

export default mongoose.model("Todo", TodoSchema)

6. app.js 작성

import express from 'express';
import connect from './schemas/index.js';
import TodosRouter from './routes/todos.router.js'

const app = express();
const PORT = 3000;

connect();

// Express에서 req.body에 접근하여 body 데이터를 사용할 수 있도록 설정합니다.
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// static Middleware, express.static()을 사용하여 정적 파일을 제공합니다.
app.use(express.static('./assets'));

const router = express.Router();

router.get('/', (req, res) => { //라우터 테스터
  return res.json({ message: '메인 화면이야!어때 멋지지!' });
});

app.use('/api', [router, TodosRouter]);

app.listen(PORT, () => {
  console.log(PORT, '포트로 서버가 열렸어요!');
});

7. API기능 구현 (1,2완료)

✔️ 1. 할 일 추가하기
✔️ 2. 할 일 목록 보기

// /routes/todos.router.js
import express from 'express';
import mongoose from 'mongoose';
import Todo from '../schemas/todo.schema.js';

const router = express.Router();

/**  할 일 등록 **/
//localhost:3000/api/todos POST
router.post('/todos', async(req, res) => {
  const { value } = req.body;
  if (!value) {
    return res.status(400).json({ errorMessage: "입력 값이 없어요!"});
  };

  const todoMaxOrder = await Todo.findOne().sort('-order').exec();
  const order = todoMaxOrder ? todoMaxOrder.order + 1 : 1;

  const todo = new Todo({ value, order });
  await todo.save();

  return res.status(201).json({ todo : todo });
});

/**  할 일 목록 조회 **/
//localhost:3000/api/todos GET
router.get('/todos', async(req, res) => {
  const todos = await Todo.find().sort('-order').exec();
  return res.status(200).json({ todos });
});

export default router;

✔️ 3. 할 일 내용 변경하기
✔️ 4. 할 일 순서 변경하기
✔️ 5. 할 일 완료하기
✔️ 6. 할 일 완료 해제하기

/**  할 일 내용 변경 **/
//localhost:3000/api/todos/:todoId PATCH
//:todoId : 경로매개변수. 어떤 해야할 일을 수정할지 알아야해서 넣은거임
router.patch('/todos/:todoId', async (req, res) => {
  //변경 '해야하는 일'의 id값 갖고오기 (경로매개변수에서 갖고오기)
  //그냥 order를 경로매개변수로 찾으면 안되는건가..? 안되나..? body에 들어있으니까인가?
  const { todoId } = req.params;
  //'해야하는 일'을 몇번째 순서로 설정할지 order값 요청에서 받기
  const { order, done, value } = req.body;

  //현재 나의 order가 뭔지 알아야한다.
  //변경하려는 '해야하는 일'에 대한 내용 모델에서 찾아 갖고오기.
  const currentTodo = await Todo.findById(todoId).exec();
  //'해야하는 일'이 없다면 에러메시지로 응답
  if (!currentTodo) {
    return res.status(404).json({ errorMessage: "존재하지않는 todo 데이터입니다." });
  };

  //❗'해야하는 일'의 순서 변경
  if (order) {
    const targetTodo = await Todo.findOne({ order: order }).exec();
    if (targetTodo) {
      targetTodo.order = currentTodo.order;
      await targetTodo.save(); //이건 어디에 저장이 되는거야?
      // 이건 어떤가?!
      // targetTodo.order = currnetTodo.order;
      // currentTodo.order = order;
      // await tagetTodo.save(); 
    }
    currentTodo.order = order;
  }

  //❗❗'해야하는 일' 완료 / 해제
  if (done !== undefined) {
    //변경하려는 '해야하는 일'의 doneAt값을 변경
    currentTodo.doneAt = done ? new Date() : null;
  }

  //❗❗❗'해야하는 일' 내용 변경
  if (value) {
    currentTodo.value = value;
  };

  //변경된 '해야하는 일'을 저장
  await currentTodo.save(); //이건 어디에 저장이 되는거야?

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

✔️ 7. 할 일 삭제

/** 할 일 삭제 **/
//localhost:3000/api/todos/:todoId DELETE
router.delete('/todos/:todoId', async (req, res) => {
  //삭제할 '해야하는 일'의 id값 가져오기
  const { todoId } = req.params;

  //삭제하려는'해야하는 일' 가져오기. 만약 해당아이디를 가진 일이 없으면 에러처리
  const todo = await Todo.findById(todoId).exec();
  if (!todo) {
    return res.status(400).json({ errorMessage: "해당 내용이 없어요!" });
  };

  //조회된 todo를 삭제
  await Todo.deleteOne({ _id: todoId }).exec();

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

👊💥트러블 슈팅

첫번째

할 일 등록, 할 일 목록 조회 API를 만들고 나서 서버를 실행시키려고 하니 에러가 떴다. todos.find()에서 시간을 오래 잡아먹었다고 하는거 같았다.

아무래도 몽고DB를 연결하는부분에서 잘못한거같아 코드를 다시 봤다.
그랬더니 발견한 오류. schemas 폴더에서 index.js에서 몽고DB와 연결하는 코드가 있었는데 그걸 이제 app.js에서 불러와서 사용했어야했다. 불러오기까지만 하고 실행을 안시켰던 것..!

얼탱무. 했더니 오류없이 MongoDB에 연결이 성공했다.

두번째

mongoDB의 모델(스키마, 테이블)을 쓰려면 그에 맞는 메소드를 써야하는데 아직 낯설어서 자꾸 실수를 하게된다. 대표적인게 find(), findOne(), findById() 이들 매개변수로 들어가는 변수의 타입이 자꾸 헷갈린다.

Model.find({객체})
Model.findOne({객체})
Model.findById(id값)

[참고자료]

findOne() mongoose site
find() mongoose site
findById() mongoose site

profile
시간이 걸릴 뿐 내가 못할 건 없다.

0개의 댓글