코드코코

210913 [4장] 4.2 REST와 라우팅사용하기 본문

기록/node.js 교과서 따라하기

210913 [4장] 4.2 REST와 라우팅사용하기

코드코코 2021. 9. 13. 22:56
a {
    color: blue;
    text-decoration: none;
}

1-1. restFront.js

// 로딩시 사용자 정보를 가져오는 함수
async function getUser() {
    try {
        //Axios는 브라우저, Node.js를 위한 Promise API를 활용하는 HTTP 비동기 통신 라이브러리.
        const res = await axios.get('/users');
        const users = res.data;
        const list = document.getElementById('list');
        list.innerHTML = '';
        
        //사용자마다 반복적으로 화면 표시 및 이벤트 연결
          //object.keys() 메소드는 객체가 가지고 있는 키들의 목록을 배열로 리턴.
          //객체의 내장 메소드가 아닌 객체 생성자인 Object가 직접 가지고 있는 메소드.
          //.map() : callback 함수를 각각의 요소에 대해 한번씩 순서대로 불러 그 함수의 반환값으로 새로운 배열을 만듦.
          //array를 돌면서 array 로 결과가 출력 - 참고 및 출처 사이트 : https://velog.io/@claire-euni/js-map%ED%95%A8%EC%88%98%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C
        Object.keys(users).map(function (key) {
            const userDiv = document.createElement('div');
            const span = document.createElement('span');
            //textContent : 모든 공백을 포함하여 반환.
            span.textContent = users[key];
            const edit = document.createElement('button');
            edit.textContent = '수정';
            edit.addEventListener('click', async () => {//수정 버튼 클릭
                const name = prompt('바꿀 이름을 입력하세요');
                if (!name) {
                    return alert('이름을 반드시 입력하셔야 합니다');
                }
                try {
                    await axios.put('/user/' + key, { name });
                    getUser();
                } catch (err) {
                    console.error(err);
                }
            });
            const remove = document.createElement('button');
            remove.textContent = '삭제';
            remove.addEventListener('click', async () => {//삭제 버튼 클릭
                try {
                    await axios.delete('/user/' + key);
                    getUser();
                } catch (err) {
                    console.error(err);
                }
            });
            userDiv.appendChild(span);
            userDiv.appendChild(edit);
            userDiv.appendChild(remove);
            list.appendChild(userDiv);
            console.log(res.data);
        });
    } catch (err) {
        console.error(err);
    }
}

//화면 로딩 시 getUser호출
window.onload = getUser;
//폼 제출(submit)시 실행
document.getElementById('form').addEventListener('submit', async (e) => {
   
    //a 태그나 submit 태그는 누르게 되면 href 를 통해 이동하거나 , 창이 새로고침하여 실행됨.
    //preventDefault 를 통해 이러한 동작을 방지.
    //주로 사용되는 경우
    //1. a 태그를 눌렀을때도 href 링크로 이동하지 않게 할 경우
    //2. form 안에 submit 역할을 하는 버튼을 눌렀어도 새로 실행하지 않게 하고싶을 경우 (submit은 작동됨)
    e.preventDefault();
    
    //e.target : 이벤트가 발생한 요소를 반환.
    //e.target.username.value : 이벤트가 발생한 요소의 id값의 value를 반환.
    const name = e.target.username.value;
    if (!name) {
        return alert('이름을 입력하세요');
    }
    try {
        await axios.post('/user', { name });
        getUser();
    } catch (err) {
        console.error(err);
    }
    e.target.username.value = '';
});

1-1.  restFront.html

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>RESTful SERVER</title>
    <link rel="stylesheet" href='./restFront.css'>
</head>
<body>
    <nav>
        <a href="/">Home</a>
        <a href="/about">About</a>
    </nav>
    <div>
        <form id="form">
            <input type="text" id="username">
            <button type="submit">등록</button>
        </form>
    </div>
    <div id="list"></div>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>   
    <script src="./restFront.js"></script>

</body>
</html>

1-1. restFront.css

a {
    color: blue;
    text-decoration: none;
}

1-2. about.html

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>RESTful SERVER</title>
    <link rel="stylesheet" href="./restFront.css">
</head>
<body>
    <nav>
        <a href="/">Home</a>
        <a href="/about">About</a>
    </nav>
    <div>
        <h2>소개 페이지입니다.</h2>
        <p>사용자 이름을 등록하세요!</p>
    </div>
    
</body>
</html>

2. restServer.js

const http = require("http");
const fs = require("fs").promises;

const users = {}; //데이터 저장용

http.createServer(async (req, res) => {
    try {
      console.log(req.method, req.url);
      if (req.method === "GET") {
        //요청 메소드가 겟이면
        if (req.url === "/") {
          //요청 주소가 / 이면

          const data = await fs.readFile("./restFront.html"); //restFront.html 제공
          res.writeHead(200, { "content-type": "text/html; charset=utf-8" }); 
          return res.end(data);
        } else if (req.url === "/about") {
          //요청주소가 /about이면

          const data = await fs.readFile("./about.html"); //about.html 제공
          res.writeHead(200, { "content-type": "text/html; charset=utf-8" });
          return res.end(data);
        } else if (req.url === "/users") {

          res.writeHead(200, { "content-type": "text/plain; charset=utf-8" });
          //JSON.stringify() 메서드는 JavaScript 값이나 객체를 JSON 문자열로 변환.       
          return res.end(JSON.stringify(users));
        }
        //주소가 /도 /about도 아니면
        try {
            //폴더에서 찾아. css js 등의 파일을
          const data = await fs.readFile(`.${req.url}`); 
          return res.end(data);
        } catch (err) {
          //주소에 해당하는 라우트를 못 찾았다는 404 Not Found Error 발생
        }
      } else if (req.method === "POST") {
        if (req.url === "/user") {
          let body = "";
          //요청의 body를 stream형식으로 받음
          req.on("data", (data) => {
            body += data;
          });
          //요청의 body를 다 받은 후 실행 됨.
          return req.on("end", () => {
            console.log("POST 본문(Body):", body);
            //JSON.parse() : string형식의 데이터를 객체형식으로 변환.
            const { name } = JSON.parse(body);
            const id = Date.now();
            users[id] = name;
            res.writeHead(201,{ "content-type": "text/plain; charset=utf-8" });
            res.end("등록 성공");
          });
        }
      } else if (req.method === "PUT") {
        //startsWith() 메소드는 어떤 문자열이 특정 문자로 시작하는지 확인하여 
        //결과를 true 혹은 false로 반환
        if (req.url.startsWith("/user/")) {
          const key = req.url.split("/")[2];
          let body = "";
          req.on("data", (data) => {
            body += data;
          });
          return req.on("end", () => {
            console.log("PUT 본문(Body):", body);
            users[key] = JSON.parse(body).name;
            return res.end(JSON.stringify(users)); //✔ 계속 오류난 이유 JSON이 빠져있었음.
          });
        }
      } else if (req.method === "DELETE") {
        if (req.url.startsWith("/user/")) {
          const key = req.url.split("/")[2];
          delete users[key];
          return res.end(JSON.stringify(users));
        }
      }
      res.writeHead(404);
      return res.end("NOT FOUND");
    } catch (err) {
      console.error(err);
      res.writeHead(500);
      res.end(err);
    }
  })

  .listen(8082, () => {
    console.log('8082번 포트에서 서버 대기 중입니다.');
  });