Notice
Recent Posts
Recent Comments
Link
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

개발자공부일기

Node.js 간단한 메모장 만들기 본문

TIL(Today I Learned)

Node.js 간단한 메모장 만들기

JavaCPP 2024. 11. 20. 20:24
// /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()); //미들웨어1
app.use(express.urlencoded({ extended: true }));//미들웨어2

// static Middleware, express.static()을 사용하여 정적 파일을 제공합니다.
app.use(express.static('./assets'));//미들웨어3

app.use((req, res, next) => {//미들웨어4
  console.log('Request URL:', req.originalUrl, ' - ', new Date());
  next();
});

const router = express.Router(); //라우터 생성

router.get('/', (req, res) => {
  return res.json({ message: 'Hi!' }); //아무 요청에 Hi반환
});

// /api 주소로 접근하였을 때, router와 TodosRouter로 클라이언트의 요청이 전달됩니다.
app.use('/api', [router, TodosRouter]);//미들웨어 5

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

미들웨어는 위에서 아래로 실행되고 next()가 없으면 다음 미들웨어를 실행하지 않는다.

미들웨어를 사용할때 next() 또는 res.json()을 꼭 사용해야 한다.그렇지 않으면 무한정으로 요청은 대기한다. 

 

// 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);

각각의 key값이 어떤 유형인지 정의하는 스키마

 

// schemas/index.js

import mongoose from 'mongoose';

const connect = () => {
  mongoose
    .connect(
      // MongoDB와 연결하기 위한 주소.userid에는 ID를 <password>에 설정한 password를 입력
      'mongodb+srv://userid:<password>@express-mongo.ta3gl.mongodb.net/~~~~~',
      {
        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;

MongoDB에 연결하고 성공/실패 여부를 확인하기 위한 코드

 

 

// /routes/todos.router.js

import express from 'express';
// routes/todos.router.js

import Todo from '../schemas/todo.schema.js';

const router = express.Router();

router.post('/todos', async (req, res) => {//데이터를 조회하는동안 멈춰야 하니까 async
    //1. 클라이언트로부터 받은 value데이터 가져오기

    const { value } = req.body;
    //1-5. 만약, 클라이언트가 value데이터를 전달하지 않았을 때, 
    //클라이언트에게 에러 메시지 전달
    if (!value) {
        return res
            .status(400)
            .json({ errorMessage: '해야할 일 데이터가 존재하지 않습니다.' });
    }
    // Todo모델을 사용해, MongoDB에서 'order' 값이 가장 높은 '해야할 일'을 찾습니다.
    //2. 해당하는 마지막 order데이터 조회
    // findOne = 1개의 데이터만 조회
    // sort = 정렬한다. ->어떤 컬름을 기준으로?order
    //exec를 안붙이면 앞에 코드가 promise로 동작하지 않는다=>await 사용불가
    const todoMaxOrder = await Todo.findOne().sort('-order').exec();

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

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

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

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

//해야할 일 목록 조회 API

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

    //2.조회 결과 클라이언트에 반환
    return res.status(200).json({todos});
})

//해야할 일 순서 변경, 완료/해제,내용변경 API
router.patch('/todos/:todoId',async(req,res)=>{
   //req.params는 URL에 정의된 모든 경로 변수들을 키-값 쌍으로 포함하는 객체
   //ex)GET /todos/12345로 요청하면 req.params = { todoId: '12345' }
   const {todoId} = req.params;
    const {order,done,value} = req.body;

    //현재 나의 order가 무엇인지 알아야 한다.
    const currentTodo = await Todo.findById(todoId).exec(); //변경하려는 _id를 조회해서 저장
    if(!currentTodo){
        return res.status(404).json({errorMessage: ' 존재하지 않는 해야할 일 입니다.'});
    }

    if(order){
        const targetTodo = await Todo.findOne({order}).exec(); //내가 바꾸고싶은 번호의 데이터를 조회
        if(targetTodo){
            targetTodo.order = currentTodo.order; //기존에 있던것과 바꾸려는것의 순서 변경
            await targetTodo.save(); //저장
        }

        currentTodo.order = order; //변경하려던 데이터의 번호를 변경
    }
    if(done !== undefined){
        currentTodo.doneAt = done ? new Date() : null; //done이 true면 지금 날짜 할당. 아니면 null
    }

    if(value) {
        currentTodo.value = value; //메모바꾸기
    }

    await currentTodo.save();

    return res.status(200).json({}); //200 상태메세지 반환
});

//할일 삭제

router.delete('/todos/:todoId',async(req,res)=>{
    const {todoId} = req.params;

    const todo = await Todo.findById(todoId).exec(); //삭제하려는 데이터 조회

    if(!todo){
        return res.status(400).json({errorMessage:'존재하지 않는 해야할 일 정보입니다.'});
    }

    await Todo.deleteOne({_id: todoId}); //그 id에 해당하는 데티어 삭제

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




export default router;

todo list를 작성하고 순서를 변경하고 삭제하고 조회하는 코드들

 

전체적으로 많이 어려운 부분은 없었다. 항상 그렇듯 익숙하지 않아서 눈에 잘 안들어온다. 계속 익숙해지려고 코드 따라치고 계속 읽어보는 중이다. 확실히 점점 눈에 드는게 느껴진다 계속 하다보면 언젠가 되겠지