REST는 Representational State Tranfer의 약자로, 월드와이드웹(www)와 같은 하이퍼미디어 시스템을 위한 소프트웨어 아키텍쳐 중 하나의 형식이다. REST 서버는 클라이언트의 요청으로 하여금, HTTP 프로토콜을 사용해 서버의 정보에 접근 및 변경을 가능케 한다. 이때 주고 받는 정보의 형식은 Text, XML, JSON 등이 있으나, 현재 가장 널리 쓰이는 형식은 JSON 이다.

이번 메모에서는 REST 기반의 HTTP 통신으로 서버의 데이터에 접근하는 API 를 만들어보려고 한다.


HTTP 메소드

HTTP/1.1 에서 제공되는 메소드는 보통 알려져 있는 GET/POST 이외에도 여러가지가 있다. REST 기반 아키텍쳐에서 주로 사용되는 4가지 메소드는 다음과 같다.

  1. GET - 조회
  2. PUT - 생성 및 업데이트(idempotent)
  3. DELETE - 제거
  4. POST - 생성(non-idempotent)
  5. PATCH - 업데이트(non-idempotent)

PUT과 POST의 차이

PUT은 몇 번을 다시 실행해도 결과가 같은 action 에 사용하며, 그렇지 않은 경우에 POST를 사용하는 것이 일반적이다. 가령 DB에 insert 쿼리를 실행하는 메소드일 경우, 계속 실행이 지속된다면, 계속해서 튜플이 생성되는 결과가 일어나기 때문에 이는 non-idempotent 하므로 POST 를 사용하는 것이 맞다. 두번 째의 경우로, DB에 update 쿼리를 실행하는 경우, 연산식을 사용하지 않고 정적인 값을 대입한다면 몇 번을 실행시켜도 같은 결과가 나오기 때문에 idempotent 하므로 PUT 을 사용하는 것이 맞다.


서버 데이터 생성

아직 Node.js를 활용한 데이터베이스를 구축하지 않았기 때문에, 파일 시스템 모듈을 활용한 서버 데이터를 생성하겠다. 프로젝트 디렉토리 내에 /data/user.json 을 작성하자

/data/user.json

{
    "first_user": {
        "password": "first_pass",
        "name": "abet"
    },
    "second_user":{
        "password": "second_pass",
        "name": "betty"
    }
}

API-1 : GET /list

module.exports = function(app, fs)
{
 
     app.get('/',function(req,res){
         res.render('index', {
             title: "MY HOMEPAGE",
             length: 5
         })
     });
 
    app.get('/list', function (req, res) {
        //__dirname : 이 파일(라우터 코드)의 현재 디렉토리
       fs.readFile( __dirname + "/../data/" + "user.json", 'utf8', function (err, data) {
           console.log( data );
           res.end( data );
       });
    })
 
}

API-2 : GET /getUser/:username

app.get('/getUser/:username', function(req, res){
    fs.readFile( __dirname + "/../data/user.json", 'utf8', function (err, data) {
        var users = JSON.parse(data);
        res.json(users[req.params.username]);
    });
});

API-3 : POST /addUser/:username body:{“password”:”__”, “name”:”__”}

app.post('/addUser/:username', function(req, res){

    var result = {  };
    var username = req.params.username;

    // Request 의 유효성을 검사함
    // password와 name 항목 필수:
    if(!req.body["password"] || !req.body["name"]){
        //실패 Response
        result["success"] = 0;
        result["error"] = "invalid request";
        res.json(result);
        return;
    }

    // 데이터 읽음
    fs.readFile( __dirname + "/../data/user.json", 'utf8',  function(err, data){
        
        //JSON 파일을 JS 객체 형식으로 파싱하여 대입
        var users = JSON.parse(data);

        //중복 검사
        if(users[username]){
            //실패 Response
            result["success"] = 0;
            result["error"] = "duplicate";
            res.json(result);
            return;
        }

        // JS 객체에 데이터 추가
        users[username] = req.body;

        // JS 객체를 JSON 형식으로 데이터 파일에 작성
        fs.writeFile(__dirname + "/../data/user.json", JSON.stringify(users, null, '\t'), "utf8", function(err, data){
            //성공을 Client에게 Response 함
            result = {"success": 1};
            res.json(result);
        });
    });
});

API-4 : PUT /updateUser/:username body:{“password”:”__”, “name”:”__”}

위에서도 언급 했듯이, PUT 메소드는 idempotent한 결과를 보장해야 한다.

app.put('/updateUser/:username', function(req, res){

    var result = {  };
    var username = req.params.username;

    // CHECK REQ VALIDITY
    if(!req.body["password"] || !req.body["name"]){
        result["success"] = 0;
        result["error"] = "invalid request";
        res.json(result);
        return;
    }

    // LOAD DATA
    fs.readFile( __dirname + "/../data/user.json", 'utf8',  function(err, data){
        var users = JSON.parse(data);
        // ADD/MODIFY DATA
        users[username] = req.body;

        // SAVE DATA
        fs.writeFile(__dirname + "/../data/user.json",
                        JSON.stringify(users, null, '\t'), "utf8", function(err, data){
            result = {"success": 1};
            res.json(result);
        })
    })
});

API-5 : DELETE /deleteUser/:username

app.delete('/deleteUser/:username', function(req, res){
    var result = { };
    //LOAD DATA
    fs.readFile(__dirname + "/../data/user.json", "utf8", function(err, data){
        var users = JSON.parse(data);

        // IF NOT FOUND
        if(!users[req.params.username]){
            result["success"] = 0;
            result["error"] = "not found";
            res.json(result);
            return;
        }

        // DELETE FROM DATA
        delete users[req.params.username];

        // SAVE FILE
        fs.writeFile(__dirname + "/../data/user.json",
                        JSON.stringify(users, null, '\t'), "utf8", function(err, data){
            result["success"] = 1;
            res.json(result);
            return;
        })
    })

});