Medium - Using Express Middleware

원문 - John Au-Yeung

Trend 파악을 위한 Medium 기고문 포스팅 - 익스프레스 미들웨어 사용하기; 어떻게 라우트 레벨 미들웨어와 앱을 사용하는지 알아볼겁니다.

Photo by Connor Dugan on Unsplash

미들웨어 함수들은 리퀘스트 객체 (req), 리스폰스 객체 (res), 리퀘스트-리스폰스 사이클에 있는 그 다음 미들웨어 함수로 접근할 수 있습니다. - Express Docs

여기서 우리는 익스프레스 미들웨어 함수들이 어떤 것인지, 우리가 그걸 갖고 뭘 할 수 있는지 알아보겠습니다.

Characteristics of Middleware

미들웨어 함수는 아무 코드로나 동작하며 리퀘스트와 리스폰스 객체를 변화시키고 리퀘스트-리스폰스 사이클을 끝내고 스택에 있는 다음 미들웨어를 호출합니다.

Application-Level Middleware

미들웨어 함수는 모든 라우트에서 app.use 메소드를 콜백으로 넘기면 사용가능합니다. 만약 미들웨어 함수를 메소드 요청이 왔을 때만 호출하고 싶다면 메소드 app.METHOD로 메소드를 콜백으로 전달하면 됩니다. 여기서 METHODget, post, put, delete 등입니다.

예를들어 미들웨어 함수를 작성하고 app.use에 전달해서 리퀘스트의 요청이 올 때마다 로그를 남기게 할 수 있습니다.

const express = require('express')
const app = express()
app.use(express.json())
app.use(express.urlencoded({ extended: true}))

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

app.get('/', (req, res) => {
  res.json();
  })
app.listen(3000, () => console.log('server started'));

위와 같이 작성하면 /경로로 GET 리퀘스트를 날릴 때마다 GET이 로깅될 겁니다. 미들웨어 함수를 /경로의 GET 리퀘스트에만 동작하도록 제한할 수 있습니다.

const rexpress = require('express')
const app = express()
app.use(express.json())
app.use(express.urlencoded({ extended: true }))

app.get('/', (req, res, next) => {
  console.log(req.method);
  next();
  });

app.get('/', (req, res) => {
  res.json();
  })

app.post('/', (req, res) => {
  res.json();
  })

app.listen(3000, () => console.log('server started'));

이렇게하면 /경로로 GET 리퀘스트를 날릴 때만 로깅이 된다는 것을 알 수 있습니다.

Running a Series of Middleware Functions

next메소드를 사용하면 연속적으로 다음 미들웨어 함수를 호출할 수 있기 때문에 여러개의 미들웨어 함수들을 함께 사용할 수 있습니다. 예를 들면 다음과 같습니다.

const express = require('express')
const app = express()
app.use(express.json())
app.use(express.urlencoded({ extended: true }))

app.use(
  (req, res, next) => {
    console.log('middleware 1 called');
    next();
  },
  (req, res, next) => {
    console.log('middleware 2 called');
    next();
  }
  );

app.get('/', (req, res) => {
  res.json();
  })

app.listen(3000, () => console.log('server started'));

그러면 각 미들웨어들이 console.log를 실행한 것을 볼 수 있습니다.

middleware 1 called
middleware 2 called

만약 미들웨어에서 리스폰스를 보내면 next는 호출되지 않을 것입니다. 예를 들어보겠습니다.

const express = require('express')
const app = express()
app.use(express.json())
app.use(express.urlencoded({ extended: true}))
app.get('/',
  (req, res, next) => {
    next()
    },
    (req, res, next) => {
      res.send('Second middleware');
    }
  )
app.get('/', (req, res, next) => {
  res.end();
  })
app.listen(3000, () => console.log('server started'));

이렇게 하면 / 경로로 리퀘스트를 날리면 Second middleware 로그가 찍히게 됩니다. 라우트 핸들러에 있는 아래의 코드는 호출되지 않죠.

app.get('/', function (req, res, next) => {
  res.end();
  })

미들웨어 함수 다음에 next('route')를 이용해서 우리의 라우트핸들러로 바로 향하도록 할 수도 있습니다.

const express = require('express')
const app = express()
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.get('/:id',
  (req, res, next) => {
    if (req.params._id === '0') {
      next('route');
      return
    }
    next()''
  },
  (req, res, next) =? {
    res.send('Second middleware')''
    }
  )
app.get('/:id', (req, res, next) => {
  res.end(req.params.id);
  })

app.listen(3000, () => console.log('server started'));

/0경로로 리퀘스트를 날리면 0이 출력됩니다. 다른 경로를 사용한다면 Second Middleware가 출력될겁니다.

Router-Level Middleware

라우터 레벨 미들웨어는 app 레벨 미들웨어와 같은 방식으로 동작하지만 express 인스턴스가 아닌 express.Router() 인스턴스에 바인딩됩니다. 따라서 다음과 같이 사용할 수 있습니다.

const express = require('express')
const app = express()
const router = express.Router();

app.use(epxress.json())
app.use(express.urlencoded({ extended: true }))

router.use((req, res, next) => {
  req.requestTime = new Date();
  next();
})

router.get('/', (req, res, next) => {
  res.json(req.requestTime);
})

app.use('/', router);

app.listen(3000, () => console.log('server started'))  

/경로로 리퀘스트를 날리면 타임스탬프가 찍혀서 돌아올겁니다. 미들웨어를 연결하거나 라우트를 스킵하는 것 역시 app레벨과 동일하게 동작합니다. 미들웨어 체인은 다음과 같이 작성할 수 있습니다.

const express = require('express')
const app = express()
const router = express.Router();

app.use(express.json())
app.use(express.urlencoded({ extended: true }))

router.use(
  (req, res, next) => {
    console.log(',iddleware 1 called');
    next();
  },
  (req, res, next) => {
    console.log('middleware 2 called');
    next();
  }
)

router.get('/', (req, res, next) => {
  res.json();
})

app.use('/', router);
app.listen(3000, () => console.log('server started'));

이렇게하면 각 라우트 미들웨어의 결과물들이 콘솔로그 출력물로 보일겁니다.

middleware 1 called
middleware 2 called

next('route')를 이영해서 라우트로 바로 스킵할 수 있습니다.

const express = require('express')
const app = express()
const router = express.Router();

app.use(express.json())
app.use(express.urlencoded({ extended: true }))

router.get('/:id',
  (req, res, next) => {
    if (req.params.id === '0') {
      next('route');
      return;
    }
    next();
  },
  (req, res, next) => {
    res.send('Second middleware');
  }
)

router.get('/:id', (req, res, next) => {
  res.end(req.params.id);
})

app.use('/', router);

app.listen(3000, () => console.log('server started'));

/0경로로 리퀘스트를 날리면 0이 나올겁니다. 그 외의 경로는 Second Middleware가 출력될겁니다.

Conclusion

익스프레스 미들웨어를 사용하는 것은 간단합니다. app.use를 이용해서 미들웨어가 모든 리퀘스트 메소드에 동작하도록 하거나 app.METHOD에 전달해서 특정 메소드에만 동작하도록 할 수 있습니다.

next를 호출해서 다음 미들웨어를 실행시킬 수 있으며 next('route')를 호출해서 다른 미들웨어를 건너뛰고 바로 라우트 핸들러로 이동할 수도 있습니다.

라우트와 앱레벨 미들웨어는 거의 비슷하지만 express.Router(), express()처럼 어떤 인스턴스에 바인딩 되느냐 하는 것이 다를 뿐입니다.

Summary

  • app 레벨 미들웨어와 라우트 미들웨어의 차이
  • 거의 동일하지만 바인딩 되는 인스턴스가 차이가 있다
  • next를 이용해서 다음 미들웨어를 실행시킬 수 있으며 next 메소드의 매개변수로 라우터를 입력해서 다른 미들웨어를 건너뛸 수 있다.

© 2019. All rights reserved.

Powered by Hydejack v8.1.1