라우팅(Routing)은 특정 엔드 포인트에 대한 클라이언트 요청에 애플리케이션이 응답하는 방법을 결정하는 것을 말한다. 특정 엔드 포인트란 URI(경로)와 HTTP 요청 메서드로 구분된 클라이언트에서 서버로 요청보낼 수 있는 문이다.
익스프레스에서 라우트(route)는 다음과 같은 구조를 가진다.
- app.METHOD(PATH, HANDLER)
- app : express의 인스턴스
- METHOD : HTTP 요청 메서드(GET, POST 등)
- PATH : 서버에서의 경로
- HANDLER : 라우트(Route)가 일치할 때 실행되는 함수
const express = require('express');
const app = express();
// 클라이언트에서 HTTP 요청 메서드 GET 방식으로 'host:port'를 호출했을 때
app.get('/', (req, res) => {
res.send('root'); // 클라이언트에 root 문자열 전송
});
클라이언트에서 서버로 요청을 보낼 때 사용한 HTTP 요청 메서드에 맞는 익스프레스 라우트 메서드로 처리된다. 예를 들어 클라이언트에서 get을 사용해서 HTTP 요청 메서드를 서버로 요청 보냈다면, 익스프레스 라우트 메서드 역시 get으로 되어 있어야 연결된다
아래를 보면 2개의 라우트가 있고, 모두 '/customer'라는 동일한 라우트 경로를 가지고 있다. 하지만 첫 번째 라우트는 라우트 메서드가 get이고, 두 번째 라우트는 라우트 메서드가 post이다.
클라이언트에서 'localhost:8080/customer'라는 주소를 사용해서 서버로 요청을 보낼때 HTTP 요청 메서드로 get을 사용하느냐 post를 사용하느냐에 따라 호출되는 익스프레스 라우터가 달라지게 된다.
const express = require("express");
const app = express();
const port = 8080;
// 8080번 포트로 웹 서버 실행
app.listen(port, () => {
console.log(`서버가 실행됩니다. http://localhost:${port}`);
});
// 클라이언트에서 HTTP 요청 메서드 GET 방식으로 'host:8080/customer'를 호출했을 때
app.get('/customer', (req, res) => {
res.send('get 요청에 대한 응답'); // 클라이언트에 root 문자열 전송
});
// 클라이언트에서 HTTP 요청 메서드 POST 방식으로 'host:8080/customer'를 호출했을 때
app.post('/customer', (req, res) => {
res.send('post 요청에 대한 응답'); // 클라이언트에 root 문자열 전송
});
app.all()
라우트 메서드를 사용하면 된다.app.all('/customer', (req, res) => {
res.send('HTTP 요청 메서드 종류에 상관없이 응답');
});
라우트 경로는 요청 메서드와의 조합을 통해 요청이 이루어질 수 있는 엔드포인트를 정의한다. 라우트 경로는 문자열, 문자열 패턴, 정규식을 이용해서 만들 수 있다.
위의 2. 라우트(Route) 메서드의 예시 코드가 문자열을 기반으로 하는 라우트 경로이다.
문자열 패턴을 기반으로 하는 라우트 경로의 예시는 다음과 같다.
// 'b?'는 문자 'b'가 0개 혹은 1개 있다는 것을 의미
app.get('/ab?cd', (req, res) => {
res.send('/ab?cd');
});
// 클라이언트에서 요청한 라우트 경로에 'a'가 포함되어 있는 경우
app.get(/a/, (req, res) => {
res.send('/a/');
});
클라이언트 요청에 따라 라우트가 일치할 때 실행되는 콜백 함수이다. 파라미터는 다음과 같다.
하나의 라우트에서 next 오브젝트를 사용해서 2개 이상의 콜백 함수를 실행할 수 있다.
// 콜백 함수의 세 번째 파라미터로 next 오브젝트 사용
app.get('/example', (req, res, next) => {
console.log('첫 번째 콜백 함수');
next(); // 다음 콜백 함수 호출
}, (req, res) => {
res.send('두 번째 콜백 함수'); // 클라이언트로 응답
});
const ex1 = (req, res, next) => {
console.log('첫 번째 콜백 함수');
next(); // 다음 콜백 함수 호출
}
const ex2 = (req, res, next) => {
console.log('두 번째 콜백 함수');
next(); // 다음 콜백 함수 호출
}
const ex3 = (req, res) => {
res.send('세 번째 콜백 함수'); // 클라이언트로 응답
}
app.get('/examples', [ex1, ex2, ex3]); // 콜백 함수 배열로 정의
클라이언트로부터 요청이 오면 라우트에서는 아래 메서드 중 한 가지 방법으로 응답을 전송하고 요청(requesr)-응답(response) 주기를 종료할 수 있다. 라우트 핸들러 함수에서 아래 메서드 중 하나라도 호출되지 않은 경우에는 클라이언트 요청이 응답받지 못하고 정지된 채로 있다.
한 라우터에서 여러개의 응답을 보내게 된다면 에러가 발생하므로 단일 요청에는 단일 응답으로 설계해야 한다.
메서드 | 설명 |
---|---|
res.send() | 다양한 유형의 응답을 전송 |
res.json() | JSON 응답을 전송 |
res.end() | 응답 프로세스를 종료 |
app.route()
를 이용하면 get, post, put과 같은 라우트 메서드를 한 곳에서 작성할 수 있다. 이렇게 모듈식 라우트를 작성하면 중복성이 감소하여 코드를 좀 더 효율적으로 관리할 수 있다.// 모듈식 라우터 - 하나의 라우트 경로로 각 라우트 메서드 처리
app.route('/customer')
.get((req, res) => {
res.send('고객 정보 조회');
})
.post((req, res) => {
res.send('신규 고객 추가');
})
.put((req, res) => {
res.send('고객 정보 수정');
})
.delete((req, res) => {
res.send('고객 정보 삭제');
});
express.Router 클래스를 사용하면 라우트 처리를 하나의 파일에서 하는 것이 아니라 여러 개의 파일로 분리해서 각각의 용도(기능)에 맞게 구현하여 사용할 수 있다.
routes라는 이름의 폴더에 customer.js라는 파일을 생성하고 아래와 같이 라우트를 정의한다.
const express = require('express');
const router = express.Router();
// 고객 정보 조회를 위한 라우트
// index.js에서 기본 경로에 /customer를 사용하기 때문에 /customer 라우트 경로를 가짐
router.get('/', (req, res) => {
res.send('customer 라우트 루트');
})
// 고객 정보 추가를 위한 라우트
// index.js에서 기본 경로에 /customer를 사용하기 때문에 /customer/insert 라우트 경로를 가짐
router.post('/insert', (req, res) => {
res.send('/customer/insert 라우트');
});
module.exports = router;
const express = require("express");
const cors = require("cors");
const customerRoute = require("./routes/customer"); // customer 라우트 추가
const app = express();
const port = 8080;
app.use(cors());
// 클라이언트 요청 body를 json으로 파싱 처리
app.use(express.json());
// 8080번 포트로 웹 서버 실행
app.listen(port, () => {
console.log(`서버가 실행됩니다. http://localhost:${port}`);
});
// customer 라우트를 추가하고 기본 경로로 /customer 사용
app.use("/customer", customerRoute);