익스프레스(Express)로 시간 절약

익스프레스(Express)로 시간 절약

  • 앞서 노드만을 사용해 단순한 웹 서버를 만드는 방법을 배웠다.
  • 이 장에서는 익스프레스(Express)를 사용해 그 서버를 다시 만든다.
  • 익스프레스의 기본에 대해 이해해 보자.

스캐폴딩(Scaffolding)

  • 프로젝트는 대개 템플릿 코드가 일정량 필요하다.
  • 프로젝트의 엉성한 뼈대(템플릿)를 만들어놓고,
    새 프로젝트를 시작할 때마다 이 템플릿을 복사하는 방법이 훨씬 간단하다.
  • 루비 온 레일즈(Ruby on Rails)에서는 자동으로 스캐폴딩을 생성하는 프로그램을 만들어
    이 개념을 한 단계 진화시켰다.

  • 익스프레스(Express)루비 온 레일즈(Ruby on Rails)의 아이디어를 받아들여,

  • 프로젝트를 시작할 때 스캐폴딩을 생성하는 유틸리티를 제공한다.

메도라크 여행사 웹사이트

  • 이 책 전체에서 사용하는 예제는 오리건 주를 찾아오는 사람을 대상을 서비스를 제공하는
    가상의 여행사 메도라크(들종다리)의 웹사이트이다. REST 서비스도 제공할 예정이다.

초기 단계

  • 프로젝트에 사용할 새 디렉터리를 만든다.

    • 이 디렉터리는 프로젝트의 루트 디렉터리이다.
  • 이 책에서 ‘프로젝트 디렉터리’, ‘앱 디렉터리’, ‘프로젝트 루트’라고 말하면
    그건 이 디렉터리를 가리키는 것이다.

Tip!
프로젝트를 진행하다 보면 회의록이나 문서 같은 파일이 생기게 마련인데,
이런 파일들과 웹 앱 파일을 분리해서 보관하자.
-> 서브디렉터리를 하나 만들어 프로젝트 루트로 지정하자.
예를 들어, 메도라크 여행사 웹사이트 프로젝트와 관련된 파일을 ~/projects/meadowlark 안에 두되,
프로젝트 루트(프로젝트 디렉터리)는 ~projects/meadowlark/site로 지정한다.

npm은 프로젝트 의존성과 메타데이터를 package.json 파일에 보관해서 관리한다.
이 파일을 만드는 가장 쉬운 방법은 npm init이다.
이 명령을 내리면, 몇 가지 질문을 거쳐 package.json 파일을 생성한다.
(진입점(entry point)을 묻는 질문에는 meadowlark.js 또는 프로젝트 이름을 쓰면 된다. )

Tip!

package.json에 저장소 URL을 지정하지 않거나 README.md 파일을 작성하지 않으면
npm을 실행할 때마다 경고가 나올 것임
사실 package.json 파일에 들어있는 메타데이터는 프로젝트를 npm 저장소에 올리지 않는다면 필요 없는 것이지만,
간단한 작업을 해서 경고를 없애는 것도 좋다.

익스프레스를 설치한다.

1
npm install --save express
  • npm install을 실행하면, 지정한 패키지를 node_modules 디렉터리에 설치한다.
  • –save 플래그를 지정하면 package.json 파일을 업데이트한다.
  • node_modules 디렉터리는 언제든 npm에서 다시 생성할 수 있으니 저장소에 저장할 필요가 없다.
  • 실수로 node_modules 디렉터리를 저장소에 추가하는 일이 없도록 다음과 같이 .gitignore 파일을 만들어 두자.
1
2
// .gitignore
node_modules;

meadowlark.js 파일을 만든다.

  • 이 파일이 프로젝트의 진입점
  • 이 책 전체에서 이 파일을 ‘앱 파일’이라고 부를 예정
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
const express = require("express");
const app = express();
app.set("port", process.env.PORT || 3000);

// 커스텀 404 페이지
app.use(function(req, res) {
res.type("text/plain");
res.status(404);
res.send("404 - Not Found");
});

// 커스텀 500 페이지
app.use(function(err, req, res, next) {
console.error(err.statck);
res.type("text/plain");
res.status(500);
res.send("500 - Server Error");
});

app.listen(app.get("port"), function() {
console.log(
"Express started on http://localhost:" +
app.get("port") +
";press Ctrl-C to terminate."
);
});
  • 기초적인 익스프레스 서버가 만들어졌다.
  • 터미널에 아래의 명령어를 입력하여 meadowlark.js로 서버를 시작해보자.
    http://localhost3000에 접속할 수 있다.
1
node meadowlark.js
  • 아직 익스프레스에 아무런 라우트(Route)도 지정하지 않았으므로
  • 페이지가 존재하지 않음을 나타내는 범용 404 페이지가 나타난다.

NOTE
애플리케이션 포트는 app.set(port, process.env.PORT || 3000)으로 지정했다.
이렇게 하면, 서버를 시작하기 전에 환경 값을 설정해 포트를 오버라이드 할 수 있다.
이 예제를 실행했을 때, 앱이 포트 3000에서 실행되지 않는다면,
PORT 환경 변수가 설정됐는지 체크해보자.

TIP
HTTP 요청의 상태 코드와 리다이렉션 여부를 보여주는 브라우저 플러그인을 설치하길 권한다.
이런 플러그인을 설치하면, 대개 간과할 수 있는
리다이렉션 문제부정확한 상태 코드를 찾아내기 쉽다.
크롬에서는 아이마(Ayima)의 Redirect Path가 좋다.
브라우저 대부분에서 개발자 도구의 네트워크 섹션에서 상태 코드를 볼 수 있다.

홈페이지어바웃 페이지 라우트를 추가해보자.

  • 다음과 같이 404 핸들러 앞에 새 라우트를 2개 추가한다.
1
2
3
4
5
6
7
8
9
10
11
12
// app.get 메서드: 라우트를 추가하는 메서드
// 이 메서드는 매개변수로 경로, 함수를 받는다.
app.get("/", function(req, res) {
res.type("text/plain");

// 노드의 저수준 메서드 res.end 대신 익스프레스의 확장 메서드 res.send를 사용함
res.send("Meadowlark Travel");
});
app.get("/about", function(req, res) {
res.type("text/plain");
res.send("About Meadowlark Travel");
});
  • 이제 다시 아래의 명령어를 입력하여 서버를 다시 시작하면,
    홈페이지와 어바웃 페이지가 정상적으로 작동한다.
1
node meadowlark.js

app.VERB: 라우트를 추가하는 메서드

  • 여기에서 VERB는 (소문자인) HTTP 동사(대개 ‘get’과 ‘post’)의 플레이스 홀더이다.
  • 이 메서드는 매개변수경로함수를 받는다.
    경로 매개변수라우트를 정의한다.
  • 기본적으로 대소문자를 구분하지 X
  • 맨 뒤의 슬래시(/)는 무시한다.
  • 매칭할 때는 쿼리스트링을 무시한 채 매칭한다.
    -> About 페이지의 라우트는 /about, /About(대소문자를 구분하지 않기 때문에),
    /about/(맨 뒤의 슬래시 무시),
    /about?foo=bar(쿼리스트링 무시),
    /about/?foo=bar(맨 뒤의 슬래시 무시, 쿼리스트링 무시)
    등에 대해 모두 작동한다.

함수 배개변수는 라우트가 일치할 때 호출되는 함수이다.
이 함수로 전달되는 매개변수는 요청/응답 객체이다.
지금은 평문(plaintext)로 상태 코드 200을 반환한다.
(익스프레스의 기본 상태 코드는 200이므로 명시하지 않아도 된다.)

노드의 저수준 메서드 res.end 대신 익스프레스의 확장 메서드 res.send를 사용함
노드의 res.writeHeadres.setres.status교체
익스프레스는 Content-Type 헤더를 설정하는 편리한 메서드 res.type을 제공한다.
물론 res.writeHead와 res.end를 써도 되지만 그럴 필요 X

커스덤 404500 페이지는 반드시 조금 다르게 처리해야 한다.
app.get 대신 app.use를 썼다.
app.use는 익스프레스에서 미들웨어(middleware)를 추가할 때 쓰는 메서드
일단은 지금은 라우트와 일치하지 않는 모든 것을 처리하는 폴백(catch-all) 핸들러라고 생각하자.
중요한 요점은 익스프레스에서는 라우트와 미들웨어를 추가하는 순서가 중요하다.

404핸들러를 라우트 앞에 두었다면, Home 페이지와 About 페이지는 동작하지 않고,
404 에러가 일어났을 것이다.
지금은 라우트 구조가 매우 단순하지만, 와일드 카드를 지원하므로 순서 문제가 생길 수 있다.
ex) About 페이지에 /about/contact나 /about/directions 같은 서브페이지를 추가한다면 어떻게 될까?
다음 코드는 원하는 대로 작동하지 않을 것이다.

1
2
3
4
5
6
7
8
9
app.get("/about*", function(req, res) {
// 콘텐츠를 전송하는 코드...
});
app.get("/about/contact", function(req, res) {
// 콘텐츠를 전송하는 코드...
});
app.get("/about/directions", function(req, res) {
// 콘텐츠를 전송하는 코드...
});
  • 위 예제에서는 첫 번째 핸들러 /about에서 와일드 카드를 썼으므로
    ‘/about/contact’‘/about/directions’ 핸들러는 절대 일치되는 일이 없다.

익스프레스콜백 함수가 받는 매개변수 숫자를 통해 404500 핸들러를 구별할 수 있다.