-
[Express.js] Routing(express.Router())Back-End/Express.js 2021. 2. 2. 15:37반응형
🤯 서론
서버를 열기 위한 최소한의 공부를 목표했지만... 역시 쉽지가 않다ㅎㅎㅎㅎㅎ
Express-generator 로 서버환경을 구현했다보니, app.js 코드들이나 디렉토리들을 하나하나 분석하기도 해야했고
그러다보니, 우리가 요청하는 URI에 따른 서버로직을 구현하기 위해 필요한 Routing과,
여기에 사용되거나 혹은 생성기에 기본적으로 포함되었던 Middleware의 의미와 간단한 이해를 정리해야겠다고 느꼈다.
📗 Routing
[Express 공식문서]
라우팅은 URI(또는 경로) 및 특정한 HTTP 요청 메소드(GET, POST 등)인 특정 엔드포인트에 대한 클라이언트 요청에 애플리케이션이 응답하는 방법을 결정하는 것을 말합니다.
각 라우트는 하나 이상의 핸들러 함수를 가질 수 있으며, 이러한 함수는 라우트가 일치할 때 실행됩니다.
위에서 알 수 있듯, Routing은 클라이언트에서 경로와 HTTP 요청을 보내면, 이에 대응하는 라우터에서 Response를 반환한다.
아래는 Router를 정의하는 기본적인 문법이다.
app.[method] ('path', (req, res) => { /* handler function */ })
1) app
express() 객체를 담은 인스턴스이다. 여기엔 HTTP method에 대응하는 함수들을 가지고 있다.
2) method
HTTP request 폼에는 Method 개념이 존재한다. 클라이언트에서 보내는 요청의 유형으로 이해하면 될 것 같다.
CRUD에 대응되는 GET(read), PUT(create),POST(update), Delete(delete) 등의 메소드에 대응하는 함수들을 여기에 작성한다.
- app.get() : HTTP 'GET' 요청에 대응한다. 오직 데이터를 읽는 목적이므로, 특정 리소스를 반환하는 것이 통상이다.
- app.post() : HTTP 'POST' 요청에 대응한다. 정보를 request body에 첨부하며, 서버 리소스가 이를 참고해 수정될 수 있다.
- app.put() : HTTP 'PUT' 요청에 대응한다. 현재 URI 표현값을 첨부한 payload로 바꾼다. (리소스 생성)
- app.delete() : HTTP 'DELETE' 요청에 대응한다. 특정 리소스를 삭제한다.
- app.use() : 위 모든 HTTP 요청에 대응할 수 있다. path(경로값)를 시작점으로 관련 모든 경로를 대응한다.
- app.all() : 위 모든 HTTP 요청에 대응할 수 있다. path(경로값)가 정확히 일치해야 대응한다.
- app.listen() : 해당 path(경로값)에 접근했을 때 내부의 콜백함수가 실행된다. HTTP 요청이 아닌 URI 접속에도 실행된다.
이외에도, route(), param() 등등 다양한 메서드들이 존재하나 우선 HTTP 통신에 필요한 메서드만 인지하도록 하자!
3) path
서버경로에 해당하는 URI 파라미터 값이다. /users, /products 등 경로뿐만 아니라, /users/:id 형태로 동적 라우팅을 대응할 수 있다.
4) Handler function
request(클라이언트 요청객체), response(서버 응답객체) 2가지 인자를 받는다. 각각의 처리 메서드를 활용한다.
- Request(요청) 확인 메서드
- req.params : URI path의 변수값을 조회할 수 있다. /:id가 1이라면, { id: '1' } 객체를 반환한다.
- req.query : URI path의 쿼리스트링을 조회한다. ?limit=5&skip=10 이라면, { limit: '5', skip='10' } 객체를 반환한다.
- Response(응답) 처리 메서드
- res.send() : 다양한 형태의 응답을 보낼 수 있다. (버퍼 데이터, 문자열, HTML 코드, JSON 데이터 등등)
- res.sendFile() : 파일을 응답으로 보낸다. 파일경로를 통상 첨부한다.
- res.json() : JSON 데이터를 응답으로 보낸다. 상품들의 정보를 보낼 때 유용할 것 같으며, send()에 비해 직관적이다.
- res.render([템플릿 파일경로], { 변수 }) : Pug(Jade) 등의 템플릿을 렌더링한다. 파일경로와, 사용될 변수를 입력한다.
- res.redirect(주소) : 내부의 주소URI로 응답을 보낸다.
- res.status(상태코드) : 해당 상태코드의 로직을 추가할 수 있다. (예시: res.status(404).send('Not Found'))
HTTP 프로토콜에 따라 하나의 요청엔 하나의 응답(Stateless)으로 대응해야 하며, 중복응답엔 에러가 발생한다.
(Error: Can't set headers after they are sent.)
* next()
핸들러 함수에는 next() 라는 메서드가 정의되어 있다. 다수의 핸들러 함수를 지정할 때, 함수의 로직 마지막에 next()를 기입한다.
app.get('/path', (req, res) => { console.log('GET request to the /path'); next(); // 둘 이상의 핸들러 함수를 사용하기 위함. }, (req, res) => { res.send('This is /path page!'); } );
🤔 URI vs URL?
프론트와 백은 왔다갔다 하면서 궁금했던 부분이, 바로 이 URI와 URL의 차이다.
막연하게, URL은 웹 브라우저에서 보이는 주소, URI는 서버에 접근하는 경로라고 생각했는데 이 부분이 상당부분 잘못되었다는 것을 알았다.
- URI(Uniform Resource Identifier) : 통합 자원 식별자
인터넷에 있는 자원을 나타내는 유일한 주소이다. URI의 존재는 인터넷에서 요구되는 기본 조건으로 인터넷 프로토콜이 동반된다.
URI의 하위 개념으로, URL과 URN이 있다.
- URL(Uniform Resource Locator) : 파일 식별자, 통합 자원 지시자
네트워크 상에서 리소스가 어디에 있는지 알려주기 위한 규약이다. 컴퓨너 네트워크와 검색 메커니즘에서의 위치를 지정하는 웹 리소스에 대한 참조이다. 해당 주소에 접속하려면, URL에 맞는 프로토콜로 접근해야 한다.
- URN(Uniform Resource Name) : 통합 자원 이름
리소스의 위치에 영향을 받지 않는 그 이름이다. 독립적인 값으로, 리소스 위치를 옮기거나 여러 프로토콜로 접근해도 문제없다.
위키피디아 개념은 이해하기 힘들지만, 결론은 URI는 리소스에 대한 규약, URL는 리소스 규약에 대한 형태이자 식별자인 것이다.
위 경우에서, path까지는 URL이지만, query string을 포함한 전체부분은 URI라고 생각된다. (일종의 부분집합)
📗 express.Router()
[Express 공식문서]
express.Router 클래스를 사용하면 모듈식 마운팅 가능한 핸들러를 작성할 수 있습니다. Router 인스턴스는 완전한 미들웨어이자 라우팅 시스템이며, 따라서 “미니 앱(mini-app)”이라고 불리는 경우가 많습니다.
const express = require('express'); const app = express(); app.get('/',(req,res,next) => { res.send('Hello world!'); }); app.post('/users',(req,res,next) => { // response... }); app.get('/products',(req,res,next) => { // response... }); app.get('/products/:id',(req,res,next) => { // response... });
Express에서는 위처럼 Router를 만들 수 있다. 하지만, 프로젝트의 규모가 커지면 위처럼 app.js 의 코드량도 늘어날 것이다.
이를 위해, Express는 Router() 클래스를 제공하며, 이를 활용해서 Router 기능 및 핸들러들을 각각 모듈화할 수 있다.
- Router 모듈화
위에서 언급했듯, Express는 기본적으로 라우팅이 가능하지만 기능별 코드관리를 위해 Router를 별도로 분리(모듈화)하는 것이다.
우리는 Express-generator 에서 만들어진 모듈화된 Router들을 가지고 있다. 이를 분석해보도록 하였다.
1) router/index.js
Router 모듈들을 모아놓은 router 디렉토리가 있으며, 각 모듈은 js파일로 작성한다.
var express = require('express'); var router = express.Router(); router.get('/', function(req, res, next) { res.render('index', { title: 'AirTnT' }); }); module.exports = router;
- express 변수에 Express를 가져오고, router 변수를 Express의 Router() 를 인스턴스화 한다.
- router 객체는 app과 같은 문법으로 사용하면 된다.(메서드, 경로, 핸들러 함수)
- 해당 모듈을 export 한다. (module.exports 의미: express.Router() 가 반환한 객체(router)를 수정한 최종객체를 모듈로 반환)
* 모듈이란? jongmin92 님의 github 블로그(jongmin92.github.io/2016/08/25/Node/module-exports_exports/)
2) /app.js
메인 서버파일에서 모듈들을 import 하고 활용하는 부분이다.
var indexRouter = require('./routes/index'); app.use('/', indexRouter);
- routes 디렉토리 -> index.js를 require 한 뒤, indexRouter 에 저장한다.
- app(express())에서 사용할 핸들러로 이 indexRouter 를 적용한다.
- Router 중복경로 모듈화
같은 URI 경로의 하위경로들에서 라우팅을 하는 경우가 있다. (로그인/회원가입을 sign/login, sign/register...)
이 때도, 상위경로 단위로 모듈화하면 기능별 바인딩을 더 효율적으로 할 수 있다. (위 예시에선 /routes/sign.js)
// /routes/sign.js var express = require('express'); var router = express.Router(); router.get('/', function (req,res) { res.send('This is Sign Server'); }); router.post('/login', function (req, res) { /* Login logic */ }); router.post('/register', function (req, res) { /* Register logic */ }); module.exports = router; // /app.js var express = require('express'); var app = express(); var signRouter = require('./router/sign.js'); app.get('/', function (req, res) { res.send('This is main'); }); app.use('/sign', signRouter);
- sign.js 안에는, 하위경로들을 지정하고 여기의 핸들러 함수는 각각의 로직들을 포함하고 있다.
- app.js 에서는, sing.js를 signRouter 변수로 저장하여 app.use() 하면 해당 하위로직들까지 구현이 되는 것이다.
동적 라우팅, 페이지네이션을 이전에 구현해보면서, 데이터 핸들링을 위해 반드시 필요했던 서버 라우팅을 드디어 깨우쳤다!!! 😃😃
또한, Express에서 라우팅 기능을 지원하는 Router() 의 사용법에 대해서도 감을 잡게 되었다~
이제, 로그인/회원가입 서버, 에어비앤비 숙소 정보(동적 라우팅, 페이지네이션) 순서로 구현하며 라우팅을 숙달해야겠다.
공부하면서 미들웨어라는 단어를 많이 접했다. app이나 router 내의 핸들러 함수를 미들웨어라고도 칭하곤 했다.
또한, morgan, body-parser 등 생성자에 포함된 모듈들을 third-party middleware 라고 부르기도 했다.
이 미들웨어는 프론트-백의 Request, Response 중간에 동작하는 객체들이라고 한다. 다음엔 이 미들웨어를 좀 더 자세히 공부하겠다!
[출처]
- Express 공식 홈페이지 : expressjs.com/ko/guide/routing.html
- 김정환 님의 블로그 : jeonghwan-kim.github.io/express-js-2-%EB%9D%BC%EC%9A%B0%ED%8C%85/
- jongmin92 님의 블로그(jongmin92.github.io/2016/08/25/Node/module-exports_exports/)
반응형'Back-End > Express.js' 카테고리의 다른 글
[Express.js] 미들웨어(Middleware) (0) 2021.02.15 [Express.js] CORS(Cross-Origin Resource Sharing) (0) 2021.02.13 [Express.js] Query String, Semantic URL (0) 2021.02.07 [Express.js] 인증/인가(Bcrypt, JWT) (0) 2021.02.04 [Express.js] Express 설치 및 실행 (0) 2021.02.01