Fork me on GitHub

Node.js의 고성능, 고품격 웹 애플리케이션 개발

설치

$ npm install express

또는 전역 옵션을 사용하여 express(1)를 설치합니다:

$ npm install -g express

역자주 - npm(node package manager)은 Node.JS에서 사용할 모듈을 설치하는 쉘 명령어입니다.

빠른 시작

Express를 시작하는 가장 쉬운 방법은 실행 가능한 express(1) 을 이용하여 애플리케이션 생성하는 것입니다:

애플리케이션 만들기:

$ npm install -g express
$ express /tmp/foo && cd /tmp/foo

종속성 모듈 설치:

$ npm install -d

서버 시작:

$ node app.js

역자주 - npm에 -g 옵션을 사용하여 전역에서 사용될 모듈로 설치하고 express 쉘 명령을 이용하는 것을 권장합니다.

서버 만들기

express.HTTPServer의 인스턴스를 생성하려면 createServer() 메서드를 호출합니다. 인스턴스인 app을 사용하여 다음 예제인 app.get()에서 행하고 있는 것처럼 HTTP 동사로 라우팅을 정의할 수 있습니다.

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

app.get('/', function(req, res){
  res.send('hello world');
});

app.listen(3000);

HTTPS 서버 만들기

express.HTTPSServer의 초기화는 위의 일반적인 서버의 초기화와 거의 비슷하지만, 허용할 keycert 같은 옵션을 포함하는 개체를 전달하는 것이 다릅니다. 기타 옵션은 node의 https 문서를 참조하십시오.

 var app = require('express').createServer({ key: ... });

환경 설정

Express는 productiondevelopment 모드를 지원합니다. 개발자는 configure() 메서드를 사용하여 현재상황에 필요한 모드를 설정할 수 있습니다. configure()는 첫 인수에 지정된 이름이 없는 경우 모든 모드에 사용되는 환경설정으로 실행합니다.

다음 예제에서는 development 모드에서만 오류 발생시의 스택을 추적하기 위한 설정으로 dumpExceptions옵션을 활성화하고 두 모드의 일반적인 설정으로 methodOverridebodyParser를 이용하고 있습니다. 그 다음으로 설정된 app.router(옵션)는 애플리케이션의 라우팅을 마운트하는데 사용됩니다. 이것을 사용하지 않으면 첫 번째 app.get()app.post() 등의 호출 경로를 마운트합니다.

app.configure(function(){
    app.use(express.methodOverride());
    app.use(express.bodyParser());
    app.use(app.router);
});

app.configure('development', function(){
    app.use(express.static(__dirname + '/public'));
    app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

app.configure('production', function(){
    var oneYear = 31557600000;
    app.use(express.static(__dirname + '/public', { maxAge: oneYear }));
    app.use(express.errorHandler());
});

유사한 방법으로 사용자가 임의로 설정한 문자열을 사용하여 여러가지 환경을 만들수 있습니다:

app.configure('stage', 'prod', function(){
    // config
});

사용자가 원하는 환경을 설정하기 위해, Express는 set(key[, val]), enable(key), disable(key)와 같은 메서드들을 제공합니다:

app.configure(function(){
    app.set('views', __dirname + '/views');
    app.set('views');
    // => "/absolute/path/to/views"

    app.enable('some feature');
    // same as app.set('some feature', true);

    app.disable('some feature');
    // same as app.set('some feature', false);

    app.enabled('some feature')
    // => false
});

지금까지 정의한 환경을 실행에 반영하기 위해서는 NODE_ENV 환경변수를 설정합니다:

$ NODE_ENV=production node app.js

이것은 매우 중요합니다. 적지않은 캐싱 메커니즘이 production 모드에서만 유효하기 때문입니다

세팅

Express는 다음과 같은 설정들을 지원합니다.

라우팅

Express의 라우팅 API는 HTTP 의미를 가지고있는 동사에 기초하였습니다. 예를 들어 /user/12라는 경로는 사용자 계정정보를 표시할 때 다음과 같이 처리합니다. app.get()의 첫 번째 인수에있는 ":id" 플레이스홀더는 req.params 값으로 연결됩니다:

app.get('/user/:id', function(req, res){
    res.send('user ' + req.params.id);
});

이 라우팅은 내부에서 정규식(RegExp)으로 컴파일됩니다. 예를 들어 /user/:id는 다음과 같은 정규식으로 컴파일됩니다:

\/user\/([^\/]+)\/?

더 복잡한 용도로 정규식 리터럴을 직접 전달할 수도 있습니다. 정규식 리터럴의 캡처 그룹은 req.params에서 직접 결과를 받을수 있습니다. 첫 번째 캡처 그룹은 req.params[0]가 되고, 계속 두 번째는 req.params[1]과 같은 상태가됩니다:

app.get(/^\/users?(?:\/(\d+)(?:\.\.(\d+))?)?/, function(req, res){
    res.send(req.params);
});

방금 정의한 라우트에 대한 Curl 요청:

   $ curl http://dev:3000/user
   [null,null]
   $ curl http://dev:3000/users
   [null,null]
   $ curl http://dev:3000/users/1
   ["1",null]
   $ curl http://dev:3000/users/1..15
   ["1","15"]

다음은 라우팅 룰과 실제 경로로 연결되는 몇가지 예제입니다:

 "/user/:id"
 /user/12

 "/users/:id?"
 /users/5
 /users

 "/files/*"
 /files/jquery.js
 /files/javascripts/jquery.js

 "/file/*.*"
 /files/jquery.js
 /files/javascripts/jquery.js

 "/user/:id/:operation?"
 /user/1
 /user/1/edit

 "/products.:format"
 /products.json
 /products.xml

 "/products.:format?"
 /products.json
 /products.xml
 /products

 "/user/:id.:format?"
 /user/12
 /user/12.json

다음 예제는 JSON을 POST하고 bodyParser 미들웨어를 사용하여 JSON을(또는 다른 데이터) 파싱하고 바디에 반환하는 방법입니다. 결과값은 req.body에 저장합니다:

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

app.use(express.bodyParser());

app.post('/', function(req, res){
  res.send(req.body);
});

app.listen(3000);

일반적으로 사용할 수 있는 "/user/:id"는 사용 제한이 없는 "막연한" 플레이스홀더입니다만, 예를 들어, 사용자 ID를 정수로 제한하고 싶다면, /user/:id([0-9]+)와 같이 작성하여 정수만을 가지는 플레이스홀더 값으로 제한할 수 있습니다.

라우트 제어 및 전달

일치하는 라우트만 제어하는 것은 해당 라우트 콜백의 세 번째 인수에 next() 메서드의 호출여부로 결정됩니다. 일치하지 않는다면 use()에 의해 추가된 순서에 따른 미들웨어들의 호출이 계속발생됩니다. 또한 다른 라우트 룰에 합당하는 노선에 대해서도 마찬가지로 호출이 발생합니다. 이것은 단순히 next() 호출이 없어질 때까지 순서대로 실행되어 응답 위치를 결정합니다.

app.get('/users/:id?', function(req, res, next){
    var id = req.params.id;
    if (id) {
        // do something
    } else {
        next();
    }
});

app.get('/users', function(req, res){
    // do something else
});

app.all()은 한 번 호출하여 같은 로직의 모든 HTTP 동사에 적용하는데 도움을 줍니다. 다음 예제는 가상의 데이터베이스에서 사용자를 읽고 그것을 req.user에 할당할 것입니다.

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

var users = [{ name: 'tj' }];

app.all('/user/:id/:op?', function(req, res, next){
  req.user = users[req.params.id];
  if (req.user) {
    next();
  } else {
    next(new Error('cannot find user ' + req.params.id));
  }
});

app.get('/user/:id', function(req, res){
  res.send('viewing ' + req.user.name);
});

app.get('/user/:id/edit', function(req, res){
  res.send('editing ' + req.user.name);
});

app.put('/user/:id', function(req, res){
  res.send('updating ' + req.user.name);
});

app.get('*', function(req, res){
  res.send('what???', 404);
});

app.listen(3000); 

미들웨어

Connect를 통해 사용 가능한 미들웨어를 express.createServer()를 호출할 때 전달하는 예제입니다:

  var express = require('express');

var app = express.createServer(
      express.logger()
    , express.bodyParser()
  );

또 하나, 진보한 방식으로 configure() 블록 내에서 use()를 추가하는 방법이 있습니다:

app.use(express.logger({ format: ':method :url' }));

일반적으로 connect 미들웨어를 사용하는 경우 require('connect')를 작성합니다:

var connect = require('connect');
app.use(connect.logger());
app.use(connect.bodyParser());

이것은 다소 성가시지만 Express는 미들웨어가 똑같은 것이라고해도 그것들을 다시 익스포트합니다:

app.use(express.logger());
app.use(express.bodyParser());

미들웨어의 순서는 중요합니다. Connect가 요청을 받으면 createServer() 또는 use()를 사용하여 전달하고 첫 번째 미들웨어가 세 개의 파라미터와 함께 실행됩니다. 그것은 각각 request, response, 그리고 next라는 인자를 받는 콜백 함수입니다. next()를 호출하여 두 번째 미들웨어가 시작되는 것은 정의된 순서입니다. 이것은 중요한 사항입니다. 왜냐하면 미들웨어들 사이에는 많은 종속성이 존재하기 때문입니다. 예를 들어, methodOverride()HTTP 메서드 재정의를 위해 req.body를 확인하고 bodyParser()요청 바디를 파스(parse)하고 req.body를 채웁니다. 다른 예를 들면, session()_을 실행하기 위해서는 쿠키를 파싱한 후에야 세션이 지원될 수 있습니다. user() cookieParser()가 반드시 앞서 호출되어야 하는 것이죠.

여기서 많은 Express 애플리케이션이 app.use(app.router) 라인을 포함하고 있는 것을 이상하게 생각할지도 모릅니다. 그것은 단순히 정의된 모든 라우트를 포함하는 미들웨어의 기능이며, 현재 요청된 경로와 URL을 HTTP 메서드에 따라 조회를 수행하는 것입니다. 당신은 이 미들웨어를 자유롭게 포지셔닝할 수 있습니다. 이 라인은 기본적으로 가장 아래에 추가됩니다. 라우터를 포지셔닝하여 미들웨어의 우선 순위를 변경할 수 있습니다. 예를 들어, 마지막 미들웨어로 오류보고를 추가한 경우, next()에 전달된 예외를 미들웨어가 처리합니다. 또한 정적인(Static) 파일은 우선 순위를 낮게하여 정적인 파일의 다운로드 수를 계산하고 특정 요청을 중단하는 일도 가능한 것입니다. 조금 예제를 보여 드리죠.

app.use(express.logger(...));
app.use(express.bodyParser(...));
app.use(express.cookieParser(...));
app.use(express.session(...));
app.use(app.router);
app.use(express.static(...));
app.use(express.errorHandler(...));

먼저 node의 req.end() 메서드를 래핑하는 logger()를 추가하면 응답시간 데이터를 제공받을 수 있습니다. 다음 요청의 본문 파싱(if any), 세션을 지원하기 위한 쿠키파서와 세션, 이것은 app.router에 포함된 라우트를 찾았 때 req.session이 정의되는 것을 의미합니다. 만약 GET /javascripts/jquery.js와 같은 요청이 우리의 라우트에서 처리되었을 경우, 그리고 next()를 호출하지 않으면, 비록 이같은 정의라 하더라도 static() 미들웨어는 이 요청을 절대로 만나지 못합니다. 아래와 같이 정의하면 상태를 기록하거나 다운로드 거부 및 다운로드 인증후 응답하는 등이 가능해 집니다.

var downloads = {};

app.use(app.router);
app.use(express.static(__dirname + '/public'));

app.get('/*', function(req, res, next){
  var file = req.params[0];
  downloads[file] = downloads[file] || 0;
  downloads[file]++;
  next();
});

라우트 미들웨어

각 경로는 메서드에 하나 이상의 콜백(또는 배열)을 전달하여 라우트에 맞는 미들웨어를 이용할 수 있습니다. 이 기능은 접근 제한이나 라우트에 필요한 데이터를 로드하는 등 매우 유용합니다.

일반적으로 비동기 데이터 검색은 파라미터 :id를 받아서 다음과 같이 사용자 정보를 얻어내려고 합니다.

app.get('/user/:id', function(req, res, next){
  loadUser(req.params.id, function(err, user){
    if (err) return next(err);
    res.send('Viewing user ' + user.name);
  });
});

낭비를 없애고 가독성을 높이기 위해 이 로직을 미들웨어 논리로 적용해 봅시다. 아래에서 볼 수 있듯이 로직을 미들웨어로 추상화 함으로써 재사용 가능하도록하는 동시에 라우트의 작업이 간결해지고 있습니다.

function loadUser(req, res, next) {
  // You would fetch your user from the db
  var user = users[req.params.id];
  if (user) {
    req.user = user;
    next();
  } else {
    next(new Error('Failed to load user ' + req.params.id));
  }
}

app.get('/user/:id', loadUser, function(req, res){
  res.send('Viewing user ' + req.user.name);
});

라우트 미들웨어는 다중으로 적용할 수도 있습니다. 사용자 계정에 대한 접근제한과 추가적인 논리를 적용하면 순차적으로 실행됩니다. 다음 예제에서는 인증된 사용자에게만 계정의 편집을 허용하는 것입니다.

function andRestrictToSelf(req, res, next) {
  req.authenticatedUser.id == req.user.id
    ? next()
    : next(new Error('Unauthorized'));
}

app.get('/user/:id/edit', loadUser, andRestrictToSelf, function(req, res){
  res.send('Editing user ' + req.user.name);
});

미들웨어는 그냥 단순한 함수라는 것입니다. 따라서 다음과 같이 추가 미들웨어를 반환하는 함수를 정의하여 더 유연한 솔루션을 작성할 수 있습니다.

function andRestrictTo(role) {
  return function(req, res, next) {
    req.authenticatedUser.role == role
      ? next()
      : next(new Error('Unauthorized'));
  }
}

app.del('/user/:id', loadUser, andRestrictTo('admin'), function(req, res){
  res.send('Deleted user ' + req.user.name);
});

일반적으로 사용되는 미들웨어의 "스택"은 배열(applied recursively)로 전달할 수 있습니다. 이들은 혼합이 가능하며 재귀적으로 적용됩니다. 다음 예제를보세요.

var a = [middleware1, middleware2]
  , b = [middleware3, middleware4]
  , all = [a, b];

app.get('/foo', a, function(){});
app.get('/bar', a, function(){});

app.get('/', a, middleware3, middleware4, function(){});
app.get('/', a, b, function(){});
app.get('/', all, function(){});

온전한 예제는 저장소에 있는 route middleware example을 참조하세요.

나머지 미들웨어에 대해서는 생략하도록 하겠습니다. 그러나 이후에도 경로에 대한 매칭은 계속 사용됩니다. 이렇게도 한 번 해보세요. next() 메서드에 "route"라는 문자열을 함께 next('route') 호출합니다. 나머지 라우트들에서 아무런 요청이 발생하지 않은 URL인 경우, Express는 404 Not Found로 응답합니다.

HTTP 메서드

지금까지 여러 번 app.get()라는 메서드를 보아왔지만, Express는 다른 친숙한 HTTP 동사들인 app.post()app.del() 등에 대해서도 유사한 형식으로 처리할 수 있습니다.

폼(form)을 제출했을 때에 해당하는 POST의 일반적인 사용 예제를 봅시다. 다음과 같이 메서드를 "post"로 설정하여 간단한 폼을 html에 작성합니다. 그리고 그 다음으로 정의하는 라우트에서 처리됩니다.

 <form method="post" action="/">
     <input type="text" name="user[name]" />
     <input type="text" name="user[email]" />
     <input type="submit" value="Submit" />
 </form>

기본적으로 Express는 이 요청 바디에 대하여 무엇을 해야할지 모릅니다. 따라서 application/x-www-form-urlencodedapplication/json 요청 바디를 파싱해줄 bodyParser 미들웨어를 추가하고 req.body에 파라미터를 배치해야합니다. 먼저 다음과 깉이 미들웨어를 "사용"하는 작업을 수행합니다.

app.use(express.bodyParser());

이제 req.body.user에 접근할 수 있게 되었습니다. 여기에는 nameemail이 저장되어 있습니다.

app.post('/', function(req, res){
  console.log(req.body.user);
  res.redirect('back');
});

폼에서 PUT과 같은 메서드를 사용하려면 숨겨진 인풋요소를 통하여 _method HTTP 동사를 오버라이딩할 수 있습니다. 먼저 methodOverride 미들웨어를 bodyParser 아래에 둘 필요가 있습니다. 이렇게하면 req.body에서 폼의 값을 포함합니다.

app.use(express.bodyParser());
app.use(express.methodOverride());

Express는 이와 같은 것들이 모든 환경에서 기능하기 위해 항상 기본으로 설정되어 있지 않은 이유는 간단합니다. 애플리케이션의 요구에 따라 이들은 전혀 필요로하지 않을 수도 있으니까요. 또한 PUTDELETE같은 메서드는 사용 가능한 클라이언트에서만 접근할 수 있습니다. 이런 측면에서 methodOverride는 폼을 처리하는 뛰어난 솔루션을 제공한다는 것은 두말할 나위 없습니다. 다음에서 PUT의 사용법을 보여 드리죠.

<form method="post" action="/">
  <input type="hidden" name="_method" value="put" />
  <input type="text" name="user[name]" />
  <input type="text" name="user[email]" />
  <input type="submit" value="Submit" />    
</form>

app.put('/', function(){
    console.log(req.body.user);
    res.redirect('back');
});

오류 처리

app.error() 메서드와 next(err)(임의) 같은 방법으로 라우트에서 발생한 오류를 처리할 수 있습니다. 다음은 애드혹(ad-hoc) NotFound는 오류에 따라 서로다른 페이지를 보여주는 예입니다:

function NotFound(msg){
  this.name = 'NotFound';
  Error.call(this, msg);
  Error.captureStackTrace(this, arguments.callee);
}

NotFound.prototype.__proto__ = Error.prototype;

app.get('/404', function(req, res){
  throw new NotFound;
});

app.get('/500', function(req, res){
  throw new Error('keyboard cat!');
});

종종 다음과 같이 app.error()를 호출할 수 있습니다. 여기에서는 NotFound 인스턴스인지 확인하고 맞는 경우 404 페이지를 그렇지 않은 경우 다음 오류 핸들러를 통해 처리합니다.

이 핸들러는 모든 장소에서 정의할 수있는 것 을 기억하세오. listen()의 라우트 처리기에 넣을 수 있습니다. 이것은 configure() 블록에서 정의 할 수 있다는 것을 의미하며, 따라서 환경에 적합한 다른 방법으로 예외 처리를 할 수 있습니다.

app.error(function(err, req, res, next){
    if (err instanceof NotFound) {
        res.render('404.jade');
    } else {
        next(err);
    }
});

여기에서는 간결함을 위해 모든 오류를 500으로 가정하지만, 물론 당신이 원하는데로 선택할 수 있습니다. 다음 예제에서는 node가 파일 시스템에서 syscalls을 수행할 때 ENOENT 또는 error.code가 오류 개체를 나타나도록 하는 것입니다. 이 오류는 "no such file or directory"를 의미합니다. 우리는 언제든지 이 개체를 사용하여 오류를 조율할 수 있으며, 필요한 경우 특정 오류 페이지를 표시합니다.

app.error(function(err, req, res){
  res.render('500.jade', {
     error: err
  });
});

또한 Connect의 errorHandler 미들웨어를 사용할 수도 있습니다. "development"모드에서 stderr(표준 오류 출력)을 사용하려면 다음과 같이 하면 됩니다:

app.use(express.errorHandler({ dumpExceptions: true }));

개발하는 동안에는 스텍 추적 기능을 갖춘 오류가 표시되는 html 페이지를 갖고 싶어질 것입니다. 그럴 때는 showStack을 true로 설정합니다:

app.use(express.errorHandler({ showStack: true, dumpExceptions: true }));

요청 헤더가 Accept: application/json인 경우 errorHandler 미들웨어는 json형식의 오류로 응답할 수 있습니다. 클라이언트 사이드에 강하게 의존하는 애플리케이션을 개발하는 동안에는 이 방법이 아주 유용합니다.

라우트 파라미터의 사전 처리

라우트 파라미터의 사전처리는 데이터의 암시적인 읽기 및 요청 URL의 검증을 통해 애플리케이션의 가독성을 크게 향상시킵니다. 예를 들어, 여러 라우트에 대해서 공통의 데이터를 한결같이 배치하고 싶다면, 우리는 보통 다음과 같이 /user/:id로 사용자 정보읽기를 시도할수 있습니다:

app.get('/user/:userId', function(req, res, next){
  User.get(req.params.userId, function(err, user){
    if (err) return next(err);
    res.send('user ' + user.name);
  });
}); 

전제 조건으로 각 파라미터는 유효성 검사, 형식 강제, 또는 데이터베이스에서 데이터 읽어오는 등의 작업을 수행하는 콜백을 매핑할 수 있습니다. 다음에서 app.param()을 호출하는 데에서 볼 수 있듯이 플레이스홀더의 값에 포함된 id를 일부 미들웨어에 할당하고 파라미터 이름과 함께 호출합니다. 이것으로 사용자의 정보를 읽고 평소와 같이 오류 처리를 수행합니다. 단지 next()를 호출하면 다음의 조건이나 경로 처리기에 제어권을 전달합니다.

app.param('userId', function(req, res, next, id){
  User.get(id, function(err, user){
    if (err) return next(err);
    if (!user) return next(new Error('failed to find user'));
    req.user = user;
    next();
  });
});

이렇게하면 라우팅의 가독성이 크게 향상되고 앞서 언급했듯이 애플리케이션 전체에서 공유하는 것이 용이해 집니다.

app.get('/user/:userId', function(req, res){
  res.send('user ' + req.user.name);
});

뷰 렌더링

뷰 파일의 이름은 "<name>. <engine>"형식을 취합니다. 보통 <engine>은 모듈의 이름이며 별도로 호출해야합니다. 예를 들어 layout.ejs라는 뷰를 사용하기 위해서는 require('ejs')를 통해 적합한 뷰 엔진을 로드해야합니다. 또한 로드된 모듈은 상황에 따라서 exports.compile(str, options) 메서드를 호출할 필요가 있으며, 이때 Express에서 사용할 준비가 된 함수를 반환해 줍니다. 작동 방식을을 변경하려면 app.register()를 사용하여 파일의 확장명과 엔진을 매핑해야합니다. 이를테면 "foo.html"는 ejs에 의해 렌더링되도록 뷰 엔진에게 지시할 수 있습니다.

다음 예제는 Jade 뷰 엔진을 사용하여 index.html을 다루는 것입니다. layout: false 옵션을 사용하지 않는 한 index.jadebody라는 지역 변수로 layout.jade파일에 전달됩니다.

app.get('/', function(req, res){
    res.render('index.jade', { title: 'My Site' });
});

view engine 설정으로 기본 템플릿 엔진을 지정할 수 있습니다. Jade를 사용하는 경우 다음과 같이 지정합니다:

app.set('view engine', 'jade');

이제 Jade 뷰 엔진을 사용하여 그려 봅시다:

res.render('index');

또는:

res.render('index.jade');

view engine이 설정되어있는 경우 확장자는 생략해도 됩니다만, 다수의 템플릿 엔진을 혼합하여 사용하는 경우라면 확장자로 구분할 수 있습니다:

res.render('another-page.ejs');

Express는 여러가지 view options(뷰 옵션들)을 제공합니다. 예를 들어 대부분의 컨텐츠가 레이아웃을 사용하지 않으려면 다음과 같이 설정하여 레이아웃 호출을 피할수 있습니다:

app.set('view options', {
  layout: false
});

이것은 개별적으로 res.render()를 호출할 때마다 다시 정의할 수도 있습니다:

res.render('myview.ejs', { layout: true });

대신 레이아웃을 필요로하는 경우에는 레이아웃의 경로를 지정해야 합니다. 예를 들어 view enginejade로 설정되었고, 레이아웃 파일 이름이 ./views/mylayout.jade이라면 그냥 이렇게 설정합니다:

res.render('page', { layout: 'mylayout' });

또는 확장명을 지정할 수 있습니다:

res.render('page', { layout: 'mylayout.jade' });

전체 경로를 지정한 것입니다:

res.render('page', { layout: __dirname + '/../../mylayout.jade' });

아래에 좋은 예를 소개합니다. 뷰 템플릿에서 사용할 열고 닫는 태그를 사용자가 지정하여 ejs에 전달한 것입니다:

app.set('view options', {
    open: '{{',
    close: '}}'
});

역자주 - 이것은 뷰 파일에서 <h1>{{= title }}</h1>처럼 변수가 호출에 사용되는 것을 말합니다. 참고로, ejs 템플릿 엔진의 기본 코드는 <%= code %>입니다.

뷰 파셜

Express 뷰 시스템은 파셜과 컬렉션을 기본으로 내장하여 지원하며 뷰는 "작은" 문서의 조각들을 나타냅니다. 예를 들어 반복적으로 표시되는 댓글과 같은 것을 화면에 표시하기 위해서는 파셜 컬렉션을 사용하는 것이 좋습니다:

partial('comment', { collection: comments });

만약 별다른 옵션이 없거나 원하는 지역 변수가 없는 경우 객체를 생략하고 단지 배열만을 전달하면됩니다. 다음과 같습니다:

partial('comment', comments);

파셜 컬렉션을 사용하고 있는 동안에는 몇 가지 "마법"과 같은 지역 변수들을 제공합니다.

지역 변수들은 전달(또는 생성)을 우선적으로 처리합니다. 부모 뷰에 전달되는 지역 객체가 자식 뷰에서 유효하더라도 우선시됩니다. 예를 들어, 블로그 기사를 만들어야 한다면 partial('blog/post', post)와 같이 사용합니다. post라는 지역 객체가 생성되지만 이 함수를 호출하는 뷰는 user라는 지역 객체를 가지고 있으며, 그것은 blog/post 뷰에서 마찬가지로 이용할 수 있도록합니다.

개체의 이름을 변경하는 방법은 res.partial() 문서를 참조하십시오.

참고 : 파셜 컬렉션을 사용할 때 길이가 100인 배열을 렌더링한다는 것은 100개의 뷰를 렌더링하는 것을 의미한다는 것에 주의하십시오. 간단한 컬렉션은 파셜 컬렉션을 사용하는 대신 인라인 반복을 사용하는 것이 오버헤드를 줄일수 있습니다.

뷰 조회

뷰 조회는 부모의 뷰를 기준으로 동작합니다. 예를 들어 views/user/list.jade는 뷰 페이지가 그 안에서 partial('edit')views/user/edit.jade를 로드하는 한편, partial('../messages')에 의해 views/messages.jade를 로드합니다.

또한 뷰 시스템은 인덱스 템플릿을 지원합니다. 동일한 디렉토리에 "index.*"를 두는 것만으로 이 기능은 작동합니다. 예를 들어 라우트에서 res.render('users')가 호출되면 views/users.jade 또는 views/users/index.jade로 라우트됩니다.

위와 같은 상황에서 인덱스 뷰를 사용하여 동일한 디렉토리에 뷰 파일은 partial('users')에 의해 views/users/index.jade를 참조하고 뷰 시스템은 partial('index')이 호출되는 것을 방지하기 위해 ../users/index경로만으로 해결을 시도합니다.

템플릿 엔진

Express에서 사용할 수 있는 템플릿 엔진들은 다음과 같습니다:

세션 지원

세션을 지원하는 것은 Connectsession 미들웨어를 사용합니다. 또한 앞서 말한바 있는 req.cookies에 담겨진 쿠키의 데이터를 분석해 주는 cookieParser 미들웨어의 사전 배치가 필요합니다.

app.use(express.cookieParser());
app.use(express.session({ secret: "keyboard cat" }));

기본적으로 session 미들웨어는 Connect에서 제공하는 번들 메모리를 저장소로 사용하지만 이 밖에도 다른 저장소들이 사용할 수도 있습니다. 예를 들어 connect-redisRedis스타일 세션 저장소를 제공하며, 다음과 같이 사용합니다:

var RedisStore = require('connect-redis')(express);
app.use(express.cookieParser());
app.use(express.session({ secret: "keyboard cat", store: new RedisStore }));

이제 req.sessionreq.sessionStore 속성으로 모든 라우트와 미들웨어들이 접근할 수 있습니다. req.session 속성은 응답과 동시에 자동으로 저장됩니다. 장바구니에 데이터를 담는 예를 들어봅시다:

var RedisStore = require('connect-redis')(express);
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.session({ secret: "keyboard cat", store: new RedisStore }));

app.post('/add-to-cart', function(req, res){
  // Perhaps we posted several items with a form
  // (use the bodyParser() middleware for this)
  var items = req.body.items;
  req.session.items = items;
  res.redirect('back');
});

app.get('/add-to-cart', function(req, res){
  // When redirected back to GET /add-to-cart
  // we could check req.session.items && req.session.items.length
  // to print out a message
  if (req.session.items && req.session.items.length) {
    req.flash('info', 'You have %s items in your cart', req.session.items.length);
  }
  res.render('shopping-cart');
});

req.session 개체 또한 Session#touch(), Session#destroy(), Session#regenerate()와 같은 메서드를 가지며 이것으로 다른 사용자의 세션을 조작하거나 관리할 수 있습니다. 보다 자세한 정보는 Connect Session 문서를 참조하십시오.

마이그레이션 가이드

Express 1.x을 이용한 개발자를 위한 참조입니다. Express 2.x와 Connect 1.x, 그리고 Node 0.4.x을 이용하여 기존 애플리케이션을 업그레이드하고 속도까지 향상시킬수 있는 방법이 담긴 마이그레이션 가이드(영문) 문서를 참조하세요.

req.header(key[, defaultValue])

대/소문자를 구분하지 않는 로 요청 헤더를 가져옵니다. (옵션으로 defaultValue를 함께 사용):

req.header('Host');
req.header('host');
req.header('Accept', '*/*');

ReferrerReferer 필드는 다음과 같이 조금 독특하게 작동합니다:

// sent Referrer: http://google.com

req.header('Referer');
// => "http://google.com"

req.header('Referrer');
// => "http://google.com"

req.accepts(type)

Accept 헤더가 있는지 여부와 주어진 type을 포함하는지 확인합니다.

Accept가 아예 없는 경우는 true를 돌려줍니다. 주어진 type이 유형에서 문자열을 포함하거나 정확하게 일치하는 경우에도 마찬가지입니다. "html"을 유형으로 전달하면 헤더의 "MIME"을 조회하여 포함 또는 일지 여부를 반환하는 것입니다.

// Accept: text/html
req.accepts('html');
// => true

// Accept: text/*; application/json
req.accepts('html');
req.accepts('text/html');
req.accepts('text/plain');
req.accepts('application/json');
// => true

req.accepts('image/png');
req.accepts('png');
// => false

req.is(type)

받은 요청으로부터 Content-Type 헤더를 검사하고, type에 지정된 MIME 타입을 가지고 있는지 확인합니다.

   // With Content-Type: text/html; charset=utf-8
   req.is('html');
   req.is('text/html');
   // => true

   // When Content-Type is application/json
   req.is('json');
   req.is('application/json');
   // => true

   req.is('html');
   // => false

Express에서는 애드혹(ad-hoc) 콜백을 등록하여 사용자 지정 타입을 만들어 낼 수 있습니다. 예를 들어, 받은 요청이 이미지 파일인 것을 확인하는 방법으로 다음과 같이 "an image" 콜백을 등록했습니다:

    app.is('an image', function(req){
      return 0 == req.headers['content-type'].indexOf('image');
    });

이제 "image/jpeg""image/png"같은 컨텐트의 타입은 라우트의 콜백 안에서 아래처럼 이용할 수 있습니다.

   app.post('/image/upload', function(req, res, next){
     if (req.is('an image')) {
       // do something
     } else {
       next();
     }
   });

이 메서드는 Content-Type만을 검사하는 용도가 아니라는것을 기억하세요. 당신이 원하는 모든 표현에 사용할 수 있습니다.

와일드카드 매칭도 준비되어 있으므로, 위의 "an image" 예제는 하위 유형만으로 구분할 수 있도록 다음과 같은 간단한 형태로 바꿀 수 있습니다.

req.is('image/*');

물론, type에 의한 표현도 가능합니다. 다음 예제에서는 "application/json""text/json"에 대해 true를 반환합니다.

req.is('*/json');

req.param(name[, default])

name에 지정된 파라미터의 값 또는 default를 반환합니다.

인코딩된 URL의 바디 파라미터에 사용하려면 req.body 객체를 이용해야합니다. 이것은 _express.bodyParser 미들웨어에 의해 이루어집니다.

req.get(field, param)

필드param 값을 가져오며, param 또는 field가 존재하지 않을때 기본값인 ''(빈 문자열)을 돌려줍니다.

 req.get('content-disposition', 'filename');
 // => "something.png"

 req.get('Content-Type', 'boundary');
 // => "--foo-bar-baz"

req.flash(type[, msg])

지정된 typemsg를 플래시를 큐에 추가합니다.

req.flash('info', 'email sent');
req.flash('error', 'email delivery failed');
req.flash('info', 'email re-sent');
// => 2

req.flash('info');
// => ['email sent', 'email re-sent']

req.flash('info');
// => []

req.flash();
// => { error: ['email delivery failed'], info: [] }

플래시 알림 메시지는 포매터(formatter)를 사용할 수도 있습니다. 기본적으로 %s만 유효합니다:

req.flash('info', 'email delivery to _%s_ from _%s_ failed.', toUser, fromUser);

req.isXMLHttpRequest

req.xhr의 별칭입니다. 이 게터(getter)는 요청이 XMLHttpRequest에 의한 것인지 알아내기 위하여 X-Requested-With 헤더를 확인합니다:

req.xhr
req.isXMLHttpRequest

res.header(key[, val])

key로 지정된 응답 헤더의 값을 가져 오거나 설정합니다.

res.header('Content-Length');
// => undefined

res.header('Content-Length', 123);
// => 123

res.header('Content-Length');
// => 123

res.charset

이후 응답할 컨텐츠의 Content-Type 헤더 필드에 문자셋(charset)을 설정합니다. 예를 들어 res.send()res.render()는 기본적으로 "utf8"이 지정되어 있습니다만, 템플릿이 그려지기 전에 이것을 명시적으로 설정해야 합니다:

res.charset = 'ISO-8859-1';
res.render('users');

또는 res.send()에서 응답하기 전에:

res.charset = 'ISO-8859-1';
res.send(str);

또는 node의 res.end()이전에 :

res.charset = 'ISO-8859-1';
res.header('Content-Type', 'text/plain');
res.end(str);

res.contentType(type)

응답 헤더의 Content-Type을 입력받은 type으로 설정합니다.

  var filename = 'path/to/image.png';
  res.contentType(filename);
  // Content-Type is now "image/png"

Content-Type 리터럴도 마찬가지로 작동합니다:

  res.contentType('application/json');

또한 단순히 확장자만으로도 지정할 수 있습니다:

  res.contentType('json');

res.attachment([filename])

응답 헤더의 Content-Disposition를 "attachment"로 설정합니다.(옵션 filename)

  res.attachment('path/to/my/image.png');

res.sendfile(path[, options[, callback]])

임의의 파일 전송을 위한 res.download()에 의해 사용됩니다.

res.sendfile('path/to/my.file');

이 메서드는 예외 발생시 또는 전송이 완료될 때 호출되는 콜백을 받습니다. 기본적으로 오류가 발생하면 next(err)가 호출되지만, 콜백을 전달한 경우 오류가 무시되기 때문에 오류 발생시 행동을 명시적으로 지정해야합니다.

res.sendfile(path, function(err){
  if (err) {
    next(err);
  } else {
    console.log('transferred %s', path);
  }
});

옵션은 내부적으로 호출되는 fs.createReadStream()에 전달됩니다. 이것을 이용하면 bufferSize을 변경할 수 있습니다:

res.sendfile(path, { bufferSize: 1024 }, function(err){
  // handle
});

res.download(file[, filename[, callback[, callback2]]])

주어진 file을 전송합니다.(옵션 alternative filename)

res.download('path/to/image.png');
res.download('path/to/image.png', 'foo.png');

이것은 다음과 동일합니다:

res.attachment(file);
res.sendfile(file);

두 번째 또는 세 번째 인수로 콜백을 전달할 수 있습니다. 이 콜백은 res.sendfile()에 전달됩니다. 헤더의 전송이 완료되지 않은 경우이 콜백에서 응답을 계속할 수 있습니다.

res.download(path, 'expenses.doc', function(err){
  // handle
});

두 번째 콜백 옵션인 callback2는 연결 오류 발생시에 대한 처리를 지정합니다. 여기에서 응답을 시도해서는 안됩니다.

res.download(path, function(err){
  // error or finished
}, function(err){
  // connection related error
});

res.send(body|status[, headers|status[, status]])

res.send() 메서드는 json이나 html 문자열, Buffer 인스턴스 또는 상태 코드의 숫자 등으로 응답하는 높은 수준의 응답 유틸리티입니다. 다음은 모두 유효한 사용 방법들입니다.

 res.send(); // 204
 res.send(new Buffer('wahoo'));
 res.send({ some: 'json' });
 res.send('<p>some html</p>');
 res.send('Sorry, cant find that', 404);
 res.send('text', { 'Content-Type': 'text/plain' }, 201);
 res.send(404);

기본적으로 Content-Type 응답 헤더에 설정됩니다. 그러나 이 이전에 res.send() 또는 res.header() 또는 res.contentType()를 사용하여 명시적으로 할당했다면 재설정 되지 않을 것입니다.

이 메서드는 end()에서 처리되는 것에 주의하십시오. 그래서 여러 스트리밍을 쓰기위해서는 node의 res.write()를 사용하세요.

res.json(obj[, headers|status[, status]])

JSON으로 응답을 보냅니다. headersstatus를 포함할 수 있습니다. 이 메서드는 JSON형식의 API를 제공하기에 이상적입니다. res.send(obj) 역시도 JSON을 잘 보냅니다만, 다음 예제와 같은 키/값 형식의 문자열로도 사용이 가능합니다. res.send(string)과 같이 문자열이 대입될 경우 text/html로 응답해 버리거든요.

res.json(null);
res.json({ user: 'tj' });
res.json('oh noes!', 500);
res.json('I dont have that', 404);

res.redirect(url[, status])

지정된 url로 리디렉션합니다. 기본 status 코드는 302이며 옵션입니다.

res.redirect('/', 301);
res.redirect('/account');
res.redirect('http://google.com');
res.redirect('home');
res.redirect('back');

Express는 "리디렉션 매핑"을 지원하며 기본적으로 homeback이 제공됩니다. back 맵은 ReferrerReferer 헤더를 확인하고 home은 “basepath” 설정이고 기본적으로 "/"로 각각 매핑되어 있습니다.

res.cookie(name, val[, options])

지정된 nameval에 쿠키를 설정합니다. 옵션으로는 httpOnly, secure, expires 등이 있습니다. path옵션의 기본은 애플리케이션의 “basepath” 설정이며, 일반적으로 "/"입니다.

// "Remember me" for 15 minutes 
res.cookie('rememberme', 'yes', { expires: new Date(Date.now() + 900000), httpOnly: true });

maxAge속성은 Date.now()에서 얻어진 밀리세컨즈의 값으로 expires 설정에 사용할 수 있습니다. 이 방법을 사용하려면 다음과 같이 합니다:

res.cookie('rememberme', 'yes', { maxAge: 900000 });

받은 Cookie헤더를 구문 분석하려면 cookieParser 미들웨어를 사용하고, req.cookies 개체로 접근합니다.

app.use(express.cookieParser());

app.get('/', function(req, res){
  // use req.cookies.rememberme
});

res.clearCookie(name[, options])

"만료(expires)"되기 이전에 설정된 쿠키를 name으로 찾아 삭제합니다. res.cookie()와 유사하며 path 옵션은 기본으로 "basepath" 설정을 따릅니다.

res.clearCookie('rememberme');

res.render(view[, options[, fn]])

주어진 options으로 view를 그린 후 콜백 함수 fn에 전달합니다. 콜백 함수가 주어진 경우, 응답은 자동으로 이루어지지 않습니다. 그렇지 않으면, 200 상태 코드와 text/html로 응답하게 됩니다.

또한 options 내에 전달된 속성들은 뷰에서 지역 변수로 사용됩니다. 예를 들어 어떠한 "사용자"를 특정 뷰에 대해서만 노출하고 개체 내에서만 접근하게 하려면 다음과 같이 합니다:

var user = { name: 'tj' };
res.render('index', { layout: false, user: user });

여기에 전달된 options 개체는 그냥 “options” 개체로 간주됩니다. 예들 들면, 이 로컬의 status를 통과하면 이 것은 오직 뷰만 활성화 되지 않은 것입니다. 여기에서는 번호로 응답상태를 설정합니다. 템플릿 엔진은 특정 옵션을 허용 경우에 debug하거나, compress할 때 유용하게 사용됩니다. 아래는 오류 페이지를 만드는 예제입니다 status를 출력하고 res.statusCode를 설정합니다.(응?)

 res.render('error', { status: 500, message: 'Internal Server Error' });

res.partial(view[, options])

view를 파셜하여 주어진 options으로 그립니다. 이 메서드는 지역 변수로 항상 뷰에서 사용할 수 있습니다.

다음 예제는 모두 동일합니다. 컬렉션의 값 이름은 파셜로 전달될 때 뷰의 이름으로 부터 파생되어 movie가 된 것입니다.

partial('theatre/movie.jade', { collection: movies });
partial('theatre/movie.jade', movies);
partial('movie.jade', { collection: movies });
partial('movie.jade', movies);
partial('movie', movies);
// In view: movie.director

이를 movie에서 video로 변경하려면 "as" 옵션을 사용합니다:

partial('movie', { collection: movies, as: 'video' });
// In view: video.director

또한 뷰 속에서 this는 movie를 가르키므로 movie.director 대신 this.director로 바꿀 수 있습니다.

partial('movie', { collection: movies, as: this });
// In view: this.director

또 다른 하나는 컬렉션의 항목의 속성을 as: global 옵션을 사용하여 가상 전역(지역 변수)으로 "확장(expand)"하는 것입니다. 다음 구문을 봅시다.

partial('movie', { collection: movies, as: global });
// In view: director

이 같은 로직을 적용한 단독 파셜 개체 사용법입니다:

partial('movie', { object: movie, as: this });
// In view: this.director

partial('movie', { object: movie, as: global });
// In view: director

partial('movie', { object: movie, as: 'video' });
// In view: video.director

partial('movie', { object: movie });
// In view: movie.director

컬렉션이 아닌 경우(.length를 가지지 않음)에는 두 번째 인수로 전달된 것은 객체로 간주되며, 이후 객체가 가지는 지역 변수의 이름은 뷰의 이름에서 파생됩니다:

var movie = new Movie('Nightmare Before Christmas', 'Tim Burton')
partial('movie', movie)
// => In view: movie.director

이 예외는 "{}"와 "new Object"같은 일반적인 개체가 전달되었을 지역 개체와 변수로 간주합니다. 다음 예제에서는 "movie"가 지역 객체가 되는 것을 기대하고 있습니다만, 그것은 일반 객체이기 때문에 "director"와 "title"은 단지 지역 개체입니다.

var movie = { title: 'Nightmare Before Christmas', director: 'Tim Burton' }; 
partial('movie', movie)

이렇게 일반적인 개체가 전달되기를 바라는 경우, 그냥 키를 할당하거나 object키를 사용하면 파일 이름에서 파생된 변수 이름을 사용하는 것입니다. 다음 예제도 동일합니다:

 partial('movie', { locals: { movie: movie }})
 partial('movie', { movie: movie })
 partial('movie', { object: movie })

이 엄격한 API는 Ajax 또는 WebSocket을 통한 단편적인 응답을 위한 내부 경로에서 활용될 수 있습니다. 예를 들면 라우트에서 직접 사용자 디렉토리의 컬렉션을 볼 수 있습니다.

app.get('/users', function(req, res){
  if (req.xhr) {
    // respond with the each user in the collection
    // passed to the "user" view
    res.partial('user', users);
  } else {
    // respond with layout, and users page
    // which internally does partial('user', users)
    // along with other UI
    res.render('users', { users: users });
  }
});

res.local(name[, val])

지정된 지역 변수 name으로 값을 설정하거나 가져옵니다. 이 지역 변수는 응답이 res.render()와 같은 뷰 렌더 메서드에 적용될 때 만들어집니다.

  app.all('/movie/:id', function(req, res, next){
    Movie.get(req.params.id, function(err, movie){
      // Assigns res.locals.movie = movie
      res.local('movie', movie);
    });
  });

  app.get('/movie/:id', function(req, res){
    // movie is already a local, however we
    // can pass more if we wish
    res.render('movie', { displayReviews: true });
  });

res.locals(obj)

주어진 obj와 함께 여러 지역 변수를 할당합니다. 다음 예제는 동일합니다:

 res.local('foo', bar);
 res.local('bar', baz);

 res.locals({ foo: bar, bar, baz });

app.set(name[, val])

애플리케이션 수준의 설정을 nameval로 설정합니다. 또는 val이 생략된 경우는 name 값을 가져옵니다:

app.set('views', __dirname + '/views');
app.set('views');
// => ...path...

또는 app.settings를 통해서 세팅 값에 간단하게 접근할 수 있습니다:

app.settings.views
// => ...path...

app.enable(name)

name 설정을 활성화합니다:

app.enable('some arbitrary setting');
app.set('some arbitrary setting');
// => true

app.enabled('some arbitrary setting');
// => true

app.enabled(name)

name 설정이 유효한지 확인합니다:

app.enabled('view cache');
// => false

app.enable('view cache');
app.enabled('view cache');
// => true

app.disable(name)

name 설정을 비활성화합니다:

app.disable('some setting');
app.set('some setting');
// => false

app.disabled('some setting');
// => false

app.disabled(name)

name설정이 무효한지 확인합니다:

app.enable('view cache');

app.disabled('view cache');
// => false

app.disable('view cache');
app.disabled('view cache');
// => true

app.configure(env|function[, function])

이 콜백 함수는 지정된 env(또는 모든 환경)에 사용될 콜백 함수를 정의합니다:

app.configure(function(){
    // executed for each env
});

app.configure('development', function(){
    // executed for 'development' only
});

app.redirect(name, val)

res.redirect()와 함께 사용하여 애플리케이션 수준에서 리디렉션 매핑을 가능하게 합니다:

app.redirect('google', 'http://google.com');

이제 라우트에서호출합니다.

res.redirect(‘google’);

동적 리디렉션 매핑도 가능합니다.

app.redirect('comments', function(req, res){
  return '/post/' + req.params.id + '/comments';
});

이제 다음과 같이 호출하면, 요청의 컨텍스트에 따라 동적으로 조정되어 리디렉션됩니다. 만약 GET /post/12로 라우트를 호출하면 리디렉션 주소/post/12/comments가 될 것입니다.

app.get('/post/:id', function(req, res){
  res.redirect('comments');
});

마운트시 res.redirect()는 마운트 지점과 관련됩니다. 예를 들어 블로그 애플리케이션이 /blog에 마운트된 경우, 다음은 /blog/posts로 리디렉션됩니다.

res.redirect('/posts');

app.error(function)

오류 헨들러 function을 추가합니다. 이 함수는 다음과 같이 첫 번째 인수에서 예외 개체를 받습니다. 여러번 이 메서드를 호출하여 여러가지 오류를 처리하도록 설정할 수 있지만, 이 헨들러는 반드시 next(err)를 명시적으로 호출할 필요가 있다는 것에 주의 하세요:

app.error(function(err, req, res, next){
  res.send(err.message, 500);
});

app.helpers(obj)

정적인 뷰 헬퍼를 등록합니다.

app.helpers({
    name: function(first, last){ return first + ', ' + last }
  , firstName: 'tj'
  , lastName: 'holowaychuk'
});

이제 뷰에서 firstNamelastName이라는 변수를 사용할 수 있을 뿐만 아니라 name()라는 함수도 제공됩니다.

<%= name(firstName, lastName) %>

Express는 기본적으로 몇 가지의 지역 개체를 제공합니다.

- `settings`  the app's settings object
- `filename`  the view's filename
- `layout(path)`  specify the layout from within a view

이 메서드는 app.locals()의 별칭입니다.

app.dynamicHelpers(obj)

동적 뷰 헬퍼를 등록합니다. 동적 뷰 헬퍼는 reqres를 인수로 취하는 단순한 함수입니다. 뷰를 그리기 전에 Server 인스턴스에 의해 실행됩니다. 이 함수의 반환값은 객체의 속성에 연결된 지역 개체입니다.

app.dynamicHelpers({
  session: function(req, res){
    return req.session;
  }
});

모든 뷰에서 세션을 사용 가능해지며 session.name 등의 데이터에 접근할 수 있습니다:

<%= session.name %>

app.lookup

http 메서드인 app.lookup은 지정된 path에 연결된 콜백 함수의 배열을 반환합니다.

다음과 같은 라우팅을 정의했다고 가정합니다.

  app.get('/user/:id', function(){});
  app.put('/user/:id', function(){});
  app.get('/user/:id/:op?', function(){});

이 조회 기능은 어떤 경로가 정의되었는지 확인하는 데 사용할 수 있으며 Express로 만든 높은 수준의 프레임워크를 구축하는데 있어서 매우 유용합니다.

  app.lookup.get('/user/:id');
  // => [Function]

  app.lookup.get('/user/:id/:op?');
  // => [Function]

  app.lookup.put('/user/:id');
  // => [Function]

  app.lookup.all('/user/:id');
  // => [Function, Function]

  app.lookup.all('/hey');
  // => []

app.lookup.VERB()의 별칭이며 콜백을 생략하고 app.VERB()로 단축해서 라는 사용할 수 있습니다. 예를 들어 다음 예제는 동일합니다:

  app.lookup.get('/user');
  app.get('/user');

반환된 함수는 다음과 같은 속성을 가지고 있습니다.

  var fn = app.get('/user/:id/:op?')[0];

  fn.regexp
  // => /^\/user\/(?:([^\/]+?))(?:\/([^\/]+?))?\/?$/i

  fn.keys
  // => ['id', 'op']

  fn.path
  // => '/user/:id/:op?'

  fn.method
  // => 'GET'

app.match

http 메서드인 app.match는 지정된 url에 일치하는 콜백 함수의 배열을 반환합니다. 쿼리 문자열 등을 포함할 수 있습니다. 이것은 어떤 라우트가 해당 주소로 사용되고 있는지 찾을 때 유용합니다.

다음과 같은 라우팅을 정의했다고 가정합니다.

    app.get('/user/:id', function(){});
    app.put('/user/:id', function(){});
    app.get('/user/:id/:op?', function(){});

GET에 대한 합당하는 두 개의 함수를 반환합니다. 두 번째 라우트에있는 :op 이후는 옵션입니다.

  app.match.get('/user/1');
  // => [Function, Function]

이 두 번째 호출은 /user/:id/:op?의 콜백만을 반환합니다.

  app.match.get('/user/23/edit');
  // => [Function]

또한 all()를 사용하여 http 메서드를 무시한 모든 콜백을 얻을 수도 있습니다:

  app.match.all('/user/20');
  // => [Function, Function, Function]

일치하는 각각의 함수는 다음과 같은 속성을 가지고 있습니다:

  var fn = app.match.get('/user/23/edit')[0];

  fn.keys
  // => ['id', 'op']

  fn.params
  // => { id: '23', op: 'edit' }

  fn.method
  // => 'GET'

app.mounted(fn)

ServerServer#use()에 전달되면 호출되는 콜백인 fn을 할당합니다.

var app = express.createServer(),
    blog = express.createServer();

blog.mounted(function(parent){
  // parent is app
  // "this" is blog
});

app.use(blog);

app.register(ext, exports)

exports에 지정된 템플릿 엔진을 ext에 지정된 형식으로 출력하도록 등록합니다. 예를 들어 "html"을 Jade에 매핑하려면:

 app.register('.html', require('jade'));

이것은 임의의 확장명이어서 일치하지 않는 라이브러리에 매핑할 때 유용합니다. 예를 들어 내 haml.js 라이브러리는 npm에서 "hamljs"로 설치되었습니다. 따라서 layout.hamljs 대신에 "haml"을 그 엔진으로 등록합니다.

 app.register('.haml', require('haml-js'));

Express 규격을 준수하지 않은 엔진에 대해서는 다음과 같은 방법으로 그들의 API를 래핑하는 것도 가능합니다. 다음 예제에서는 .md 마크다운 파일을 뷰 렌더에 매핑하는 것입니다. 한번 html로 렌더링하면 그 이후 호출에서 변경되지 않기 때문에 "{name}"와 같은 형식으로 대체하는 것이 가능합니다.

  app.register('.md', {
    compile: function(str, options){
      var html = md.toHTML(str);
      return function(locals){
        return html.replace(/\{([^}]+)\}/g, function(_, name){
          return locals[name];
        });
      };
    }
  });

app.listen([port[, host]])

애플리케이션 서버가 지정된 포트를 바인드합니다. 기본값은 3000번입니다. 호스트가 생략된 경우 INADDR_ANY를 통해 모든 연결을 허용합니다.

app.listen();
app.listen(3000);
app.listen(3000, 'n.n.n.n');

port 인자는 유닉스 도메인 소켓 경로를 표현하는 문자열로도 사용할 수 있습니다.

app.listen('/tmp/express.sock');

시도해 봅시다.

$ telnet /tmp/express.sock
GET / HTTP/1.1

HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 11

Hello World