1. Node.JS로 TODO

jonyChoiGenius·2023년 12월 13일
0

NEXT JS 13 투두앱

목록 보기
1/4

Node.js의 HTTP 모듈을 이용해서 TODO앱을 만드는 법.

createServer

http 모듈을 import 한다.
const http = require("http");

createServer를 통해 서버를 만들 수 있다.
const server = http.createServer()

만든 서버는 server.listen(포트번호)를 통해 실행시킬 수 있다.
server.listen(8080, () => console.log("8080 포트 작동"));

createServer의 인자로 requestListener라는 콜백 함수를 넘길 수 있다. 해당 함수는 첫번째 인자로 request를, 두번째 인자로 response를 받는다.

res.setHeader(키, 밸류)를 통해 헤더값을 추가할 수 있으며,
res.write(chunk)를 통해 응답의 body값을 추가할 수 있다.
res.end(chunk?)는 요청에 대한 응답을 종료시키며, 종료와 함께 추가적인 body값을 보낼 수 있다.

const server = http.createServer((res, req)=> { res.setHeader("Content-Type", "application/json"); res.end("응답입니다."); })

CORS 해결

헤더에 아래와 같이 추가하여 CORS 문제를 해결할 수 있다.

const server = http.createServer((req, res) => {
  console.log(req.url);

  res.setHeader("Access-Control-Allow-Origin", "*");
  res.setHeader("Access-Control-Allow-Headers", "Content-Type"); //post 요청 등에서 Content-Type인 경우에도 CORS를 허용한다.
  res.setHeader("Access-Control-Allow-Methods", "*"); //OPTIONS, GET, POST 이외의 요청에 대해서 허용
})

CRUD

임시로 주고 받을 userInfo 데이터를 넣는다.

const http = require("http");

const userInfo = [
  {
    id: 1,
    username: "john_doe",
    email: "john@example.com",
  },
];

userInfo를 가져와서 조회 및 생성을 하는 API이다.
이때 if 문으로 라우팅을 하고, 필요에 따라 return을 넣어주어야 한다.
아래에서는 req가 POST인 경우에 대해서도 return을 넣어주었다.

const server = http.createServer((req, res) => {
  console.log(req.url);

  res.setHeader("Access-Control-Allow-Origin", "*");
  res.setHeader("Access-Control-Allow-Headers", "Content-Type"); //post 요청 등에서 Content-Type인 경우에도 CORS를 허용한다.
  res.setHeader("Access-Control-Allow-Methods", "*"); //OPTIONS, GET, POST 이외의 요청에 대해서 허용

  // application/json 타입으로 헤더에 콘텐츠 타입을 설정한다.
  res.setHeader("Content-Type", "application/json");

  if (req.url === "/") {
    res.write(JSON.stringify({ url: "암것두 없다" }));
  }

  if (req.url.startsWith("/user")) {
    if (req.method === "GET") {
      res.write(JSON.stringify(userInfo));
    }

    if (req.method === "POST") {
      let requestBody = "";
      req
        .on("data", (chunk) => {
          requestBody += chunk;
        })
        .on("end", () => {
          const user = JSON.parse(requestBody);
          userInfo.push({ id: userInfo.at(-1).id + 1, ...user });

          //아래의 두 코드는 같다.
          res.end(JSON.stringify(userInfo));
          // res.write(JSON.stringify(userInfo));
          // res.end();
        });
      return; // return을 넣어주어야 res.end()가 작동하지 않는다. return하지 않으면 res.end가 한번 더 실행되며 잘못된 응답을 보내게 된다.
    }
  }
  res.end();
});

/user는 리스트를 조회하고,
/user/:id는 특정 하나를 조회하도록 추가해보자.

const server = http.createServer((req, res) => {
  console.log(req.url);

  res.setHeader("Access-Control-Allow-Origin", "*");
  res.setHeader("Access-Control-Allow-Headers", "Content-Type"); //post 요청 등에서 Content-Type인 경우에도 CORS를 허용한다.
  res.setHeader("Access-Control-Allow-Methods", "*"); //OPTIONS, GET, POST 이외의 요청에 대해서 허용

  // application/json 타입으로 헤더에 콘텐츠 타입을 설정한다.
  res.setHeader("Content-Type", "application/json");

  if (req.url === "/") {
    res.write(JSON.stringify({ url: "암것두 없다" }));
  }

  if (req.url.startsWith("/user")) {
    //url.split("/")[2]는 params를 의미한다.
    if (!req.url.split("/")[2]) {
      if (req.method === "GET") {
        res.write(JSON.stringify(userInfo));
      }

      if (req.method === "POST") {
        let requestBody = "";
        req
          .on("data", (chunk) => {
            requestBody += chunk;
          })
          .on("end", () => {
            const user = JSON.parse(requestBody);
            userInfo.push({ id: userInfo.at(-1).id + 1, ...user });

            res.end(JSON.stringify(userInfo));
          });
        return;
      }
    } else {
      const userId = Number(req.url.split("/")[2]);
      const userData = userInfo[userInfo.findIndex((e) => e.id === userId)];
      if (req.method === "GET") {
        res.write(JSON.stringify(userData));
      }

      // POST 요청을 활용한다.
      if (req.method === "PATCH") {
        let requestBody = "";
        req
          .on("data", (chunk) => {
            requestBody += chunk;
          })
          .on("end", () => {
            const user = JSON.parse(requestBody);
            // 유저 객체의 키, 밸류를 수정하는 방식으로 업데이트를 실행한다.
            // (객체 불변성을 지키지 않고 있음에 유의!)
            Object.entries(user).forEach((entry) => {
              const [key, value] = entry;
              userData[key] = value;
            });
            res.end(JSON.stringify(userData));
          });
        return;
      }
    }
  }
  res.end();
});

server.listen(8080, () => console.log("8080 포트 작동"));

클라이언트

프론트엔드에서 fetch API를 통해서 응답을 주고 받은 방법은 아래와 같다.
fetch(요청).then(res=> res.json()).then(data=>{}) 와 같이 res를 json으로 파싱해주어야 한다. RESPONSE.json()은 비동기적으로 작동하며, PROMISE를 반환한다는 점에 유의하자.

import { useState } from "react";
import "./App.css";

function App() {
  const [data, setData] = useState("");

  const onClickHandler = () => {
    fetch("http://localhost:8080", { method: "GET" })
      .then((res) => {
        //fetch의 결과물을 자바스크립트 객체로 반환한다..
        return res.json();
      })
      .then((res) => {
        //반환된 객체를 res에 저장한다.
        setData(res);
      })
      .catch((e) => console.log(e));
  };

  const onGetUser = () => {
    fetch("http://localhost:8080/user", { method: "GET" })
      .then((res) => {
        //fetch의 결과물을 자바스크립트 객체로 반환한다..
        return res.json();
      })
      .then((res) => {
        //반환된 객체를 res에 저장한다.
        setData(res);
      })
      .catch((e) => console.log(e));
  };

  const onPostUser = () => {
    const newDate = new Date();

    fetch("http://localhost:8080/user", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        username: `john_doe${newDate.getSeconds()}`,
        email: `john${newDate.getSeconds()}@example.com`,
      }),
    })
      .then((res) => {
        return res.json();
      })
      .then((res) => {
        setData(res);
      })
      .catch((e) => console.log(e));
  };

  const onUpdateUser = () => {
    const newDate = new Date();

    fetch("http://localhost:8080/user/1", {
      method: "PATCH",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        username: `john_${newDate.getSeconds()}`,
      }),
    })
      .then((res) => {
        return res.json();
      })
      .then((res) => {
        setData(res);
      })
      .catch((e) => console.log(e));
  };

  const onRetriveUser = () => {
    fetch("http://localhost:8080/user/1", {
      method: "GET",
    })
      .then((res) => {
        return res.json();
      })
      .then((res) => {
        setData(res);
      })
      .catch((e) => console.log(e));
  };

  return (
    <>
      <button onClick={onClickHandler}>버튼</button>
      <button onClick={onGetUser}>user-get버튼</button>
      <button onClick={onPostUser}>user-post버튼</button>
      <button onClick={onUpdateUser}>user-1-patch버튼</button>
      <button onClick={onRetriveUser}>user-1-get버튼</button>
      <div>{JSON.stringify(data)}</div>
    </>
  );
}

export default App;
profile
천재가 되어버린 박제를 아시오?

0개의 댓글

관련 채용 정보