티스토리 뷰

백엔드 설계 작업

 

REST API

1. 할일 추가하기 → POST / api / todos

2. 할일 목록 보기 → GET / api / todos

3. 할일 내용 변경하기 → PATCH / api / todos / :todoId

4. 할 일 순서 변경하기 → PATCH / api / todos / :todoId

5. 할 일 완료하기 → PATCH / api / todos / :todoId

6. 할 일 완료 해제하기 → PATCH / api / todos / :todoId

6. 할 일 삭제 → DELETE / api / todos / :todoId

※주의 ※

더보기

경로 설정할 때 REST API 즉, 네트워크 표현 수단을 사람이 봐도 이해하기 쉬운 표현으로 정의 하기 위해

seememo, getmemo등과 같이 헷갈리는 표현을 막고자 동사를 없애고 명사로 표기합니다.

 

그렇게 되면 memo라는 명사만 남게 되어 경로를 설정할 때 GET/ memo 이런식으로 하면 되는데

백엔드로 향하는 경로와 프론트엔드로 향하는 경로가 겹칠수 있습니다.

 

메모를 보여주는 파일도 /memo, 서버를 가리키는 경로도 GET/memo 이렇게 되버리면 서버는 혼란스러워합니다.

 

그렇기 때문에 주소를 확실히 구분해주기 위해서 서버로 향하는 경로는

/api를 붙여주어서 구분해 주도록 합니다.

 

GET /api/memo → 서버로 향하는 화면에 메모를 보여주기 위한 API경로

/memo → 프론트엔드 파일을 가리키는 주소

 

사전 작업 정리

1. Node.js - Express.js 서버 → API를 구현하기 위한 Express.js

2. MongoDB, mongoose → 할일 목록을 저장할 NoSQL - MongoDB

3. 프론트 설계 작업

 

 

Node.js - Express.js  -  API 서버 준비하기

 

프로젝트 초기화 하기

yarn init -y

 

라이브러리 설치하기(express, mongoose)

yarn add express mongoose

ES6 모듈(import/export)를 사용하기 위해 package.json의 type을 module로 설정해 줍니다.

 

 

memo를 만들기 위한 서버 준비

// app.js
import express from 'express'; //express 사용을 위한 import
import connect from './schemas/index.js'; // app.js에서 connect함수를 하용하기 위함 import
import TodosRouter from './routes/todos.router.js'; //todos.router.js의 router를 사용하기 위한 import

const app = express(); //라우트, 미들웨어, HTTP 요청 처리 등을 정의하기 위한 Express애플리케이션의 인스턴스 생성
const PORT = 3000; //포트번호 설정

connect();//MongoDB와의 연결 시도

// app.use - 미들웨어 설정
app.use(express.json()); // 클라이언트의 요청(Request)을 받을때 req.body에 접근하여 body데이터를 사용할 수 있도록 설정
app.use(express.urlencoded({extended:true})); //폼데이터나 쿼리스트링 형식의 URL-encoded데이터를 이해하고 처리할 수 있도록 설정
                                             //extended: true는 쿼리스트링 라이브러리를 사용하도록 확장된 옵션을 설정하는 것

app.use(express.static('./assets')); // 클라이언트에게 정적파일들을 제공하기위한 미들웨어 설정. 

const router = express.Router(); // 라우터 인스턴스 생성 - express.Router는 라우팅을 모듈화하고 더 효율적으로 구성할 수 있게 해주는 기능

router.get('/',(req,res)=>{
    return res.json({messege:'안녕'});
});

app.use('/api',[router,TodosRouter]); // api로 시작된 경로는 router와 TodosRouter로 클라이언트의 요청이 전달

app.listen(PORT, () => { // Express 애플리케이션에서 지정된 포트에서 실행, 웹 서버를 실행하고 클라이언트 요청 받을수 있도록 구성.
    console.log(PORT, '포트로 서버가 열렸어요!');
});

 

 

프론트 엔드 파일 설정

assets라는 폴더에 프론트 파일 (정적파일) js, css, html을 넣어줍니다.

 

명령어 node app.js 로 서버를 켜보면 켜지는걸 확인 할수 있며 해당 서버로 들어가면

http://localhost:3000

 

input창과 버튼을 볼수 있습니다.

 

Mongoose Schema 설계

 

MongoDB에 저장하기 위한 스키마 설정 폴더 및 파일 생성.

// schemas/index.js
import mongoose from 'mongoose'; //Mongoose는 MongoDB와 상호작용하기 위한 ODM(Object Data Modeling) 라이브러리

const connect = () => { //MongoDB에 연결하는 역할
    mongoose
        .connect( //connect 메서드를 사용하여 연결정보를 입력하고 MongoDB에 연결시도
            '문자열 입력 위치', // MongoDB클러스터의 주소와 사용자 인증 정보를 포함한 연결 문자열입력 & 환경 변수로 관리
            {
                dbName: 'todo_memo', // todo_memo 데이터베이스명을 사용합니다.
            },
        )
        .then(() => console.log('MongoDB 연결에 성공하였습니다.'))
        .catch((err) => console.log(`MongoDB 연결에 실패하였습니다. ${err}`));
};

mongoose.connection.on('error', (err) => { // DB연결에 에러가 발생하면 해당에러를 콘솔에 출력
    console.error('MongoDB 연결 에러', err);
});

export default connect;

 

할 일 메모사이트 Schema 설계

1. 할일 추가하기,할일 목록 보기,할일 내용 변경하기

공통된 할일 = value, 문자열(String) 형식

 

2. 할 일 순서 변경하기

순서 정의 = order, 숫자(Number) 형식

 

3. 할 일 완료하기, 할 일 해제하기

완료 시간 확인 = doneAt, 날짜(Date) 형식

 

설계한대로 Schema 작성

스키마 작성을 위한 파일 경로

// schemas/todo.schema.js
import mongoose from "mongoose";

const TodoSchema = new mongoose.Schema({ //스키마 정의하기
    value: {
        type: String,
        require: true, // value(할일) 필수 요소
    },
    order: {
        type: Number,
        require: true, // order(순서) 필수 요소
    },
    doneAT: {
        type: Date,
        require: true, // doneAt(완료날짜) 필수요소 x
    },
});

// 프론트엔드 서빙을 위한 코드
TodoSchema.virtual('todoId').get(function () {
    return this._id.toHexString();
});
TodoSchema.set('toJSON', {
    virtuals: true,
});


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

 

 

각 기능들의 api구현

해당 기능에 맞는 라우터를 생성하고 app.js에서 이동할수 있는 Router를 등록합니다.

라우터기능을 하는 폴더 및 파일 생성

기능 정의 관계 정의 하기

1. order(할일 순서)는 데이터가 생성될 때마다 순서를 가질 수 있게 만들어 주는 필드입니다.

    가장 최근에 추가된 '해야할 일'은 order값이 높고 order값이 높은 데이터는 할일 목록의 상단에 위치하게 됩니다.

 

2. 들어간 데이터 펼쳐주기

 

3. 데이터 순서 변경하기. 해당 번호를 요청하면 존재하는지 확인을 한후 존재하면 서로의 번호를 3-4, 4-3으로 바꿔줍니다.

 

4. doneAt(할일완료)는 done값이 true로 전달되면, 해당 할일이 완료된 것으로 간주하고 doneAT필드에 현재시간 기록합니다.

    false로 전달되면 doneAt필드는 null로 수정되어야 합니다.

 

5. 삭제는 전달받은 id를 바탕으로 해당 todo데이터를 삭제합니다.

// /routes/todos.router.js

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

const router = express.Router();

/* 데이터 삽입 */
router.post('/todos', async (req, res) => {
    // 클라이언트에게 전달 받은 value데이터를 구조분해할당을 사용하여 변수에 저장
    const { value } = req.body

    // value가 존재하지 않을 때, 클라이언트에게 에러 메시지를 전달
    if (!value) {
        return res
            .status(400)
            .json({ errorMessage: '해야할 일 데이터가 존재하지 않습니다.' });
    }

    // MongoDB데이터베이스에서 Todo모델의 데이터를 검색하고 order필드를 기준으로 내림차순(-)으로 정렬한후 최대값 찾는 과정.
    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 });
});



/* 데이터 조회 */
router.get('/todos', async (req, res) => {

    // Todo모델을 이용해, MongoDB에서 'order'값이 가장 높은 '해야할일'을 찾음
    const todos = await Todo.find().sort('-order').exec();

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




/* 데이터 순서 변경, 할일 완료 */
router.patch('/todos/:todoId', async (req, res) => {
    // 바뀌기전 할일의 id값
    const { todoId } = req.params // 동기적으로 변하는 :todoId값을 가져옴

    // 바꿔질 할일의 번호, 완료 시점
    const { order, done } = req.body // body의 값을 가져옴

    // validation - 유효성검사
    const currentTodo = await Todo.findById(todoId).exec();
    if (!currentTodo) {
        return res
            .status(404)
            .json({ errmessege: '존재하지 않는 todo데이터' })
    }

    if (order) { //order가 있다면 순서를 변경하는 로직
        const changeTarget = await Todo.findOne({order}).exec();
        if (changeTarget) {
            changeTarget.order = currentTodo.order;
            await changeTarget.save(); // 변경사항 저장
        }
        currentTodo.order = order;
    }

    if (done !== undefined) {
        // 변경하려는 '해야할 일'의 doneAt 값을 변경합니다.
        currentTodo.doneAt = done ? new Date() : null;
    }

    currentTodo.save();
    return res.status(200).json({}); // 
})



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

    // 삭제하려는 '해야할 일'을 가져오는데 없으면 존재 x알림
    const currentTodo = await Todo.findById(todoId).exec() // 명시적으로 id를 찾는다고 했으므로 값만 넣어주면 됨.
    if(!currentTodo){
        return res
            .status(404)
            .json({errermessage:'존재하지 않는 데이터'})
    }

    // 주어진 id값으로 데이터 베이스에 해당하는 해야할 일 삭제
    await Todo.deleteOne({_id:todoId}).exec(); // 1가지를 삭제하는거지 id를 찾아서 삭제하는게 아니므로 명시적으로 지정해주어야 함
    return res.status(200).json({});
})

export default router;

할일을 완료하는 요청을 한다면

해당하는 id가 완료된 시간이 나오는걸 볼수 있습니다.

 

삭제를 한다고 하면

해당 아이디를 가져와서 입력해주면 성공한걸 볼수있고

해당 id의 할일 목록이 사라진걸 볼수 있습니다.

 

이렇게 확인을 다 하고난뒤 화면에서 확인해보면

할일을 적으면 데이터가 들어오고 화면에 나오는걸 볼 수가 있고 데이터베이스에도 들어가 있씁니다.

UP 또는 DOWN을 누른다면  위치가 바뀌고 데이터 베이스의 order도 바뀌는걸 볼수가 있습니다.

할일을 다 마치고 체크를 한다면 끝마친 시간이 나오며 체크를 해제하면 null이 뜹니다.

내용을 수정한다면 value의 내용도 바뀌는걸 확인할수 있습니다.

마지막으로 삭제버튼을 클릭하면 삭제되는걸 확인 할 수 있습니다.

 

이렇게 REST API를 이용하여 간단한 할일 목록 을 만들었습니다.

주의 할점!!

오타 주의, 변수명 주의 , 객체 표현 주의{}

'프로그래밍 기초 > Node.js' 카테고리의 다른 글

데이터 유효성 검증과 에러처리  (1) 2024.02.01
미들웨어란?  (0) 2024.01.30
Express.js의 req, res 객체  (0) 2024.01.24
Node.js특징  (0) 2024.01.22
REST API 만들어보기(데이터 베이스 X)  (0) 2024.01.18
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/09   »
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
글 보관함