231127(월) Todolist Redux

심재원·2023년 11월 27일
1

open source license Type

https://blog.naver.com/occidere/220850682345

참고

https://nestjs.com/

Backend 서버 만들기

API를 만들 수 있는 서버 만들기
Routing 작업
Routing이 많아지면 많아질 수록 앱에서 관리하는데 한계가 생김

swagger UI

https://petstore.swagger.io/?_ga=2.110122051.757277682.1701045196-980531850.1701045196

to-do-list-redux
backend
open terminal
cd backend

npm init -y

package.json

{
  "name": "backend",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "h662",
  "license": "MIT"
}

npm i express
git init

.gitignore

node_modules
.env

README.md file 생성

app.js file 생성

const express = require("express");

const app = express();

const port = 3010;

app.get("/", (req, res) => {
  return res.send("Hello, Express!");
});

app.listen(port, () => {
  console.log(`🚀 Server is listening on port : ${port}`);
});

node app.js
http://localhost:3010/ 에서 "Hello, express!"뜨는지 확인

routes folder/todos.js

todos.js

const express = require("express");

const router = express.Router();

router.get("/", (req, res) => {
  return res.send("Todo Router");
});

module.exports = router;

npm i -D nodemon하고 package.json에 명령어 등록해줘야 함

package.json

{
  "name": "backend",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "start": "node app.js", <- 수정해준 것
    "dev": "nodemon app.js" <- 수정해준 것
  },
  "keywords": [],
  "author": "h662",
  "license": "MIT",
  "devDependencies": {
    "nodemon": "^3.0.1"
  }
}

npm run dev
만약 안 되면 npm i express 다시 실행하고
npm run dev 재명령

지금까지 만든 라우터는 테스트용으로 만든 것

todos.js의 코드 수정(임시 라우터)

const express = require("express");

const router = express.Router();

let todoId = 1;
let todos = [{ id: 1, title: "🧹 청소하기", isDone: false }];

router.post("/", (req, res) => {
    console.log(req.body);

    return res.json({ message: "ok" });
});

module.exports = router;

Output

Postman에서 날려보기

그러면 Terminal에 undefined 뜸

app.js file

const express = require("express");
const todosRouter = require("./routes/todos");

const app = express();

const port = 3010;

app.use(express.json());
app.use("/todos", todosRouter);

app.get("/", (req, res) => {
  return res.send("Hello, Express!");
});

app.listen(port, () => {
  console.log(`🚀 Server is listening on port : ${port}`);
});

postman에서 x-www-form에서 아래와 같이 작성 후 send

app.js file 코드 추가

const express = require("express");
const todosRouter = require("./routes/todos");

const app = express();

const port = 3010;

app.use(express.json());
app.use(express.urlencoded({ extended: true })); <-- 추가
app.use("/todos", todosRouter);

app.get("/", (req, res) => {
  return res.send("Hello, Express!");
});

app.listen(port, () => {
  console.log(`🚀 Server is listening on port : ${port}`);
});

todos.js file 코드 수정

const express = require("express");

const router = express.Router();

let todoId = 1;
let todos = [{ id: 1, title: "🧹 청소하기", isDone: false }];

router.post("/", (req, res) => {
  const { title } = req.body; <--- 수정
  
  todoId++; <--- todoId = todoId + 1; todoId += 1;
  					++는 값을 저장하는 의미도 담고 있음
 
 const newTodo = { id: todoId, title, isDone: false } <--- key와 value값이 같으면 생략이 가능하다 title: title

    todos.push(newTodo);

    console.log(todos);

  return res.json({ todo: newTodo });
});

Postman에서 send 후 output

Terminal output

Error Case

todos.js file Input

const express = require("express");

const router = express.Router();

let todoId = 1;
let todos = [{ id: 1, title: "🧹 청소하기", isDone: false }];

router.post("/", (req, res) => {
  const { title } = req.body;

  if (!title) {
    return res.status(400).json({
        message: "Not exist title.",
    });
  }

  todoId++;

  const newTodo = { id: todoId, title, isDone: false }

    todos.push(newTodo);

    console.log(todos);

  return res.json({ todo: newTodo });
});

// router.get("/", (req, res) => {
//   return res.send("Todo Router");
// });

module.exports = router;

Postman output

Get 요청 Input

const express = require("express");

const router = express.Router();

let todoId = 1;
let todos = [{ id: 1, title: "🧹 청소하기", isDone: false }];

router.post("/", (req, res) => {
  const { title } = req.body;

  if (!title) {
    return res.status(400).json({
      message: "Not exist title.",
    });
  }

  todoId++;

  const newTodo = { id: todoId, title, isDone: false };

  todos.push(newTodo);

  console.log(todos);

  return res.json({ todo: newTodo });
});

router.get("/", (req, rest) => {
    return res.json({ todos });
});

module.exports = router;

todos.js Input

const express = require("express");

const router = express.Router();

let todoId = 1;
let todos = [{ id: 1, title: "🧹 청소하기", isDone: false }];

router.post("/", (req, res) => {
  const { title } = req.body;

  if (!title) {
    return res.status(400).json({
      message: "Not exist title.",
    });
  }

  todoId++;

  const newTodo = { id: todoId, title, isDone: false };

  todos.push(newTodo);

  console.log(todos);

  return res.json({ todo: newTodo });
});

router.get("/", (req, res) => {
  return res.json({ todos });
});

router.get("/:todoId", (req, res) => {
  const { todoId } = req.params;

  let existTodo;

  todos.map((v, i) => {
    if (v.id === +todoId) {
      existTodo = v;
    }
  });

  return res.json({ todo: existTodo });
});

module.exports = router;

Terminal Output

http://localhost:3010/todos에서도 확인 가능

Input

if (isNaN(todoId)) {
    return res.status(400).json({
      message: "todoId is not a number.",
    });
  }
if (!existTodo) {
    return res.status(400).json({
      message: "Not exist todo.",
    });
  }

Whole Code

const express = require("express");

const router = express.Router();

let todoId = 1;
let todos = [{ id: 1, title: "🧹 청소하기", isDone: false }];

router.post("/", (req, res) => {
  const { title } = req.body;

  if (!title) {
    return res.status(400).json({
      message: "Not exist title.",
    });
  }

  todoId++;

  const newTodo = { id: todoId, title, isDone: false };

  todos.push(newTodo);

  console.log(todos);

  return res.json({ todo: newTodo });
});

router.get("/", (req, res) => {
  return res.json({ todos });
});

router.get("/:todoId", (req, res) => {
  const { todoId } = req.params;

  if (isNaN(todoId)) {
    return res.status(400).json({
      message: "todoId is not a number.",
    });
  }

  let existTodo;

  todos.map((v, i) => {
    if (v.id === +todoId) {
      existTodo = v;
    }
  });

  if (!existTodo) {
    return res.status(400).json({
      message: "Not exist todo.",
    });
  }

  return res.json({ todo: existTodo });
});

module.exports = router;

Output

Postman 5ea 생성

http://localhost:3010/todos/4
= 4번 출력

http://localhost:3010/todos/12
= "message": "Not exist todo."

http://localhost:3010/todos/abc
= "message": "todoId is not a number."

Input

router.put("/:todoId/done", (req, res) => {
  const { todoId } = req.params;

  if (isNaN(todoId)) {
    return res.status(400).json({
      message: "todoId is not a number.",
    });
  }

  let updateTodo;

  todos = todos.map((v) => {
    if (v.id === +todoId) {
      updateTodo = { id: v.id, title: v.title, isDone: !v.isDone };

      return updateTodo;
    } else {
      return v;
    }
  });

  if (!updateTodo) {
    return res.status(400).json({
      message: "Not exist todo.",
    });
  }

  return res.json({ todo: updateTodo });
});

OutPut

Postman
post : http://localhost:3010/todos/ 10ea send
put : http://localhost:3010/todos/10/done send
get : http://localhost:3010/todos/ send 후 10번만 true인지 확인

마지막은 delete

총정리

app.js

const express = require("express");
const todosRouter = require("./routes/todos");

const app = express(); -> express 자체를 함수로 실행

const port = 3010;

app.use(express.json()); 
app.use(express.urlencoded({ extended: true })); 
-> 위 두 줄은 json 형태로 받기 위함
app.use("/todos", todosRouter);
->app.use는 미들웨어. 중간에 위치해서 서버를 다채롭게 하는 역할. 라우터의 경우 첫 번째(/todos)에 경로를 입력하고, 그 라우터에 우리가 만들어 놓은 경로를 이용할 수 있음

app.get("/", (req, res) => {
  return res.send("Hello, Express!");
}); -> get 요청. 로컬호스트 들어가면 서버가 열려있는지 아닌지 확인해볼 수 있음. 필수가 아니라면 굳이 안 둬도 되긴 함.

app.listen(port, () => {
  console.log(`🚀 Server is listening on port : ${port}`);
}); -> 다 실행하면 마지막에 app.listen 사용. listen은 문자 그대로 요청이 들어오나 안 들어오나 서버가 듣고 있는 것. 3010 port가 열릴 거고, 콘솔로그 찍히면서 서버가 시작.

todos.js 라우터

const express = require("express");

const router = express.Router();
-> express를 router에 담음

let todoId = 1;
let todos = [{ id: 1, title: "🧹 청소하기", isDone: false }]; -> 필요한 데이터를 임시로 변수로 달아놓음. 이 경우 데이터가 메모리에 저장됨. 서버가 리셋되면 데이터가 날라가는 것.


router.post("/", (req, res) => {
  const { title } = req.body; -> body로부터 타이틀을 받아옴

  if (!title) {
    return res.status(400).json({
      message: "Not exist title.",
    });
  } -> title이 없으면 예외처리 한다는 명령어

  todoId++; -> 투두아이디값 증가시키고

  const newTodo = { id: todoId, title, isDone: false };

  todos.push(newTodo);

  console.log(todos);

  return res.json({ todo: newTodo });
});

router.get("/", (req, res) => {
  return res.json({ todos }); 
}); -> 그냥 리턴하면 안 되고 res.json 해야 함

router.get("/:todoId", (req, res) => {
  const { todoId } = req.params;

  if (isNaN(todoId)) {
    return res.status(400).json({
      message: "todoId is not a number.",
    });
  } -> 숫자가 아니면 에러처리

  let existTodo;

  todos.map((v, i) => {
    if (v.id === +todoId) {
      existTodo = v;
    }
  }); 

  if (!existTodo) {
    return res.status(400).json({
      message: "Not exist todo.",
    });
  } -> 존재하지 않는 투두 뿜어내기

  return res.json({ todo: existTodo });
});

router.put("/:todoId/done", (req, res) => {
  const { todoId } = req.params;

  if (isNaN(todoId)) {
    return res.status(400).json({
      message: "todoId is not a number.",
    });
  } -> 아이디가 없을 경우 isNaN으로 탐색

  let updateTodo;
  -> 업데이트 해준 내용을 기존 todos에 반영해줘야 하니 아래 return해준 것

  todos = todos.map((v) => {
    if (v.id === +todoId) {
      updateTodo = { id: v.id, title: v.title, isDone: !v.isDone };

      return updateTodo;
    } else {
      return v;
    }
  });

  if (!updateTodo) {
    return res.status(400).json({
      message: "Not exist todo.",
    });
  }

  return res.json({ todo: updateTodo });
});

router.put("/:todoId", (req, res) => {
  const { todoId } = req.params;
  const { title } = req.body;

  if (isNaN(todoId) || !title) {
    return res.status(400).json({
      message: "Not exist data.",
    });
  } -> isNaN해서 타이틀이 없거나 todoId 한 번에 비교 가능. 물론 퉁쳐서 하면 정확히 어떤 에러인지 알 수 없음

  let updateTodo;

  todos = todos.map((v) => {
    if (v.id === +todoId) {
      updateTodo = { id: v.id, title, isDone: v.isDone };

      return updateTodo;
    } else {
      return v;
    }
  });

  return res.json({ todo: updateTodo });
});

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

  if (isNaN(todoId)) {
    return res.status(400).json({
      message: "todoId is not a number.",
    });
  }

  todos = todos.filter((v) => {
    if (v.id !== +todoId) {
      return v;
    }
  });

  console.log(todos);

  return res.json({ message: "Deleted todo." });
});

module.exports = router;

자바가 솔리디티랑 적합하고
자바스크립트랑 솔리디티는 다름

솔리디티에서는 if문 쓰는데 map은 안 씀.
공통적인 요소나 로직은 달라지지 않음.

같은 자바스크립트를 써도 프론트엔드랑 백엔드가 다른 게 있음.
이 차이점을 알고 하느냐 모르고 하느냐는 중요.
프론트엔지니어가 데이터베이스까지 붙일 수 있으면 할 수 있는 게 많아짐.

next.js는 서버리스 형태로 백엔드 구현 가능.
이게 express랑 유사함.

0개의 댓글