Codesigner

[Express] Express 에서 미들웨어란? 본문

Nodejs/Express

[Express] Express 에서 미들웨어란?

eunsukimme 2019. 6. 15. 01:05

코드의 품질을 향상시키는 방법으로는 여러가지가 있다. 변수 명명을 해당 변수의 기능과 연관되게 짓는 것은 코드의 가독성을 향상시킨다. 또한 코드의 중복을 피하는 것도 코드의 품질을 향상시키는 또 다른 방법이다. 사실, 코드의 중복은 버그를 우리 프로그램으로 초대하는 초대장이다. 부정확한(충분히 검증되지 않은) 코드가 복사-붙여넣기 되는 것은 개발자가 코드를 수정하는데 있어서도 많은 작업이 요구되고, 또 모든 코드를 수정하지 못 할 우려도 존재한다. 이번 포스팅에서는 이러한 중복과 복잡성을 줄일 수 있는 몇 가지 방법에 대해서 알아보도록 하자. 일반적인 프로그래밍에서, 재사용 되는 코드는 재사용가능한 컨테이너(함수 또는 객체)를 따로 만들어서 그 안에서 작성한다. Express 에서는 이를 일련의 미들웨어로 구성한다

 

 

 

함수로 코드의 중복 피하기(DRYing Code With Function)

좋은 코드란 프로그래밍 언어의 장점을 활용해서 동일한 작업의 수행을 피하는 것이다. 다음 코드를 보자

const addFive = number => {
  const fiveAdded = number + 5;
  console.log(`Your number plus 5 is ${fiveAdded}`);
}

const addTen = number => {
  const tenAdded = number + 10;
  console.log(`Your number plus 10 is ${tenAdded}`);
}

const addTwenty = number => {
  const twentyAdded = number + 20;
  console.log(`Your number plus 20 is ${twentyAdded}`);
}

위 코드는 세 가지 서로 다른 함수를 정의하고 있다. 파라미터로 주어진 수에 각각 5, 10, 15를 더하고 로그를 남기고 있다. 위 코드는 아주 완전 정확하게 중복된 것은 아니지만, 조금의 융통성을 더한다면 위 코드는 다음과 같이 아주 유연하게 작성할 수 있다

const addNumber = (number, addend) => {
  const numAdded = number + addend;
  console.log(`Your number plus ${addend} is ${numAdded}`);
}

보시다시피 하나의 파라미터를 더 추가함으로써, 우린 두 개의 함수를 작성할 시간을 절약할 수 있게 되었다. 여러 곳에 같은 작업을 하는 코드가 반복적으로 나타나는 것을 두고만 있지 말라는 신조를 DRY(Don't Repeat Yourself) 라고 한다. 만약 프로그래머가 비슷한 기능을 하는 코드를 작성하고도 리팩토링 하지 않는다면, 이를 두고 "violate DRY" 라고 말한다. "Violate DRY"는 코드가 중복되고 있는 걸 의미하면서도 동시에 보다 적은 코드로 똑같은 기능을 수행할 수 있음을 의미한다. 그러면서 재사용가능한 함수를 작성하는 것을 요구하는 것이다

 

 

 

미들웨어(middleware)

Express 에서는 DRY를 어떻게 달성할 수 있을까? 바로 미들웨어(middleware)를 작성함으로써 가능하다. 미들웨어는 서버가 요청을 받아들이는 것과 응답을 전송하는 것 사이에서 작동하는 코드를 말한다. 즉, 두 HTTP 패킷 전송 사이에 일어나는 일들을 수행한다. Express 에서 미들웨어는 함수이다. 미들웨어는 들어온 요청을 검사하거나, 어떠한 로직을 실행하거나, 추가적인 정보를 응답에 붙이고 상태 코드를 수정한 후 유저에게 전달하거나, 또는 단순히 다른 미들웨어로 요청 및 응답을 전송하는 등 요청과 응답 객체를 갖고 여러 기능들을 수행할 수 있다. 자바스크립트 함수가 구현할 수 있는 모든 기능을 미들웨어 안에서도 구현할 수 있다. 다음 코드를 보자

app.use((req, res, next) => {
  console.log('Request received');
});

위 코드는 미들웨어의 한 예시이다. app.use() 는 콜백 함수를 파라미터로 취하고, 이는 모든 요청이 들어올 때마다 실행된다. 위 예시에서 서버는 요청을 받을때마다 처음으로 등록된 미들웨어 함수를 찾아 호출한다. 위 경우엔 단순히 "Request received"를 출력한다

그런데 미들웨어가 낯선 독자들에겐 한 가지 궁금한 것이 생길 수 있다. 우리가 만들고자 하는 어플리케이션이 미들웨어와 무슨 상관이 있는건데? 라는 것이다. 그에 대한 답변은 간단하다. Express의 공식 문서에 의하면, 다음과 같이 설명하고 있다

 

An Express application is essentially a series of middleware function calls

 

우리가 Express를 활용하는 것이 바로 미들웨어를 활용하는 것이란 뜻이다. 웹 서버 상에서 분리된 엔드포인트 상으로 적절하게 데이터를 라우팅 하는 것 뿐만 아니라 필요한 미들웨어를 작성함으로써 우리가 수행하고자 하는 어플리케이션 로직을 정확하게 수행할 수 있는 것이다

 

 

 

미들웨어 흐름제어: next()

미들웨어는 라우트와 마찬가지로 코드상에서 나타나는 순서대로 실행된다. 중요한것은 이게 메서드와는 관련이 없다는 것이다. app.get() 뒤에 나타나는 app.use()app.get()이 호출된 뒤에 실행된다. 다음 코드를 보자

const express = require('express');
const app = express();
const PORT = 4001;

app.use((req, res, next) => {
  console.log("A sorcerer approaches!");
  next();
});

app.get('/magic/:spellname', (req, res, next) => {
  console.log("The sorcerer is casting a spell!");
  next();
});

app.get('/magic/:spellname', (req, res, next) => {
  console.log(`The sorcerer has cast ${req.params.spellname}`);
  res.status(200).send();
});

app.get('/magic/:spellname', (req, res, next) => {
  console.log("The sorcerer is leaving!");
});

app.listen(PORT, () => console.log(`Server is listening on port ${PORT}`) );

// Accessing http://localhost:4001/magic/fireball 
// 출력:
// "A sorcerer approaches!"
// "The sorcerer is casting a spell!"
// "The sorcerer has cast fireball"

위 코드에서 라우트는 각각이 코드상에서 나타나는 순서대로 호출되었고, 이전 라우트의 next()에 의해서 다음 미들웨어로 컨트롤이 넘어가게 되었다. 여기서 마지막 app.get()은 호출되지 않았음을 확인할 수 있는데, 이는 이전의 라우트에서 next()를 호출하지 않았기 때문이다. Express에서 미들웨어는 (req, res, next) 세 가지 파라미터를 취하는 함수이다. 세 번째 파라미터인 next 는 미들웨어의 마지막에서 명시적으로 호출해주어야 다음 미들웨어로 요청과 응답을 핸들링 할 수 있는 컨트롤을 전송할 수 있다

 

그런데 눈치 빠른 독자라면 이쯤되면 미들웨어가 우리가 Express 서버에서 라우트 해줄때와 매우 유사하단 것을 인지했을 것이다. 그렇다! 사실 라우트는 미들웨어다!(두둥!). Express 서버의 모든 라우트는 미들웨어로, 요청과 응답 객체를 핸들링한다. 처음부터 라우트가 미들웨어라는 것을 말해주지 않은 이유는 그러한 의구심을 품고 계속 글을 읽게 만들기 위함이였으니, 이제 와서 설명한 것을 너그러이 이해하길 바란다

 

 

 

Review

지금까지 코드의 중복을 피하고 코드의 품질을 향상시킬 수 있는 방법은 무엇이고, 이를 Express 에서 달성하기 위해선 미들웨어를 활용해야 한다는 것을 배웠다. 아직 미들웨어를 활용해서 코드의 품질을 향상시키는 예시를 들진 않았지만, 일련의 미들웨어의 연속이 Express 의 전부라는 사실은 변함이 없다. 다음 포스팅에서는 미들웨어를 활용해서 코드의 품질을 향상시키는 방법에 대해서 알아보도록 하자

 

 

Comments