Search
▪️

Working with Express.js

Express.js

Business Logic에 집중하고 싶지만, Incoming Request에 대해서 Body의 값을 Extracting 하는 반복되는 코드를 작성해야 하는 상황이라면 이를 타개할 방법이 있다. Express.js를 사용하는 것이다.
Express.js는 Thrid Party Package로 설치 가능한 프레임 워크이다. 유용한 Function들을 제공함으로써 반복되는 작업들의 더러운 코드들을 정리할 수 있게 도와준다.
Middleware들을 여럿 두면서 App이 처리해야 하는 Function들에 대해서 수행한다. (Express는 Middleware에 대한 의존도가 매우 높다.)
다른 Thrid Party Package들과의 호환성이 매우 뛰어나다. 이런 TPP들은 Middleware에 탑재하여 사용 가능하다.
** Middleware의 추가는 use() Method를 이용하면 가능하고, 이런 Middleware들은 Request와 Response에 대해서 처리하고 next()를 호출함으로써 (즉, In-line으로 처리한다.) 그 다음 Middleware에 대한 수행할 수 있게 한다.

Installing Express.js

1.
Production Dependencies로 설치한다.
2.
express() Method를 통해 Express Application을 생성하여 변수에 할당한다.
3.
express()를 할당한 변수가 갖는 use() Method의 인자인 Request Handler를 작성한다.
4.
express()를 할당한 변수를 createServer()의 인자로 준다.
** 3, 4번의 경우에는 Express에 정의된 함수인 listen()을 이용하면 자동으로 처리한다.

Adding Middleware

All About Middleware
1.
Request
2.
Middleware...
3.
Response
** 2에서 여러 Middleware 진행 시, next()를 이용한다.
** 3 → 4 진행 시 res.send()를 이용한다.
Incoming Request가 들어오면 Express.js를 이용하여 자동으로 여러 Function들을 통과 시키게 되는데, Express.js를 이용하기 전처럼 하나의 Request Handler를 두는 것이 아니라 실제로 Request가 Multiple Function을 거쳐 Response를 전달할 수 있도록 한다. 이것이 Middleware이다. 이렇게 하면, 코드를 Multiple Block처럼 조각내어 이용할 수 있다.
use() Method는 request, response, next 세 가지의 인자를 받는다.
next() Method를 통해서 여러 Function을 거치는 것이 가능해진다. (다른 Middleware를 Travel을 가능하게 한다.)
next() 호출을 해주지 않으면 원하는 Response없이 Request가 죽어버릴 수 있다.
Response를 해줘야하는 부분은 nex()가 아닌 Response를 반환 해주고 끝내야한다. 이 때, Express.js를 쓰기 전처럼 setHeader(), write()와 같은 작업들은 해주지 않고 send() Method를 부르기만 하면 된다. (이전처럼 수동으로 작성해도 무방하지만, 따로 안 해줘도 된다. Default가 text/html이다.)
별도의 작업이 없다면 위에서 아래로 next() 처리를 하게 된다.

Express.js - Looking Behind the Scenes

Express.js의 Github에서 response.js 파일을 살펴보면 response.send() 관련 Method들을 확인할 수 있다. 내부를 살펴보면 chunk라는 변수가 있는데 이 변수는 Response로 받은 인자인 body를 담고 있다. 코드를 살펴보면 chunk의 타입에 따라서 Content-Type을 정하든가 다른 Logice들을 수행하게 된다.
createServer()에 app을 인자로 넣는 것이 아닌, app.listen()을 통해서 서버를 구동할 수도 있다. 이미 Express.js의 listen() Method에는 createServer()가 되어 있다.

Handling Different Routes

Express.js의 use() Method를 살펴보면 함수의 원형을 살펴볼 수 있는데, 함수의 원형에는 Path라는 인자를 설정할 수 있으며, 별도의 설정이 없으면 Default로 '/'로 인식시킨다.
Routing 시에 주어지는 Path에 대해서 입력한 Link가 Routing의 Pattern과 매치 되는 것 먼저 실행이 되기 때문에, Root Path는 최대한 아래에 쓰는 것이 좋다. (포함 관계 파악 필수!) ⇒ 물론 next()에 대한 호출이 있다면 다르게 쓸 수도 있다.

Parsing Incoming Requests

Request의 Body에 담겨 있는 내용들을 보기 위해서, request.body를 찍고 conosle로 출력해 보면 undefined가 뜨게 된다. 이는 Request의 Body를 별도로 Parsing해주지 않았기 때문이다.
따라서 별도의 Parser가 필요하다.
body-parser라는 Third Party Package를 사용하도록 한다.
bodyParser로 import가 끝났다면, bodyParser.urlencoded({extended: false} )를 app.use() Method로 호출한다.
이 Parser는 모든 Body에 대해서 Parsing을 수행하는 것이 아니라, Form을 통해서 넘겨 받은 Body에 대해서만 Parsing하게 된다. (File과 같은 Body를 Parsing해야한다면 다른 Package를 사용해야 한다.)
** app.use() Method 대신에 app.post(), app.get() 등의 Method를 쓸 수있다.

Using Express Router

express의 Router()라는 Method는 일종의 Mini Express App이다. 즉, 다른 Express App에 종속시키거나 가져다 붙일 수 있다.
Router() Method를 통해 여러 Express App으로 나눴다면, 작은 Express App들을 Export하고, app.js와 같이 최상위의 Script에는 import 후 app.use($importName)으로 이용한다.
get()과 post()와 같은 Call Method는 Route Pattern이 정확히 일치해야 수행된다. 즉, 이와 같은 Method 이용 시에는 순서가 바뀌어도 정상 작동을 하게 된다. 이것이 use() 대신에 get(), post()을 써야하야하는 중요한 이유이다.

Adding a 404 Error Page

response.send() Method 앞에는 Chaining으로 response.setHeader()나 response.status()같은 Method를 이어 붙일 수 있다.
404 Error를 내보내면서 response를 send()하려고 할 때, response.status(404)와 같이 처리하는 것이 일반적이다.

Filtering Paths

HTTP Request Method만 다르고 Path는 동일 할 수도 있다. 이 때 만일 Path에 대한 처리를 Router로 해두었다면, 해당 Router의 Filtering Path를 App에 줄 수 있다.
** router.get('/add-product', ...)와 같고 app.use('/admin', adminRoutes)와 같이 말이다.
즉, app.use()에서 기재한 Path에 대해서는 Exact Path로 Routing을 하는 것이 아닌 First-Hit에 대해서 Routing하는 것이므로 app.use()에는 Filtering할 Path를 주어지고 해당 Path에 대해서 Routing을 수행할express.Router의 Module을 추가 인자로 주어 Routing을 용이하게 할 수 있다.

Serving HTML Pages

작성한 HTML 파일들을, 작성했던 JavaScipt 파일들에게 Serve하고 싶다면 Response를 활용하면 된다. (단, 이전처럼 HTML Code를 전송하기 위해서 썼던 send() Method가 아니라 sendFile() Method를 이용한다.)
이 때, sendFile()에 인자로 넘겨주는 Path가 중요하다! 절대 경로를 주어야한다. 일반적으로 사용되는 프로젝트의 Root경로인 '/' 역시도 상대 경로일 뿐이다. 그렇다면 Root 경로인 '/'부터 시작하는 상대 경로를 절대 경로로 바꾸기 위해서 앞에 붙어야하는 경로를 구해야하는데, 이 때 Node.js의 'path' Core Module을 이용하면 쉽게 구할 수 있다.
상대 경로를 절대 경로로 바꾸기 위해 이용하는 것은 path.join()이라는 Concatenating Method이다. 또한 해당 Method의 인자로 주는 것은 __dirname이라는 Node.js에 의해 생성된 Global Variable이다. __dirname은 path.join() Method를 호출한 프로젝트 디렉토리까지의 운영체제에서 사용되는 절대 경로를 쥐고 있다.
** path.join(__dirname, "..", "views", "shop.html");와 같이 이용한다. 보다 싶이 '/' 기호는 이용하지 않으며, '..'는 상위 디렉토리를 의미한다.
** '/' 구분자를 이용하지 않는 이유는 운영체제 마다 디렉토리 구분자가 다르기 때문이다.
위와 같이 현재 위치인 __dirname을 써서 '../' 와 같이 탐색하는 것 보다는 Root Path를 얻을 수 있는 Helper Function을 두는 것이 더 보편적으로 쓰인다.
** path.dirname(process.mainModule.filname); 을 통해 현재 프로젝트가 구동 중인 Main Module인 app.js 라는 파일 이름 까지의 디렉토리에 대한Path를 제공한다. → 즉, 프로젝트의 Root Path를 절대경로로 제공한다.

Serving Files Statically

URL을 통해서 특정 서버로 접속할 때는 Express를 이용하기 때문에, Express에 등록 되지 않은 Routes는 Access가 불가능하다. 즉, 구동되고 있는 프로젝트의 FIle에 접근하려고 Path를 URL로 주고 접속 시 접근이 불가능하다는 것을 알 수 있다. (URL로는 File System에 접근이 기본적으로는 불가능하다.) 여기서 HTML 파일을 Styling한 CSS 파일을 보통 따로 빼내어 정리하는데, 이 CSS 파일에 접근하기 위해서는 File을 읽어야하므로 별도의 작업이 필요하다.
프로젝트를 구동 시키는 app.js에서 Middleware를 추가하여 static으로 사용할 디렉토리에 대해서 명시해야 한다.
** app.use(express.static(path.join(__dirname, "public")));와 같이 이용한다.
** static() Method도 여러 개를 둘 수 있다. 하지만 Routing과 마찬가지로 가장 먼저 Hit 되는 것으로 처리하므로 이에 유의하여 이용해야 한다.
이와 같이 static하게 접근할 수 있는 권한을 주면, 이는 Read에 대한 권한만 주어지게 된다.