๐ŸŒณ๋ชฉํ‘œ

์ต์Šคํ”„๋ ˆ์Šค์™€ ์œ ์‚ฌํ•œ ์‘๋‹ต ๊ฐ์ฒด์ธ Response ๋ชจ๋“ˆ์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

Response ๋ชจ๋“ˆ

์•ž์œผ๋กœ ์›น ๊ฐœ๋ฐœ์„ ํ•  ๋•Œ API๋Š” ์ž์ฃผ ์‚ฌ์šฉ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‹จ์ผ ํŽ˜์ด์ง€ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ๋Š” ๊ฑฐ์˜ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ API ํ˜•ํƒœ๋กœ ๋‹ค๋ฃจ๊ธฐ ๋•Œ๋ฌธ์ด์ฃ .

์ด ๋•Œ ์„œ๋ฒ„๋Š” JSON ํ˜•์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์‘๋‹ตํ•ด์•ผ ํ•˜๋Š”๋ฐ ๊ฝค ์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ์ฝ”๋“œ๊ฐ€ ๋  ๋“ฏ ์‹ถ์Šต๋‹ˆ๋‹ค.

๋ฟ๋งŒ์•„๋‹ˆ๋ผ ์ƒํƒœ ์ฝ”๋“œ๋ฅผ ํฌํ•จํ•œ ํ—ค๋” ์„ค์ •๋„ ๋ชจ๋“  ์—”๋“œ ํฌ์ธํŠธ๋งˆ๋‹ค ์‚ฌ์šฉ๋  ๊ฒƒ ๊ฐ™๊ตฌ์š”.

์ด๋Ÿฌํ•œ ์‘๋‹ต ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ โ€œResponseโ€ ๋ผ๋Š” ๋ชจ๋“ˆ์„ ๋งŒ๋“ค์–ด ๋ณผ ๊ฑฐ์—์š”.

์‹œ๋ฆฌ์ฆˆ ์ดˆ๋ฐ˜์— ์†Œ๊ฐœํ–ˆ๋˜ http.createServer() ๋ฉ”์†Œ๋“œ๋ฅผ ๊ธฐ์–ตํ•˜๋‚˜์š”? ์ด๊ฒƒ์˜ ์ฝœ๋ฐฑํ•จ์ˆ˜๊ฐ€ ์ธ์ž๋กœ ๋ฐ›๋Š” ์‘๋‹ต ๊ฐ์ฒด res๋ฅผ ํ™•์žฅํ•ด์„œ ๋งŒ๋“ค์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์š”๊ตฌ์‚ฌํ•ญ ํ™•์ธ

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๊ฐ€ ์žˆ๋Š” ๋ธŒ๋žœ์น˜๋กœ ์ฒดํฌ์•„์›ƒ ํ•ฉ๋‹ˆ๋‹ค.

$ git checkout -f response/spec

src/Response.spec.js ์ฝ”๋“œ์— ์š”๊ตฌ์‚ฌํ•ญ์„ ๊ธฐ๋กํ•œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

  it('status ๋ฉ”์†Œ๋“œ๋ฅผ ๋…ธ์ถœํ•œ๋‹ค', () => {
    res.should.have.property('status')
    should(typeof res.status).be.equal('function')
  })

  it('set ๋ฉ”์†Œ๋“œ๋ฅผ ๋…ธ์ถœํ•œ๋‹ค', () => {
    res.should.have.property('set')
    should(typeof res.set).be.equal('function')
    should(res.set.length).be.equal(2);
  })

  it('send ๋ฉ”์†Œ๋“œ๋ฅผ ๋…ธ์ถœํ•œ๋‹ค', () => {
    res.should.have.property('send')
    should(typeof res.send).be.equal('function')
  })

  it('json ๋ฉ”์†Œ๋“œ๋ฅผ ๋…ธ์ถœํ•œ๋‹ค', () => {
    res.should.have.property('json')
    should(typeof res.json).be.equal('function')
  })

ํ•จ์ˆ˜ ์œ ๋ฌด๋งŒ ํŒ๋‹จํ•˜๋Š” ๊ฐ„๋‹จํ•œ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค์ธ๋ฐ์š”, ๊ฐ ํ•จ์ˆ˜์˜ ์—ญํ• ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์•„์š”.

  • status(code): ์ƒํƒœ ์ฝ”๋“œ๋ฅผ ์„ค์ •
  • set(key, value): ํ—ค๋” ๊ฐ’์„ key/value๋กœ ์„ค์ •
  • send(text): ๋ฌธ์ž ์‘๋‹ต
  • json(object): ์ œ์ด์Šจ ์‘๋‹ต

๐Ÿค์‹ค์Šต - Response ๋ชจ๋“ˆ์„ ๋งŒ๋“ค์–ด ๋ณด์„ธ์š”

res ๊ฐ์ฒด๋ฅผ ์ด์šฉํ•ด Response ๋ชจ๋“ˆ์„ ๊ตฌํ˜„ํ•ด ๋ณด์„ธ์š”. ์œ„์—์„œ ์„ค๋ช…ํ•œ 4๊ฐœ ๋ฉ”์†Œ๋“œ๋ฅผ ๋ชจ๋‘ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

ํžŒํŠธ: res ๊ฐ์ฒด๋ฅผ ํ™•์žฅํ•ด์„œ ๋งŒ๋“ค๊ธฐ

๐Ÿคํ’€์ด

๋‹ค ๋งŒ๋“ค์ˆ˜ ์žˆ์—ˆ๋‚˜์š”? ๊ทธ๋Ÿผ ๊ฐ™์ด ํ’€์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๐Ÿ‘จ๐Ÿปโ€๐Ÿซ

๋จผ์ € src ํด๋”์— Response.js ํŒŒ์ผ์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๋‹ค์„ฏ ๋ถ€๋ถ„์œผ๋กœ ๋‚˜๋ˆ  ์ฝ”๋“œ๋ฅผ ์ž…๋ ฅํ• ๊ฒŒ์š”

const Response = res => {
  if (!res) throw Error('res is required');

  return res
}

module.exports = Response

Response ๋ชจ๋“ˆ์€ ๊ธฐ์กด์˜ res ๊ฐ์ฒด๋ฅผ ์ธ์ž๋กœ ๋ฐ›์Šต๋‹ˆ๋‹ค. ์—†์„ ๊ฒฝ์šฐ ์ฆ‰์‹œ ์—๋Ÿฌ๋ฅผ ๋˜์ ธ ํ”„๋กœ๊ทธ๋žจ์„ ์ข…๋ฃŒํ•˜๊ตฌ์š”.

res๋ฅผ ํ™•์žฅํ•œ ๋’ค ๋งˆ์ง€๋ง‰์— ๋ฐ˜ํ™˜ํ•ด ์ค๋‹ˆ๋‹ค. (์•„์ง ํ™•์žฅ ์ฝ”๋“œ๋Š” ์—†์Šต๋‹ˆ๋‹ค)

๊ทธ๋Ÿผ ๋ฉ”์†Œ๋“œ๋ฅผ ํ•˜๋‚˜์”ฉ ์ถ”๊ฐ€ํ•ด ๋ณด์ฃ .

  res.status = res.status || (code => { // ๊ธฐ์กด ๊ฐ์ฒด์— ์•ˆ์ „ํ•˜๊ฒŒ ์ถ”๊ฐ€ 
    res.statusCode = code;
    return res; // ํ•จ์ˆ˜ ์ฒด์ด๋‹์„ ์œ„ํ•ด 
  })

์ƒํƒœ๊ฐ’์„ ์„ค์ •ํ•˜๋Š” status() ๋ฉ”์†Œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. res๋Š” ์ด๋ฏธ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š” ๊ฐ์ฒด์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ธฐ์กด ํ‚ค๋ฅผ ๋ฎ์–ด ์“ฐ์ง€ ์•Š๊ธฐ ์œ„ํ•ด || ์—ฐ์‚ฐ์„ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

statusCode๋ฅผ ์„ค์ •ํ•œ ํ›„ res๋ฅผ ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ํŽธ๋ฆฌํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๋„๋ก ํ•˜๊ธฐ ์œ„ํ•œ ํ•จ์ˆ˜ ์ฒด์ด๋‹ ๊ธฐ๋ฒ•์ž…๋‹ˆ๋‹ค.

  res.set = res.set || ((key, value) => {
    res.setHeader(key, value);
    return res; // ํ•จ์ˆ˜ ์ฒด์ด๋‹์„ ์œ„ํ•ด
  })

ํ‚ค/๊ฐ’์„ ์ธ์ž๋กœ ๋ฐ›์•„ ํ—ค๋”์— ์„ธํŒ…ํ•˜๋Š” set() ๋ฉ”์†Œ๋“œ ์ž…๋‹ˆ๋‹ค. setHeader() ๋ฉ”์†Œ๋“œ๋กœ ํ—ค๋”๊ฐ’์„ ์„ค์ •ํ•˜๊ณ , ์—ญ์‹œ ํ•จ์ˆ˜ ์ฒด์ด๋‹์„ ์œ„ํ•ด res๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

  res.send = res.send || (text => {
    if (!res.getHeader('Content-Type')) {
      res.setHeader('Content-Type', 'text/plain');
    }
    res.end(text);
  })

๋ฌธ์ž์—ด์„ text๋กœ ๋ฐ›์•„ end() ๋ฉ”์†Œ๋“œ๋กœ ์‘๋‹ตํ•˜๋Š” send() ๋ฉ”์†Œ๋“œ์ž…๋‹ˆ๋‹ค. ๋งŒ์•ฝ getHeader()๋กœ ์กฐํšŒํ•œ ๋’ค ์„ค์ •๋œ Content-Type ํ—ค๋”๊ฐ€ ์—†๋‹ค๋ฉด โ€œtext/plainโ€์œผ๋กœ ๊ธฐ๋ณธ๊ฐ’์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

  res.json = res.json || (data => {
    res.setHeader('Content-Type', 'application/json');
    res.end(JSON.stringify(data));
  })

json() ๋ฉ”์†Œ๋“œ๋Š” ํ—ค๋”์™€ ๋ฐ”๋””๋ฅผ ์ œ์ด์Šจ ํ˜•์‹์œผ๋กœ ์‘๋‹ตํ•ฉ๋‹ˆ๋‹ค.

๐Ÿค์‹ค์Šต - Response ๋ชจ๋“ˆ์„ Application์—์„œ ์‚ฌ์šฉํ•ด ๋ณด์„ธ์š”

์ด๋ ‡๊ฒŒ ๊ตฌํ˜„ํ•œ Response ๋ชจ๋“ˆ์„ Application์—์„œ ์‚ฌ์šฉํ•ด์•ผ ์›น ์„œ๋ฒ„๊ฐ€ ์ œ๋Œ€๋กœ ๋™์ž‘ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋งˆ์น˜ Middleware ๋ชจ๋“ˆ์„ Application์—์„œ ํ™œ์šฉํ•œ ๊ฒƒ ์ฒ˜๋Ÿผ ๋ง์ด์ฃ .

Application ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜์—ฌ Response ๋ฉ”์†Œ๋“œ๋ฅผ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ฐœ์„ ํ•ด ๋ณด์„ธ์š”. ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์ง€ ๋ชปํ•˜์‹  ๋ถ„์€ ๋ธŒ๋žœ์น˜ ์ด๋™ํ›„ ์ง„ํ–‰ํ•˜์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

$ git checkout -f response/methods

ํžŒํŠธ: Middleware.run(req, res) ๋ถ€๋ถ„ ๋ณ€๊ฒฝ, route/index.js, api/posts.js ๋ณ€๊ฒฝ

๐Ÿคํ’€์ด

๊ฐ™์ด ํ’€์–ด ๋ณผ๊นŒ์š”?

src/Application.js์—์„œ req, res ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•œ ๋ถ€๋ถ„์ด ์–ด๋””์ผ๊นŒ์š”? ๋„ค, ๋ฐ”๋กœ ๋ฏธ๋“ค์›จ์–ด ๊ตฌ๋™ ๋ฉ”์†Œ๋“œ์ธ run() ๋ถ€๋ถ„์ด์ฃ . ๋ฏธ๋“ค์›จ์–ด ํ•จ์ˆ˜์— ์ฃผ์ž…ํ•˜๊ธฐ ์œ„ํ•ด ์—ฌ๊ธฐ์„œ๋ถ€ํ„ฐ req, res๋ฅผ ์ธ์ž๋กœ ์ „๋‹ฌํ•˜๋Š” ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.

์ด ๋ถ„์„ ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  Response ๊ฐ์ฒด๋กœ ๊ต์ฒดํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

const Response = require('./Response')

const Application = () => {
  const _middleware = Middleware();

  const _server = http.createServer((req, res) => {
    _middleware.run(req, Response(res)) // Response ๊ฐ์ฒด๋กœ ๊ต์ฒด 
  })
  // ...

๋น„๊ต์  ๊ฐ„๋‹จํ•˜์ง€์š”?

๊ทธ๋Ÿผ ๊ฐ ๋ฏธ๋“ค์›จ์–ด ํ•จ์ˆ˜์—์„œ๋Š” ๊ธฐ์กด์˜ res ๋ฉ”์†Œ๋“œ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ Response ๊ฐ์ฒด์˜ ๋ฉ”์†Œ๋“œ๊นŒ์ง€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

ํ˜„์žฌ๊นŒ์ง€ ๋ผ์šฐํŠธ ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ 2๊ฐœ์ฃ ?

  • index.listPosts()
  • apiPost.index()

์ด๊ฑธ ์ƒˆ๋กœ ์ œ์ž‘ํ•œ ๋ฉ”์†Œ๋“œ๋ฅผ ์ด์šฉํ•ด ๋” ์‹ฌํ”Œํ•œ ์ฝ”๋“œ๋กœ ๊ฐœ์„ ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

index.listPosts()๋Š” routers/index.js์— ์ •์˜ ๋˜์–ด ์žˆ์ฃ .

const listPosts = () => (req, res, next) => {
  fs.readFile(`${publicPath}/index.html`, (err, data) => {
    if (err) throw err

    res.status(200).set('Content-Type', 'text/html').send(data)
  })
 }

์ƒํƒœ์ฝ”๋“œ๋ฅผ ์„ค์ •ํ•˜๋Š” status()์™€ ํ—ค๋”๋ฅผ ์„ค์ •ํ•˜๋Š” set(), ๊ทธ๋ฆฌ๊ณ  ์‘๋‹ตํ•˜๋Š” send() ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ ํ•จ์ˆ˜ ์ฒด์ด๋‹์„ ์ง€์›ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ฝ”๋“œ๋ฅผ ํ•œ ์ค„๋กœ ์ž‘์„ฑํ•œ ๋ถ€๋ถ„์„ ๋ˆˆ์—ฌ๊ฒจ ๋ณด์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

apiPost.index()๋Š” api/posts.js์— ์žˆ์Šต๋‹ˆ๋‹ค.

const index = () => (req, res, next) => {
  res.status(200).json(posts);
}

json ์‘๋‹ต์€ ์ด๋ ‡๊ฒŒ ๊ฐ„๋‹จํžˆ ์„ค์ •ํ• ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฝ”๋“œ๋ฅผ ๋” ๋‹จ์ˆœํ•˜๊ฒŒ ๋งŒ๋“ค๊ณ  ์‹ถ๋‹ค๋ฉด ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” 200 ์ƒํƒœ ์ฝ”๋“œ๋Š” ๊ธฐ๋ณธ ์ธ์ž๊ฐ’์œผ๋กœ ์„ค์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ๊ฒ ๋„ค์š”.

๋ฐฉ๊ธˆ ๋งŒ๋“ค์—ˆ๋˜ Response ๋ชจ๋“ˆ์ด ์ต์Šคํ”„๋ ˆ์ŠคJS์˜ ์„ธ ๋ฒˆ์งธ ๋ชจ๋“ˆ ๋˜์‹œ๊ฒ ์Šต๋‹ˆ๋‹ค! (์ดˆ๋ก์ƒ‰ ๋ถ€๋ถ„)

์ •๋ฆฌ

  • ์‘๋‹ต ์ฒ˜๋ฆฌ๋ฅผ ๊ฐœ์„ ํ•˜๊ธฐ์œ„ํ•ด Response ๋ชจ๋“ˆ์„ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.
  • stauts(), set(), send(), json() ๋ฉ”์†Œ๋“œ๋ฅผ ์ถ”๊ฐ€๋กœ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

๋ชฉ์ฐจ ๋ฐ”๋กœ๊ฐ€๊ธฐ