[Express] Routing

Sean·2022년 7월 26일
0

Web

목록 보기
12/22
post-thumbnail

Express에서 Routing이란?

1. Routing

Routing은 어플리케이션이 특정 엔드포인트(URI, 또는 경로)와 특정 HTTP 요청 메서드(get, post 등)에 의한 클라이언트 요청에 어떻게 응답할지를 결정하는 것을 의미합니다.
(공식문서 상의 Routing의 정의)

app.METHOD(PATH, HANDLER)
  • PATH : 서버 상에서의 Path
  • HANDLER : Path가 매치되었을 때 실행할 함수

2. Route Paths

위에서 app.get의 첫번째 파라미터로 경로를 넘겨줬는데, 이러한 요청(ex. get, post, delete, put)메소드와 결합된 Route Path는 요청이 이루어질 수 있는 엔드포인트를 정의합니다.
이 Route Path는 문자열, 문자열 패턴, 정규식의 형태를 허용합니다.

  • ?, +, *, () 와 같은 문자는 정규식에 사용됩니다.
  • hyphen(-), dot(.) 은 문자열 기반의 path에 사용됩니다.
  • 달러 기호 $ 를 문자열 기반의 path 내부에 사용하고 싶다면, ([]) 사이에 escaped된 형태로 사용해야 합니다.
    Ex) "data/$book"으로 라우트하고 싶으면 "data/([\$])book"으로 작성합니다.]

문자열 (String)

app.get('/', (req, res) => {
  	res.send('root')
}
        
app.get('/about', (req, res) => {
  	res.send('about')
}

문자열 패턴 (String Pattern)

//ab?cd는 acd 또는 abcd로 매칭됩니다.
app.get('/ab?cd', (req, res) => {
  	res.send('ab?cd')
}

//ab+cd는 abcd, abbcd, abbbcd, ... 로 매칭됩니다.
app.get('/ab+cd', (req, res) => {
  	res.send('ab+cd')
}

//ab*cd는 abcd, abxcd, abRANDOMcd, ab123cd, ... 로 매칭됩니다.
app.get('/ab*cd', (req, res) => {
  	res.send('ab*cd')
}

//ab(cd)?e는 abe 또는 abcde로 매칭됩니다.
app.get('/ab(cd)?e', (req, res) => {
  	res.send('ab(cd)?e')
}

정규식 (Regular Expression)

///a/는 내부에 a를 포함하고 있는 모든 경로와 매칭됩니다.
app.get('/a/', (req, res) => {
  	res.send('/a/')
}

///,*fly$/는 butterfly, dragonfly와 같이 fly로 끝나는 모든 경로와 매칭됩니다.
app.get('/.*fly$/', (req, res) => {
  	res.send('/.*fly$/')
}

3. Route Parameters

다음과 같이 Route Parameter를 사용하면 파라미터를 경로에 전달할 수 있으며, 전달된 파라미터를 캡처할 수 있습니다. 캡처된 값은 경로에 지정된 Route Parameter 각 변수의 이름을 key로 사용하여 req.params 객체에 저장됩니다.

Route Path: /users/:userId/books/:bookId
Request URL: http://localhost:8080/users/34/books/8989
req.params: { "userId": 34, "bookId": 8989 }

app.get('users/:userId/books/:bookId', (req, res) => {
  	res.send(req.params)
}

hyphen(-)과 dot(.)은 문자 그대로 해석되므로 다음과 같이 Route Parameter와 연결해서 사용할 수 있습니다.

Hyphen(-) 사용 예시

Route Path: /flights/:from-:to
Request URL: http://localhost:8080/flights/LAX-SFO
req.params: { "from": "LAX", "to": "SFO" }

Dot(.) 사용 예시

Route Path: /plantae/:genus.:species
Request URL: http://localhost:8080/plantae/Prunus.persica
req.params: { "genus": "Prunus", "species": "persica" }


4. Route Handlers (콜백함수)

클라이언트의 Request를 처리하기 위해 미들웨어처럼 동작하는 여러개의 Callback 함수를 전달할 수 있습니다.

콜백함수에는 총 3가지의 파라미터가 들어갑니다.

  • req (요청 객체, 필수)
  • res (응답 객체, 필수)
  • next 객체 (선택사항) : next 함수를 호출하면 다음 미들웨어 함수로 제어가 넘어갑니다.

Router Handlers는 함수, 함수들의 배열, 혹은 앞의 두 형태의 혼합형식으로 사용 가능합니다.

Single Callback Function

app.get('/example/a', (req, res) => {
  res.send('Hello!')
}

Multiple Callback Functions

app.get('/example/b', (req, res, next) => {
  console.log('response는 next function이 가져다 줄 거에요~')
  next()
}, (req, res) => {
  res.send('이제서야 response를 보냅니다!')
})

Array of Callback Function

const cb0 = function(req, res, next) {
  console.log('CB0')
  next()
}

const cb1 = function(req, res, next) {
  console.log('CB1')
  next()
}

const cb2 = function(req, res) {
  console.log('CB2')
  res.send('response 전달!')
}

app.get('/example/c', [cb0, cb1, cb2])

Combination of Independent Functions and Arrays of functions

const cb0 = function(req, res, next) {
  console.log('CB0')
  next()
}

const cb1 = function(req, res, next) {
  console.log('CB1')
  next()
}

app.get('/example/d', [cb0, cb1], (req, res, next) => {
  console.log('the response will be sent by the next function')
  next()
}, (req, res) => {
  res.send('Hello from D!')
})

5. Response Methods

아래 테이블에 나열되어 있는 메서드들을 응답 객체(res)에 사용함으로써 클라이언트에게 응답을 보낼 수 있으며, 클라이언트에게 응답함으로써 request-response cycle을 종료시키게 됩니다. 만약에 아래 테이블에 있는 Response Methods들을 한 개도 호출하지 않는다면 클라이언트의 요청은 계속 보류(대기)될 것입니다.

MethodDescription
res.download()파일을 다운로드 할 것인지 묻습니다
res.end()Response 프로세스를 종료시킵니다
res.json()JSON 형태로 응답을 전달합니다.
res.jsonp()JSONP를 지원하는 JSON 응답을 전달합니다.
res.redirect()Request를 redirect 시킵니다.
res.render()view template을 렌더해준다.
res.send()다양한 type으로 응답을 전달해준다.
res.sendFile()octet 스트림으로 파일을 전달해준다.
res.sendStatus()Response status code를 설정하고 해당 status를 문자열로 표현하여 response body에 실어보낸다.

6. express.Router()

우리가 실제로 웹사이트를 개발할 때는 app.get( ~ ), app.post( ~ ) 이런 코드를 엄청나게 많이 쓰게 될 것이 분명하다..!

예를 들어, 온라인 쇼핑몰을 만들었다고 치면 다음과 같은 코드가 셀 수 없이 많을 것이다.

app.get('/phone/apple', (req, res) => {
  res.send(iPhone정보)
}
        
app.get('/phone/samsung', (req, res) => {
  res.send(Galaxy정보)
}
        
...

그러면 가독성도 그만큼 떨어지고 작업의 효율이 매우 낮아질 것이다. 그래서 각각 다른 파일로 관리하고 싶을 때 우리는 express의 Router를 사용한다!

1) routes 폴더를 만든다.

server.js와 같은 디렉토리에 routes라는 폴더를 만들고, 그 안에 phone.js라는 파일을 만들어줍니다.
phone.js에는 다음과 같이 입력해줍니다.

const express = require('express')
const router = express.Router()	//express가 제공하는 Router라는 기능 사용

router.get('/phone/apple', (req, res) => {
  res.send(iPhone정보)
}
           
router.get('phone/samsung', (req, res) => {
  res.send(Galaxy정보)
}

module.exports = router; //파일 최하단에서 지금 만든 라우터를 export해준다.

//이제 이 phone.js라는 라우터를 server.js에 적용하는 일만 남았다!

💡require()module.exports의 용도에 대해서 알아보자!
→ Node.js 환경에서 JavaScript 파일들을 볼러와서 쓰기 위함입니다.

modules.exports = 변수명과 같이 쓰면 해당 변수명을 다른 곳에서 쓸 수 있게 해줍니다.
(함수도 가능해요!)

require('파일경로')와 같이 쓰면 다른 파일을 불러올 수 있습니다.
즉, 다른 파일에서 export 해준 변수를 현재 파일에서 require해서 사용할 수 있는 것입니다.
제일 처음에 우리가 require를 접한 것은 require('express')였는데, 이처럼 파일 경로가 아니라 npm으로 설치한 라이브러리 명을 써도 됩니다!

하지만 이렇게 쓰지 않고, 자바스크립트에 새로 도입된 import, export 문법으로도 사용 가능하니 따로 더 공부하면 될 것 같습니다.


2) server.js에 라우터를 적용한다.

server.js에 다음과 같이 입력합니다.

//사용자가 /phone 경로로 요청하면 실행할 미들웨어 정하기
app.use('/phone', require('./routes/phone.js'))

app.use()는 미들웨어를 사용하고 싶을 때 사용하는 함수입니다.

위의 코드를 이해해보자면, 아까 phone.js에서 export해준 라우터를 어떠한 사용자가 /phone이라는 경로로 요청했을 때 미들웨어로 실행시킨다는 뜻입니다.

이렇게 routes폴더 안에서 라우터들을 관리하면 훨씬 가독성이 올라갈 것 같네요!

profile
여러 프로젝트보다 하나라도 제대로, 깔끔하게.

0개의 댓글