본문 바로가기

문돌이 존버/Node.js 스터디

npm, express, 미들웨어 기본 개념 이해하기

반응형
본 글은 스파르타 코딩 클럽의 "Node.js 심화반" 강의를 듣고 작성한 개발일지입니다.

npm(node pakcage manager)은 Node.js에서 오픈소스 라이브러리를 쉽게 사용하기 위해 개발된 "패키지 관리자"라는 형식의 프로그램입니다.

express라는 라이브러리는 쉽게 서버 프로그램을 구성할 수 있게 만들어진 "오픈소스 라이브러리"입니다. 이렇게 서버 프로그램을 빠르고 손쉽게 할 수 있는 이유는 미들웨어(Middleware) 구조 때문에 가능한 것입니다. 

미들웨어
- 클라이언트에게 요청이 오고 그 요청에 따른 응답을 하는 중간 과정에서 목적에 맞게 처리를 하는 거쳐가는 함수
- req(요청) 객체, res(응답) 객체, 어플리케이션 요청-응답 사이클 도중 그 다음의 미들웨어 함수에 대한 엑세스 권한을 갖는 함수
- 다음 미들웨어 함수에 대한 엑세스는 next 함수를 이용하여 순차적으로 처리

위에서 말하는 개념이 와닿지 않을 것입니다. 아래 그림을 보면 좀 더 이해가 될 것 같은데요.

<출처: 라봉이의 개발 블로그>

간단히 말해서 사용자가 특정 url path에 접속했을 때(=request) 어떤 응답을 해줄 것이냐, 어떤 처리를 해줄 것이냐를 미들웨어를 거쳐 수행한다는 것입니다. 간단하게 예를 들어 생각해보겠습니다.

A라는 사용자가 특정 웹 사이트에 가입하려고 합니다. 처음 들어온 페이지는 "회원가입"이고, 그 다음 페이지는 아마도(?) "로그인" 페이지가 될 것입니다. 이때 로그인 페이지는 다음 미들웨어가 되는 것이며 회원가입 미들웨어에서 next 함수를 통해 호출하게 됩니다.

코드를 살펴보면서 직관적으로 이해해보겠습니다.

app.use()app.METHOD() 함수를 통해 미들웨어를 사용할 수 있음 -> 어플리케이션 레벨 미들웨어
const express = require('express');
const app = express();

var myLogger = function (req, res, next) {
  console.log('LOGGED');
  next();
};

app.use(myLogger);

app.get('/', (req, res) => {
  res.send('Hello World!');
});

app.listen(3000);

위에서 console에 "LOGGED" 라는 메시지가 출력되고, "localhost:3000"에 접속하면 "Hello World!" 라는 본문이 나타납니다. 즉 app.use() 로 미들웨어를 사용하고 다음 미들웨어인 app.get() 은 myLogger라는 함수값 변수에서 next() 를 선언했기 때문에 실행한 것입니다.

만약 next() 를 선언하지 않는다면 다음 미들웨어인 app.get() 은 실행되지 않아 console에는 "LOGGED" 메시지가 출력되지만, 웹 사이트는 열리지 않습니다.

아래 예시 코드는 스파르타 코딩 클럽에서 제공한 뼈대 구조입니다. Router 객체를 사용하고 express.json() 을 통해 json 미들웨어를 사용했습니다.

const express = require('express');
const app = express();
const router = express.Router(); // Router 객체 생성

router.get('/', (req, res) => {
    res.send('Hi!');
});
app.use('/api', express.json(), router);

app.listen(8080, () => {
    console.log('서버가 커졌습니다!');
});
json 미들웨어: HTTP 요청을 받을 때 body에 있는 데이터를 정상적으로 사용할 수 있게 분석하는 역할 수행
                   JSON 형태의 body를 입력받음

Router 객체는 그 자체가 미들웨어(모듈식 미들웨어)처럼 움직이므로 app.use() 의 인자(argument)로 사용되고 반드시 마운트시켜야만 사용 가능합니다. 공식 홈페이지를 참고하자면 mountable하다고 표현했는데 이는 Router 객체에 커스터마이징한 기능을 연결해 API를 제공할 수 있다는 뜻으로 보입니다.

정리하자면 위 코드의 app.use('/api', express.json(), router) 로 되어 있는 부분에서 app.use() 에 마운트(한국어로 번역하면 "올라타다")하는 것이고, 이때 router 의 역할은 웹 페이지에 "Hi!"라는 메시지를 출력하게 하는 것이죠.

router을 사용하는 이유는 특정 root url을 기점으로 기능이나 로직별로 라우팅을 나눠서 관리할 수 있다는 것입니다. 사용자 관리, 게시글 관리 등 기능별로 구분해서 관리하는 것이 아무래도 편리하겠죠. 다만, 주의할 점이 있습니다. app.use() 에서 지정한 경로(path)가 같은 것이 들어오면 모두 적용하기 때문에 중복될 가능성이 있습니다.

예를 들어, app.use('/data', ...) 가 있다면, /data/posts, /data/users/images 등에도 모두 적용된다는 것입니다.

참조
https://velog.io/@wjddnjswjd12/node.js-express-%EB%AF%B8%EB%93%A4%EC%9B%A8%EC%96%B4%EB%9E%80
https://psyhm.tistory.com/8
728x90
반응형