Outsider's Dev Story

Stay Hungry. Stay Foolish. Don't Be Satisfied.
RetroTech 팟캐스트 44BITS 팟캐스트

node.js 웹프레임워크 express

node.js자체가 상당히 Raw하기 때문에 직접 일일이 조작해서 구현할 수도 있지만 아무래도 생산성이나 퀄리티도 떨어지고 시간도 많이 들기 때문에 Side Effect Studio를 만들면서 직접 서버 구현해서 만들었던 코드에 적용하기 위한 웹프레임워크를 찾았습니다. 작년에도 이미 꽤 퀄리티 좋은 모듈들이 많이 나와있는 상태입니다. 아주 간단한 것들도 많이 있었지만 어느정도 수준의 퀄리티를 바랬기 때문에 웹프레임워크에는 제가 아는 것들로는 express와 fab이 있었고 최근에 알게된 파이썬의 Django를 포팅한 drty정도가 있습니다.

express는 Ruby의 DSL 웹프레임워크인 Sinatra에 영감을 받아 만들어진 node.js 웹 프레임워크인데 저는 express를 선택했습니다.(제가 고민할 당시에는 drty에 대해 몰랐습니다.) 이런 저런 자료를 조금씩 봤었는데 fab과 express는 상당히 다른 접근을 하고 있는데 fab보다는 express가 제가 보기에는 더 익숙한 프레임워크의 형태였고 문서화도 어느정도 되어 있는데다가 코드들을 보니 Sinatra는 써보지 않았지만 꽤 맘에 들었습니다.

express가 제공하는 기능은 상당히 방대하기 때문에 제가 써본 정도만 간단히 소개하겠습니다.




Installation
npm을 사용한 이후로는 node 모듈들의 설치가 아주 쉬워졌고 관리차원에서도 좋기 때문에 대부분의 모듈은 npm을 사용하고 있습니다.

npm install express

위 명령어만 사용하면 express를 설치할 수 있고 npm을 사용하지 않을 경우에는 아래와 같은 명령어를 사용하면 되지만 npm을 사용하지 않을 이유는 별로 없어 보입니다.

curl -# http://expressjs.com/install.sh | sh





Configuration
express를 사용하기 전에 웹서버에서 사용할 간단한 설정을 해주어야 합니다.


var express = require('express'),
      app = express.createServer();

app.configure(function() {
    app.set('views', __dirname + '/views');
    app.set('view options', { layout: false });
    app.use(express.methodOverride());
    app.use(express.bodyDecoder());
    app.use(app.router);
    app.use(express.staticProvider(__dirname + '/public'));
});

express모듈을 가져온 다음에 서버를 생성해서(createServer()) app이라는 변수에 저장한 다음에 configure에 웹서버에 필요한 설정을 추가해 줍니다. set('views') 부분은 뷰로 사용할 파일의 위치를 지정합니다. 일반적으로 자바에서 webContents파일에 .jsp파일을 두는것과 동일하다고 볼 수 있습니다.  set('view options')부분은 페이지의 템플릿역할을 하는 레이아웃 페이지를 사용하지 않도록 지정한 것입니다. 기본적으로는 찾는 페이지의 레이아웃파일을 사용하도록 되어있습니다.

use()는 express에서 제공하는 미들웨어를 사용하도록 지정해 줍니다. methodOverride()는 REST를 사용하기 위한 설정입니다. 웹브라우저가 GET/POST만 지원하기 때문에 관례적으로 _method라는 이름의 hidden input을 두어 HTTP 메서드를 처리하는데 이것을 처리하도록 해줍니다. bodyDecoder()는 express가 기본적으로 요청에 대한 처리를 자동으로 해주지 않기 때문에 application/x-www-form-urlencoded같은 요청을 처리해서 req.body변수에 내용이 담기도록 하기위해서 사용합니다. app.router부분은 뒤에 url에 대해서 라우팅을 위해서 지정하는 app.{get/put/del/post}로 라우팅해줍니다. staticProvider()는 css나 javascript같이 정작파일에 대한 폴더를 지정해 줍니다. 여기서 지정한 폴더에 하위에 있는 내용은 서버처리가 필요없으므로 아파치같은 웹서버처럼 정적파일을 클라이언트가 요청하도록 해줍니다.


app.configure('production', function() {
    app.use(express.logger());
    app.use(express.errorHandler());      
});

app.configure('development', function() {
    app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

글로벌 설정외에 위와같이 환경을 지정해서 추가설정을 해줄 수 있습니다. logger()는 요청에 대한 로그를 아파치 스타일로 출력해 주는 것이고 errorHandler()는 오류에 대한 처리를 지정합니다. 서비스모드에서는 오류를 클라이언트에게 보여주고 싶지 않기 때문에 오류처리를 따로 하지 않고 개발모드에서는 오류메시지를 봐야하기 때문에 예외에대한 dump와 stack을 보여주도록 지정한 것입니다.

NODE_ENV=production node server.js
NODE_ENV=development node server.js

위처럼 노드를 실행할때 환경변수를 지정해 주면 해당 환경에 대한 설정이 적용되게 됩니다.





Routing

app.get('/hello', function(req, res) {
    res.render('index.jade', {
        locals: { 
            message:'hello world'
        }
    });      
});

app.listen(3000);

라우팅은 위와같이 지정합니다. /hello에 대한 GET요청에 대해서는 위의 코드로 라우팅되어 처리가 됩니다. views파일에 있는 index.jade파일을 렌더링해서 보여주고 locals에 지정한 값들은  뷰파일에서 렌더링할때 변수로 사용할 수 있습니다.(Jade는 express에서 지원하는 템플릿엔진중 하나입니다.)

URL은 정규표현식을 사용할 수 있으며 /* 와 같은 형태도 사용가능합니다. app.get()외에도 POST, DELETE, PUT에 대한 HTTP 메서드를 처리하기 위해서 app.post(), app.del(), app.put()도 사용할 수 있습니다. 마지막 라인의 통해서 웹서버를 3000포트에 응답하도록 지정합니다.

뷰파일에 대한 폴더로 지정한 views폴더 아래에 index.jade파일을 아래와 같이 만듭니다.


#{message}

간단히 메시지만 찍어주도록 했습니다.(jade 템플릿엔진의 문법인데 나중에 따로 포스팅하겠습니다.)

이제 http://localhost:3000으로 접속하면 아래와 같은 화면을 볼 수 있습니다.

사용자 삽입 이미지

express는 문서화가 꽤 잘 되어 있기 때문에 가이드페이지를 보시면 express가 지원하는 많은 내용에 대해서 알 수 있습니다. 사실 이정도 간단한 예제는 express HelloWorldEx 같은 명령어를 입력하면 프로젝트명으로 지정한 HelloWorldEx폴더가 생기면서 express의 컨벤션을 따른 간단한 예제가 만들어집니다.
2011/01/27 00:32 2011/01/27 00:32