Medium - Using Express Middleware
in Trend
Trend 파악을 위한 Medium 기고문 포스팅 - 익스프레스 미들웨어 사용하기; 어떻게 라우트 레벨 미들웨어와 앱을 사용하는지 알아볼겁니다.
Photo by Connor Dugan on Unsplash
미들웨어 함수들은 리퀘스트 객체 (req), 리스폰스 객체 (res), 리퀘스트-리스폰스 사이클에 있는 그 다음 미들웨어 함수로 접근할 수 있습니다. - Express Docs
여기서 우리는 익스프레스 미들웨어 함수들이 어떤 것인지, 우리가 그걸 갖고 뭘 할 수 있는지 알아보겠습니다.
Characteristics of Middleware
미들웨어 함수는 아무 코드로나 동작하며 리퀘스트와 리스폰스 객체를 변화시키고 리퀘스트-리스폰스 사이클을 끝내고 스택에 있는 다음 미들웨어를 호출합니다.
Application-Level Middleware
미들웨어 함수는 모든 라우트에서 app.use
메소드를 콜백으로 넘기면 사용가능합니다. 만약 미들웨어 함수를 메소드 요청이 왔을 때만 호출하고 싶다면 메소드 app.METHOD
로 메소드를 콜백으로 전달하면 됩니다. 여기서 METHOD
는 get
, 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 메소드의 매개변수로 라우터를 입력해서 다른 미들웨어를 건너뛸 수 있다.