이 강좌는 강좌 10-1편과 이어지는 강좌입니다.
강좌를 작성하다가 글이 너무 길어져서 3편으로 나누어 작성한 점 유의해주세요 🙂
10-1. EJS
10-2. Restful API
10-3. Session
3. RESTful API
REST 는 Representational State Transfer 의 약자로서, 월드와이드웹(www) 와 같은 하이퍼미디어 시스템을 위한 소프트웨어 아키텍쳐 중 하나의 형식입니다. REST 서버는 클라이언트로 하여금 HTTP 프로토콜을 사용해 서버의 정보에 접근 및 변경을 가능케 합니다. 여기서 정보는 text, xml, json 등 형식으로 제공되는데, 요즘 트렌드는 json이죠.
HTTP 메소드
HTTP/1.1 에서 제공되는 메소드는 여러개가 있는데요,
REST 기반 아키텍쳐에서 자주 사용되는 4가지 메소드는 다음과 같습니다.
- GET – 조회
- PUT – 생성 및 업데이트
- DELETE – 제거
- POST – 생성
여기서 잠깐, POST 와 PUT 좀 헷갈리지 않나요? 둘다 생성을 한다면..
어느 상황에 무엇을 써야하는거지? PUT vs POST, REST API (1ambda Blog) 여기서 궁금증을 해소하세요!
데이터베이스 생성
JSON 기반의 사용자 데이터베이스를 만들어보겠습니다.
Node.js 와 궁합이 잘 맞는 MongoDB를 사용했더라면 좋았겠지만
이 포스트의 초점은 Express 이므로 다음으로 미루도록 하겠습니다.
2016/3/3 EDITED: 미룬 강좌가 작성되었습니다.
[Node.JS] 강좌 11편: Express와 Mongoose를 통해 MongoDB와 연동하여 RESTful API 만들기
data 폴더를 만들고 그 안에 user.json 파일을 생성해주세요:
{
"first_user": {
"password": "first_pass",
"name": "abet"
},
"second_user":{
"password": "second_pass",
"name": "betty"
}
}
(보안을 생각한다면 패스워드는 Encrypt를 하거나 Hash 를 쓰는게 좋겠지만 이건 예제니까 PASS!
그 부분은나중에 한번 다루도록 하겠습니다.)
첫번째 API: GET /list
모든 유저 리스트를 출력하는 GET API 를 작성해보겠습니다.
우선, user.json 파일을 읽어야 하므로, fs 모듈을 사용하겠지요?
module.exports = function(app, fs)
{
app.get('/',function(req,res){
res.render('index', {
title: "MY HOMEPAGE",
length: 5
})
});
app.get('/list', function (req, res) {
fs.readFile( __dirname + "/../data/" + "user.json", 'utf8', function (err, data) {
console.log( data );
res.end( data );
});
})
}
__dirname 은 현재 모듈의 위치를 나타냅니다.
router 모듈은 router 폴더에 들어있으니, data 폴더에 접근하려면
/../ 를 앞부분에 붙여서 먼저 상위폴더로 접근해야합니다.
자 서버를 실행해서 http://localhost/list 에 접속해보세요.

두번째 API: GET /getUser/:username
이번엔 특정 유저 username의 디테일한 정보를 가져오는 GET API 를 작성해보도록 하겠습니다.
다음 코드를 router/main.js 의 list API 아래에 작성해주세요.
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]);
});
});
파일을 읽은후, 유저 아이디를 찾아서 출력해줍니다.
유저를 찾으면 유저 데이터를 출력하고 유저가 없다면
{} 을 출력하게 됩니다.
fs.readFile()로 파일을 읽었을 시엔 텍스트 형태로읽어지기 때문에, JSON.parse() 롤 해야합니다.
서버를 다시 실행 후 http://localhost:3000/getUser/first_user 에 접속해보세요.

세번째 API: POST addUser/:username
body: { “password”: “_____”, “name”: “_____” }
이번 API는 첫째 둘째와 다르게 POST 메소드를 사용합니다.
편한 테스팅을 위하여 구글 크롬 익스텐션 Postman 을 사용하겠습니다.
HTTP 패킷을 요청하고 분석 할 수 있는 툴 입니다. 정말 괜찮은 앱이니 받아두세요. 물론 비슷한 프로그램이 이미 설치되있는사람들은 생략하셔도 됩니다.
다음 코드를 router/main.js 의 getUser API 하단에 작성해주세요:
app.post('/addUser/: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 & CHECK DUPLICATION
fs.readFile( __dirname + "/../data/user.json", 'utf8', function(err, data){
var users = JSON.parse(data);
if(users[username]){
// DUPLICATION FOUND
result["success"] = 0;
result["error"] = "duplicate";
res.json(result);
return;
}
// ADD TO 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);
})
})
});
JSON 형태가 INVALID 하다면 오류를 반환하고, VALID 하다면 파일을 열어서 username의 중복성을 확인 후
JSON 데이터에 추가하여 다시 저장합니다.
34번줄에서 stringify(users, null, 2) 은 JSON 의 pretty-print 를 위함 입니다.
Postman을 통하여 API를 테스트해볼까요?

body 에서 Content-type를 JSON 으로 하셔야 정상적으로 처리됩니다.
네번째 API: PUT updateUser/:username
body: { “password”: “_____”, “name”: “_____” }
이 API는 위 API와 비슷합니다. 사용자 정보를 업데이트 하는 API 이구요, PUT 메소드를 사용합니다.
PUT API 는 idempotent 해야 합니다, 쉽게말하자면 즉 요청을 몇번 수행하더라도, 같은 결과를 보장해야합니다.

마지막 API: DELETE deleteUser/:username
유저를 데이터에서 삭제하는 API 입니다. DELETE 메소드를 사용합니다.
네번째 API 아래에 다음 코드를 작성해주세요:
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 users[req.params.username];
fs.writeFile(__dirname + "/../data/user.json",
JSON.stringify(users, null, '\t'), "utf8", function(err, data){
result["success"] = 1;
res.json(result);
return;
})
})
})

router/main.js 전체 코드
module.exports = function(app, fs)
{
app.get('/',function(req,res){
res.render('index', {
title: "MY HOMEPAGE",
length: 5
})
});
app.get('/list', function (req, res) {
fs.readFile( __dirname + "/../data/user.json", 'utf8', function (err, data) {
console.log( data );
res.end( data );
});
});
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]);
});
});
app.post('/addUser/: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 & CHECK DUPLICATION
fs.readFile( __dirname + "/../data/user.json", 'utf8', function(err, data){
var users = JSON.parse(data);
if(users[username]){
// DUPLICATION FOUND
result["success"] = 0;
result["error"] = "duplicate";
res.json(result);
return;
}
// ADD TO 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);
})
})
});
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);
})
})
});
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;
})
})
})
}
이렇게 Express 응용 RESTful API 편을 마치도록 하겠습니다.
다음 편에서는 세션을 다루도록 하겠습니다.

