Yunseok's Dev Blog

배운 것을 적는 블로그입니다.

Express 라우팅 심화

Routing이란 클라이언트의 요청에 어떻게 응답할 것인지 어플리케이션의 endpoint들(URI)을 정의하는것을 말합니다. Routing을 정의하기 위해서는 Express의 app객체를 이용해서 정의할 수 있는데 다음과 같은 것들이 필요합니다.

  • HTTP method
    • GET, POST, PUT, DELETE … 등등
  • Endpoint(URI)
    • /users, /create … 등등
  • Callback(action)
    • 서버에서는 어떤 동작을 할 것인지

Route methods

// GET method route
app.get('/', function (req, res) {
  res.send('GET request to the homepage')
})

// POST method route
app.post('/', function (req, res) {
  res.send('POST request to the homepage')
})

위의 예는 GET과 POST의 예입니다. Express는 HTTP method들을 모두 지원합니다. 지원하는 모든 method들은 app.METHOD를 참고해주세요.

추가로 app.all()이라는 method도 존재하는데 이는 모둔 HTTP method에 응답합니다.

app.all('/secret', function (req, res, next) {
  console.log('Accessing the secret section ...')
  next() // pass control to the next handler
})

위의 예는 /secret endpoint에 모든 GET, POST, PUT, DELETE에 응답합니다.

Route paths

  • Route path는 URI endpoint를 말합니다. string이 될 수도 있고 혹은 regular expression이 될 수 있습니다.
  • ?, +, * 및 ()문자는 정규 표현식의 하위 집합입니다.
  • 하이픈 (-)과 점 (.)은 문자열 기반 경로로 문자 그대로 해석됩니다.
  • 경로 문자열에서 달러 문자 ($)를 사용해야하는 경우 이스케이프 처리 된 문자열 ([and])을 묶어야합니다. 예를 들어 “/data/$book”에있는 요청의 경로 문자열은 “/data/([$]) book”이됩니다.
  • Query string은 route path의 영역이 아닙니다.
  • Express는 route path를 match할 때 path-to-regexp를 사용합니다.
  • Express Route Tester를 사용하여 테스트해볼 수 있습니다.

다음과 같이 단순한 string으로 작성할 수 있습니다.

app.get('/', function (req, res) {
  res.send('root')
})

app.get('/about', function (req, res) {
  res.send('about')
})

/random.text로 요청시에 Route path는 다음과같이 작성합니다.

app.get('/random.text', function (req, res) {
  res.send('random.text')
})

/acd/abcd에 대해 응답하는 Route path입니다.

app.get('/ab?cd', function (req, res) {
  res.send('ab?cd')
})

다음은 /abcd, /abbcd, /abbbcd … 에 대해 응답하는 path입니다.

app.get('/ab+cd', function (req, res) {
  res.send('ab+cd')
})

다음은 /abcd, /abxcd, /abRANDOMcd, ab123cd … 에 대해 응답하는 path입니다.

app.get('/ab*cd', function (req, res) {
  res.send('ab*cd')
})

다음은 /abe/abcde 에 대해 응답하는 path입니다.

app.get('/ab(cd)?e', function (req, res) {
  res.send('ab(cd)?e')
})

Regular expression을 사용하였을 때 다음은 a가 들어간 endpoint는 모두 일치하여 응답합니다.

app.get(/a/, function (req, res) {
  res.send('/a/')
})

다음은 butterfloydragonfly은 응답하지만 butterflymandragonflyman은 응답하지 않습니다.

app.get(/.*fly$/, function (req, res) {
  res.send('/.*fly$/')
})

Route parameters

  • URL에 있는 값을 불러오기 위한 URL segments를 말합니다.
  • 값은 req.params에 파라미터의 이름과 함께 저장이 됩니다.
  • 만약 Route path가 /users/:userId/books/:bookId이고 요청한 URL이 http://localhost:3000/users/34/books/8989이면 req.params의 값은 { "userId": "34", "bookId": "8989" }가 됩니다.

Route path는 다음과 같이 작성할 수 있습니다.

app.get('/users/:userId/books/:bookId', function (req, res) {
  res.send(req.params)
})
  • Router parameter는 [A-Za-z0-9_]만 가능합니다.
  • 만약 Route path가 /flights/:from-:to이고 요청한 URL이 http://localhost:3000/flights/LAX-SFO이면 req.params의 값은 { "from": "LAX", "to": "SFO" }가 됩니다.
  • 만약 Route path가 /plantae/:genus.:species이고 요청한 URL이 http://localhost:3000/plantae/Prunus.persica이면 req.params의 값은 { "genus": "Prunus", "species": "persica" }가 됩니다.
  • 더 정확한 매칭을 위하여 가로안에 regular expression을 사용할 수도 있습니다.
    • 만약 Route path가 /user/:userId(\d+)이고 요청한 URL이 http://localhost:3000/user/42이면 req.params의 값은 {"userId": "42"}가 됩니다.

Route handlers

  • middleware처럼 여러개의 함수를 등록할 수 있습니다.

하나의 callback함수만 등록할 경우 다음과 같이 작성합니다.

app.get('/example/a', function (req, res) {
  res.send('Hello from A!')
})

여러개의 callback함수를 등록할 경우 다음과 같이 작성합니다.

app.get('/example/b', function (req, res, next) {
  console.log('the response will be sent by the next function ...')
  next()
}, function (req, res) {
  res.send('Hello from B!')
})

혹은 callback으로 함수들의 배열을 입력할 수 있습니다.

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

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

var cb2 = function (req, res) {
  res.send('Hello from C!')
}

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

혹은 배열과 함수를 동시에 같이 입력할 수도 있습니다.

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

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

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

Response methods

app.route()

  • 체인 가능한 route handler를 작성있습니다.
  • 자세한 기능은 Router()를 참고하세요.
app.route('/book')
  .get(function (req, res) {
    res.send('Get a random book')
  })
  .post(function (req, res) {
    res.send('Add a book')
  })
  .put(function (req, res) {
    res.send('Update the book')
  })

express.Router

  • Router는 routing시스템의 미들웨어입니다.
  • Router를 통해 모듈러하고 mountable한 route handler를 작성할 수 있습니다.

birds.js라는 router파일을 만들고 다음과같이 작성합니다.

var express = require('express')
var router = express.Router()

// middleware that is specific to this router
router.use(function timeLog (req, res, next) {
  console.log('Time: ', Date.now())
  next()
})
// define the home page route
router.get('/', function (req, res) {
  res.send('Birds home page')
})
// define the about route
router.get('/about', function (req, res) {
  res.send('About birds')
})

module.exports = router

그리고 app에서 모듈을 로드합니다.


var birds = require('./birds')

// ...

app.use('/birds', birds)

이제 응용 프로그램은 /birds /about에 대한 요청을 처리 할 수있을뿐 아니라 경로와 관련된 timeLog 미들웨어 기능을 호출 할 수 있습니다.

Sources

  • https://expressjs.com/en/guide/routing.html