코딩/프로젝트

할일 메모 사이트 제작

이즈99 2024. 5. 17. 02:44
728x90

1.초기화작업(터미널에서 진행)

yarn init -y //초기화작업

yarn add express mongoose 몽구스와 express추가

pacakage.json 파일에 "type" : "module", 추가

 

2.app.js  추가 기본적인 서버구성 express.js로 구성

import express from 'express';

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

// Express에서 req.body에 접근하여 body 데이터를 사용할 수 있도록 설정합니다.
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

const router = express.Router();

router.get('/', (req, res) => {
  return res.json({ message: 'Hi!' });
});

app.use('/api', router);

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

3.html 파일 추가 임시로 사용할 html 파일 추가

-assets 파일 밑에 따로 풀어줌

4. static 미들웨어로 html 파일을 백엔드에 연동

app.use(express.static('./assets'));

express.static() 함수는 app.js 파일 기준으로, 입력 값( 지금은"./assets") 경로에 있는 파일을 아무런 가공 없이 그대로 전달해주는 미들웨어이다. 위의 static 을 이용해서 html의 프론트엔드 파일을 서빙함.

5. Mongoose 스키마 설계

schemas폴더를 만들고 안에 index.js를 만들어 스키마 구성

// schemas/index.js

import mongoose from 'mongoose';

const connect = () => {
  mongoose
    .connect(
      // 빨간색으로 표시된 부분은 대여한 ID, Password, 주소에 맞게끔 수정해주세요!
      'mongodb+srv://username:비밀번호@kimeunjik.8jv9wnu.mongodb.net/?retryWrites=true&w=majority&appName=KimEunJik',
      {
        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;

6. app.js파일에서 MongoDB연결

import connect from './schemas/index.js';
connect();

7. 스키마 설계

// 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.virtual('todoId').get(function () {
  return this._id.toHexString();
});
TodoSchema.set('toJSON', {
  virtuals: true,
});

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

8. 할일 등록 기능 & 조회 기능 구현

등록 기능 구현

  • routes 폴더 추가, todos.router.js 파일 추가
    router.js파일 구성
import express from 'express';

//express로 라우터 구현
const router = express.Router();

//외부로 라우터 보내기
export default router;import express from 'express';
import Todo from '../schemas/todo.schema.js';

//express로 라우터 구현
const router = express.Router();

/* 할일 등록 API */
//async를 사용안하면 등록하는동안 데이터조회가 다 멈출 수 있음
router.post('/todos', async(req, res, next) =>{
    // 1. 클라이언트로 부터 받아온 value 데이터를 가져온다.
    const {value} = req.body;

    // 2. 해당하는 마지막 order 데이터를 조회한다.
    // findOne은 한개의 데이터만 조회한다.
    // sort 는 정렬한다 -> 어떤 컬럼을? -> order을 앞에 - 붙여서 내림차순으로 정렬한다
    // mongoose에서 await 작성하면 항상 exec() 사용
    const todoMaxOrder = await Todo.findOne().sort('-order').exec();
    
    // 3. 만약 존재한다면 현재 해야 할 일을 +1하고, order 데이터가 존재하지 않다면, 1로 할당
    const order = todoMaxOrder ? todoMaxOrder.order + 1 : 1;
    
    // 4. 해야할 일 등록
    const todo = new Todo({value, order});
    await todo.save();

    // 5. 해야할 일을 클라이언트에게 반환한다.
    return res.status(201).json({todo: todo});
})

//외부로 라우터 보내기
export default router;
  • 유효성 검사
    value데이터를 받아오고, find 하기전 value데이터가 존재하는지 체크해 없을경우 error 메시지를 출
// 1-5. 만약, value 데이터를 전달하지 않았을 때, 클라이언트에게 에러 메시지를 전달한다.
    if(!value){
        return res.status(400).json({errorMessage: "해야할 일(value) 데이터가 존재하지 않습니다."});
    }

할일 목록 조회 기능 만들기

/* 해야할 일 목록 조회 API */
router.get('/todos', async(req, res, next) =>{
    // 1. 해야할 일 목록 조회를 진행한다.
    const todos = await Todo.find().sort('-order').exec();

    // 2. 해야할 일 목록 조회 결과를 클라이언트에게 반환한다.
    return res.status(200).json({todos: todos});
})

9. 할일 순서변경, 내용 변경 , 완료 해제기능 구현(Update)

/* 해야할 일 순서 변경, 완료 / 해제 API */
router.patch('/todos/:todoId', async(req, res, next)=>{
    const {todoId} = req.params;
    const {order, done, value} = req.body;

    // 현재 나의 order가 무엇인지 알아야한다.
    const currentTodo = await Todo.findById(todoId).exec();
    if(!currentTodo){
            return res.status(404).json({errorMessage: '존재하지 않는 해야할 일 입니다.'});
    }
    
    if(order){
        const targetTodo = await Todo.findOne({order:order}).exec();
        if(targetTodo){
            targetTodo.order = currentTodo.order;
            await targetTodo.save();
        }

        currentTodo.order = order;
    }
    if(done != undefined){
        currentTodo.doneAt = done ? new Date() : null;
    }

    if(value){
        currentTodo.value = value;
    }
    await currentTodo.save();

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

 

10. 할일 삭제 기능(Delete)

// 할 일 삭제 API
router.delete('/todos/:todoId', async(req, res, next) =>{
    const {todoId} = req.params;

    const todo = await Todo.findById(todoId).exec();
    if(!todo){
        return res.status(404).json({errorMessage: '존재하지 않는 할 일 입니다.'});
    }

    await Todo.deleteOne({_id: todoId});

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