본문 바로가기

Programming/Node.js

5. http 모듈로 서버 만들기 (2) - REST와 라우팅 [8]

node js logo image

 

 

 

 

앞선 아티클에서 작성한 restServer.js를 계속해서 살펴보겠습니다. 작성된 코드 중, PUT과 POST에 대해서 집중적으로 살펴보겠습니다. 

 

 

 

5. http 모듈로 서버 만들기 (2) - REST와 라우팅 [7]

우선 앞서 작성했던 RESTful 서버 구현 관련 코드를 전부 다시 살펴보겠습니다.     [restFront.css]a { color: blue; text-decoration: none;}  [restFront.html] home about 등록하기   [restFront.js] // 로딩 시 사용자

nozeroslope.tistory.com

 

 

 

[restServer.js]

const http = require('http');
const fs = require('fs').promises;
const path = require('path');


// 유저 데이터 저장용
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(path.join(__dirname, 'restFront.html'));
                res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8'});
                return res.end(data);
            } else if (req.url === '/about') {
                const data = await fs.readFile(path.join(__dirname, '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': 'application/json; charset=utf-8' });
                return res.end(JSON.stringify(users));
            }
            // 주소가 /도, /about도 아닐 경우
            try {
                const data = await fs.readFile(path.join(__dirname, 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);
                    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') {
            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);
                    user[key] = JSON.parse(body).name;
                    res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8'});
                    return res.end(JSON.stringify(users));
                });
            }
        } else if (req.method === 'DELETE') {
            if (req.url.startsWith('/user/')) {
                const key = req.url.split('/')[2];
                delete users[key];
                res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8'} );
                return res.end(JSON.stringify(users));
            }
        }
        res.writeHead(404);
        return res.end('NOT FOUND');
    } catch (err) {
        console.error(err);
        res.writeHead(500, { 'Content-Type': 'text/plain; charset=utf-8'});
        res.end(err.message);
    }
})
    .listen(8082, () => {
        console.log('8082번 포트 대기 중');
    });

 

 

 

HTTP 메서드 주소 역할
GET / restFront.html 파일 제공
GET /about about.html 파일 제공
GET /users 사용자 목록 제공
GET 기타 기타 정적 파일 제공
POST /user 사용자 등록
PUT /user/사용자id 해당 id의 사용자 수정
DELETE /user/사용자id 해당 id의 사용자 삭제

 

 

 

 


 

 

 

 

우선 여기서 별도의 데이터베이스를 구축한 것은 아니기 때문에, DB 대용으로 사용하는 객체 users를 선언했습니다. 간단하게 정리하자면, 메서드 POST /user일 경우에는 사용자를 새롭게 저장하고 있고 PUT /user/아이디일 경우에는 사용자 데이터를 수정하게 됩니다. DELETE /user/아이디일 경우에는 해당 아이디의 사용자를 제거하겠죠? 

 

여기서 POST, PUT 요청 처리 과정에서는 req.on('data')와 req.on('end')를 사용합니다. 이는 req의 바디에 들어있는 데이터를 꺼내기 위해서 사용합니다. req, res도 내부적으로 스트림으로 되어 있습니다. (각각 readStream과 writeStream)그래서 요청, 응답 데이터가 스트림 형식으로 전달됩니다. on에서 보여지듯 이벤트도 연계되죠. 

 

단, 받은 데이터는 문자열이기 때문에 JSON으로 만드는 JSON.parse 과정을 거치게 됩니다. 

 

 

 


 

 

 

 

 

위와 같이 동작을 테스트해 Network 탭에서의 기록을 확인해 보겠습니다(만일 Method 칼럼이 안보이면, Name 칼럼 우클릭 후 'Method' 클릭). 'johndoe'를 등록할 경우, Network 탭에서 user와 users가 추가되는 것을 확인할 수 있습니다.

 

자, 여기서 Name 칼럼은 요청 주소를 의미하게 됩니다. 새로운 유저를 등록할 경우 POST  /user , GET  /users 이 실행됩니다. Status는 HTTP 응답 코드를 의미하고 Protocol은 통신 프로토콜을, Type은 요청의 종류를 의미하게 되는데 xhr은 AJAX를 의미합니다. 

 

테스트 삼아서 johndoe를 '삭제'버튼을 통해서 삭제할 경우에는 DELETE /user/1721050273489가 요청됩니다. 해당 키를 가진 사용자를 제거하게 되고, 등록 / 수정 / 삭제 발생 후에는 GET으로 /users를 요청해 갱신된 사용자 정보를 가져오게 됩니다.