본문 바로가기

Node.js

[Web Server] Express

개요

-Node.js의 프레임워크인 Express를 이용하여 이전에 node.js로 작성한 서버를 리팩토링한다.

-Express는 Node.js 환경에서 웹 서버 및 API를 조금 더 편리하게 구축하기 위해서 사용된다.

-Express의 핵심 기능은 MiddleWare와 Router이다.

 

 

1. Express 

-Basic structure (https://expressjs.com/en/starter/hello-world.html)

const express = require('express');
const app = express();
// express의 인스턴스인 app은 서버를 시작하고 포트 3000번을 연결한다. 

const port = 3000;

app.get('/', (req, res) => {
// 루트(root) URL( / ) 혹은  루트 라우트(route)에 대한 요청에 "Hello World!"로 응답한다.
// 이때 다른 모든 경로(path)에 대한 요청에는 404 Not Found로 응답한다.
  res.send('Hello World!');
});

app.listen(port, () => {
  console.log(`http server listen on localhost:${port}`);
});

 

-MiddleWare Function (http://expressjs.com/en/guide/writing-middleware.html)

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

const myLogger = function (req, res, next) {
  console.log('LOGGED');
  next(); // 반드시 요청-응답 사이클을 끝내거나 next를 호출해야한다.
};
// express 내에서 작성하는 일반적인 함수를 일컫는 말이다.
// 미들웨어의 역할은 다음과 같다 : 1.코드를 실행함 / 2.req&res 객체를 조작함 / 3. 요청-응답 사이클을 끝냄 / 4. 다음 미들웨어를 호출함
// 미들웨어는 인자로 request 객체, response 객체 그리고 next middleware function을 받는다.
// 이때 next middleware function은 말그대로 뒤이어서 실행되는 미들웨어를 말한다. (제어(control)를 넘긴다라는 표현을 사용한다)
// 이 미들웨어 함수의 이름은 일반적으로 next라 부른다.
// 미들웨어는 라우트의 콜백함수로 사용하며 비동기적인 http 통신 작업을 수행한다.

app.use(myLogger);
// 미들웨어 함수는 use()를 사용하여 로드한다.
// 모든 경로에 대해서 HTTP 요청을 받으면 작성된 순서대로 실행된다. (This shows a middleware function with no mount path. The function is executed every time the app receives a request.)

app.use('/user', myLogger);
// myLogger를 /user 경로에 마운트한다. 이 경로에 대한 모든 유형의 HTTP 요청에 의해 실행된다.

app.get('/user/:id', (req, res, next) => {
  if (req.params.id === '0') next('route');
// 만약 user ID가 0 이라면, 다음 route로 넘어간다.
// next('route')와 같이 next()에 인자를 전달하는 형태는 app.METHOD()이나 router.METHOD()내에서 미들웨어가 로드될 때만 적용된다.
  else next();
// 아니라면 현재 라우트 스택의 다음 middleware로 넘어간다.
}, (req, res, next) => {
  res.send('regular');
});

app.get('/user/:id', (req, res, next) => {
// 위에서 user ID가 0 일때 실행되는 라우트이다.
  res.send('special');
})

-Routing(분기) (https://expressjs.com/en/guide/routing.html)

// *** app.METHOD(PATH, HANDLER) ***
// HTTP 메소드에 대응하는 Express app 객체의 메소드는 지정된 request를 'listen(수신)'하며 
// 요청을 감지하면 handler function을 콜백한다.
// 여러 요청들에 대해서 각자에 맞는 응답을 지정해준다고 생각하면 쉽다.

// *** Route Paths
// Route : Part of a URL that identifies a resource. 
// 리소스의 endpoints를 지정한다.
// 경로는 문자열 혹은 정규표현식으로 작성한다. (기호 등 특수문자 삽입은 공식문서 참고)

app.get('/', (req, res) => {
// root(/) 경로의 'GET' Request를 처리한다.
  res.send('Hello World!');
});
app.put('/user', (req, res) => {
// /user 경로의 'POST' Request를 처리한다.
  res.send('My name is Withlaw');
});

// 다음 /book 경로에 대한 여러 HTTP 메소드 요청을 아래와 같이 chaining을 통해 한꺼번에 처리 할 수 있다.
// route module은 중복과 오타를 감소시여 코드를 효율적으로 관리 할 수 있게 한다.
app.route('/book')
  .get((req, res) => {
    res.send('~');
  })
  .post((req, res) => {
    res.send('~')
  })
  .put((req, res) => {
    res.send('~')
  });
  
  // 어느 특정 경로에 대한 모든 HTTP 요청을 다음과 같이 처리 할 수도 있다.
  app.all('/~', fn);
  
  // or
  app.use('/',['/user', '/book'], fn); // path 생략 가능

Route Handlers (middleware system)

// 라우팅 메소드는 하나 이상의 콜백함수를 인자로 받는다. 
// 만일 여러 콜백함수를 사용할 경우 각 콜백함수에 next를 추가로 전달하고 함수 내부에서 next()를 호출하여 
// 다음 콜백함수에게 바톤을 넘긴다.

app.get('/', (req, res, next) => {
  ...
  next();
}, (req, res) => {
  res.send('~');
});
// 일련의 여러 미들웨어로 구성된 것을 stack이라 부른다.


// 배열로 인자를 받는 경우
const cb0 = function (req, res, next) {
  ...
  next();
};
const cb1 = function (req, res, next) {
  ...
  next();
};
const cb2 = function (req, res) {
  res.send('Hello from C!')
};
app.get('/', [cb0, cb1, cb2]);

// 둘을 동시에 사용하는 경우
app.get('/', [cb0, cb1], (req, res, next) => {
  ...
  next();
}, (req, res) => {
  res.send('~');
});

*Request Methods

// 1. request.query
// query string은 흔히 리소스의 어떤 데이터를 고유하지 않은 정보를 이용하여 검색(필터링)할 때 사용한다.
// 다음 요청에 대해 request.query는 쿼리 데이터 객체를 반환한다.
// 'GET: http://localhost:3001/flight?departure=CJU&destination=ICN' 
request.query;
{
  departure: "CJU",
  destination: "ICN",
}


// 2. request.params
// path parameter는 리소스의 어떤 데이터를 고유한 정보를 이용하여 검색할 때 사용한다.
router.get('/flight/:uuid', findById); 
// 서버에서 위와 같이 ~path/:[parameter] 형식으로 어떤 값에 대해 매개변수를 지정하고 라우팅한 후,
// 아래와 같은 요청 메시지를 받으면 파라미터 데이터 객체를 반환한다.
// 'GET: http://localhost:3001/flight/a55c-da65-47dd-af23-578'
request.params;
{
  uuid: "a55c-da65-47dd-af23-578",
}

 

*Response Methods


Router module

const express = require('express');
const router = express.Router();
// express.Router 클래스를 통해 모듈처럼 장착(mount)할 수 있는 새로운 router 인스턴스를 생성할 수 있다.
// router 혹은 route module이라 부르며, 라우팅 및 미들웨어 기능만 수행하는 mini-app 같은 것이다.

router.get('/', (req, res) => {
  res.send('Birds home page');
});
router.get('/about', (req, res) => {
  res.send('About birds');
});
module.exports = router;


// birds.js 라는 이름으로 파일을 저장한 후
// 다른 파일에서 위에서 작성한 라우터를 다른 경로에 라우팅 시킬 수 있다.
const birds = require('./birds');
...
app.use('/birds', birds);

 

2. Refactoring by using Express 

(https://sanxang.tistory.com/68)

const express = require("express");
const cors = require("cors");
const bodyParser = require("body-parser");
// cors와 bodyParser는 third-party 미들웨어로 Node.js에서 모듈을 설치한 후에 사용할 수 있다.
// $ npm i cors bodyParser

//init
const PORT = 4999;
const ip = "localhost";
const app = express();

//Middle Ware
const jsonParser = bodyParser.json({ strict: false });

//Routing
app.use(cors(), jsonParser);
/*
app.options("/upper", (req, res) => {
  res.send("<h2>Welcome coedestates</h2>");
});
*/
app.get("/", (req, res) => {
  res.send("<h1>Welcome coedestates</h1>");
});
app.post("/upper", (req, res) => {
  // res.send(JSON.stringify(req.body.toUpperCase()));
  res.json(req.body.toUpperCase());
});
app.post("/lower", (req, res) => {
  res.json(req.body.toLowerCase());
});

app.listen(PORT, ip, () => {
  console.log(`http server listen on ${ip}:${PORT}`);
});

*Third-party middleware

(https://expressjs.com/en/resources/middleware.html)

  1) body-parser 

  -POST 요청 등에 포함된 body(payload)를 쉽게 얻을 수 있다. (이전에는 네트워크 상의 chunk를 Buffer로 합치고 문자열로 변환하는 복잡한 작업을 필요로 했음)

  -요청 메시지의 Content-Type 헤더와 body-parser모듈의 type option이 일치할 때만 req.body 프로퍼티 값이 반환된다.

  -만약 서로 다르거나, 파싱할 본문 데이터가 아예 없거나, 중간에 에러가 발생하면 req.body 프로퍼티에 빈 객체가 반환된다.

  - *bodyParser.json([options]) : [options] 조건에 맞는 json 데이터만 파싱하여 반환한다. 기본적으로 배열이나 객체 값만 파싱하는데, { strict: false } 옵션 설정을 통해 모든 타입의 데이터를 파싱할 수 있다.

  -최근에는 Express 내장 미들웨어인 express.json()을 사용한다. 작성과 사용 방법은 동일하다.

  2) CORS 

  -어떤 요청에 대해 CORS 허용을 알아서 응답 처리해주는 미들웨어이다.

  -특정 오리진이나 메소드에 대한 설정 방법은 다음 공식 문서를 읽어 볼 것 

  (http://expressjs.com/en/resources/middleware/cors.html)

 

*API reference

-express, router, req & res 등에 관한 다른 여러 프로퍼티와 메소드에 대한 설명은 다음 공식 문서를 읽어 볼 것

(https://expressjs.com/ko/4x/api.html)

*용어집

(https://expressjs.com/en/resources/glossary.html)

 

 

3. StateAirline Server 과제

-파일 구조 및 API 분석

 

 

 

 

'Node.js' 카테고리의 다른 글

Module System  (0) 2022.09.13
[Web Server] CORS  (0) 2022.08.14
-Node.js-  (0) 2022.08.14
[Web Server] HTTP Transaction  (0) 2022.08.11