Thinking in GraphQL

Created: January 13, 2022 11:49 AM

GraphQL์€ ํ”„๋กœ๋•ํŠธ ๊ฐœ๋ฐœ์ž์™€ ํด๋ผ์ด์–ธํŠธ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์š”๊ตฌ์‚ฌํ•ญ์— ์ง‘์ค‘ํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ํŒจ์น˜ํ•˜๋Š” ์ƒˆ๋กœ์šด ๋ฐฉ๋ฒ•์„ ์ œ์‹œํ•œ๋‹ค.

๊ฐœ๋ฐœ์ž๊ฐ€ ๋ทฐ์— ํ•„์š”๋กœ ํ•˜๋Š” ์ •ํ™•ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ตฌ์ฒดํ™”ํ•˜๊ณ  ํ•˜๋‚˜์˜ ๋„คํŠธ์›Œํฌ ์š”์ฒญ์„ ํ†ตํ•ด ๊ทธ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•œ๋‹ค.

์ž์› ๊ธฐ๋ฐ˜์˜ REST ์ ‘๊ทผ๋ฐฉ์‹๊ณผ ๊ฐ™์€ ๊ธฐ์กด์˜ ๋ฐฉ๋ฒ•๊ณผ ๋น„๊ตํ•ด๋ณด๋ฉด, GraphQL์€ ๋ฐ์ดํ„ฐ๋ฅผ ๋”์šฑ ํšจ์œจ์ ์œผ๋กœ ํŒจ์น˜ํ•˜๊ฒŒ๋” ๋•๊ณ  custom endpoint๋ฅผ ์ด์šฉํ•จ์— ๋”ฐ๋ผ ์ค‘๋ณต๋˜๋Š” ์„œ๋ฒ„ ๋กœ์ง์„ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.

๊ฒŒ๋‹ค๊ฐ€, GraphQL์€ ํ”„๋กœ๋•ํŠธ ์ž์ฒด์˜ ์ฝ”๋“œ์™€ ์„œ๋ฒ„ ๋กœ์ง์„ ๋ถ„๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ๋” ๋•๋Š”๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ํ”„๋กœ๋•ํŠธ๋Š” ํ•„์š”๋กœ ํ•˜๋Š” ์ •๋ณด์™€ ๊ด€๋ จ๋œ ์„œ๋ฒ„ endpoint์˜ ๋ณ€๊ฒฝ ์—†์ด ํŒจ์น˜ํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์กฐ์ ˆํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด ๊ธ€์„ ํ†ตํ•ด GraphQL ํด๋ผ์ด์–ธํŠธ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ๋งŒ๋“œ๋Š” ์˜๋ฏธ์™€ ์ „ํ†ต์ ์ธ REST ์‹œ์Šคํ…œ๊ณผ ๋น„๊ต๋˜๋Š” ์ ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. ๋˜ํ•œ Relay ๊ธฐ์ €์— ๊น”๋ฆฐ ๋””์ž์ธ ๊ฒฐ์ •์ ์ธ ์š”์†Œ์™€ GraphQL ํด๋ผ์ด์–ธํŠธ๋กœ์จ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋ช…์‹œ์ ์ธ ๋ฐ์ดํ„ฐ ํŒจ์นญ ํ”„๋ ˆ์ž„์›Œํฌ๋กœ์จ์˜ Relay๋ฅผ ์•Œ์•„๋ณด๊ณ ์ž ํ•œ๋‹ค.

๋ฐ์ดํ„ฐ ํŒจ์นญ

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์Šคํ† ๋ฆฌ ๋ฆฌ์ŠคํŠธ์™€ ๊ฐ ์Šคํ† ๋ฆฌ์˜ ๋””ํ…Œ์ผ์„ ํŒจ์น˜ํ•˜๋Š” ๊ฐ„๋‹จํ•œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž.

๊ธฐ์กด์˜ REST๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

// ์Šคํ† ๋ฆฌ ID ๋ฆฌ์ŠคํŠธ๋งŒ ํŒจ์น˜ํ•˜๊ณ 
// ๋””ํ…Œ์ผ์€ ํŒจ์น˜ํ•˜์ง€ ์•Š์Œ
rest.get('/stories')
	.then(stories =>
  // ๊ด€๋ จ๋œ ์ž์›์˜ ๋งํฌ๋ฅผ ๋ฐ˜ํ™˜
  // `[ { href: "http://.../story/1" }, ... ]`
  Promise.all(stories.map(story =>
    rest.get(story.href) // Follow the links
  ))
).then(stories => {
  // ์Šคํ† ๋ฆฌ ์•„์ดํ…œ(๋””ํ…Œ์ผ)์„ ๋ฐ˜ํ™˜
  // `[ { id: "...", text: "..." } ]`
  console.log(stories);
});

์ด ๊ณผ์ •์€ ์„œ๋ฒ„์— n+1 ๋ฒˆ์˜ ์š”์ฒญ์„ ๋ณด๋‚ธ๋‹ค.

  • 1๋ฒˆ์€ ๋ฆฌ์ŠคํŠธ๋ฅผ ํŒจ์น˜ํ•˜๊ธฐ ์œ„ํ•จ

  • n๋ฒˆ์€ ๊ฐ๊ฐ์˜ ์•„์ดํ…œ์„ ํŒจ์น˜ํ•˜๊ธฐ ์œ„ํ•จ

GraphQL์„ ์ด์šฉํ•˜์—ฌ, ์ปค์Šคํ…€ endpoint๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š๊ณ ๋„(์ด๋ฅผ ์ƒ์„ฑํ•  ์‹œ ์œ ์ง€ํ•ด์•ผ ํ•œ๋‹ค.) ์„œ๋ฒ„์— ๋‹จ ํ•œ ๋ฒˆ์˜ ๋„คํŠธ์›Œํฌ ์š”์ฒญ์„ ํ†ตํ•ด ์œ„์™€ ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฅผ ํŒจ์น˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

graphql.get(`query { stories { id, text } }`).then(
  stories => {
    // ์Šคํ† ๋ฆฌ ์•„์ดํ…œ์„ ๋‹ด์€ ๋ฆฌ์ŠคํŠธ
    // `[ { id: "...", text: "..." } ]`
    console.log(stories);
  }
);

์—ฌ๊ธฐ๊นŒ์ง€๋Š” REST ์ ‘๊ทผ๋ณด๋‹ค ์ข€ ๋” ํšจ์œจ์ ์ธ ๋ฒ„์ „์œผ๋กœ GraphQL์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™๋‹ค.

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด 2๊ฐ€์ง€์˜ ์ค‘์š”ํ•œ ์ด์ ์ด ์žˆ๋Š”๋ฐ,

  1. ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋Š” ํ•œ๋ฒˆ์˜ round trip์œผ๋กœ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

  2. ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„๊ฐ€ ๋ถ„๋ฆฌ๋  ์ˆ˜ ์žˆ๋‹ค: ํด๋ผ์ด์–ธํŠธ๋Š” ์„œ๋ฒ„์˜ endpoint์— ์˜์กดํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค์ง€ ์•Š๊ณ  ์ง์ ‘ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ตฌ์ฒดํ™” ํ•  ์ˆ˜ ์žˆ๋‹ค.

ํด๋ผ์ด์–ธํŠธ ์บ์‹ฑ

์„œ๋ฒ„์—์„œ ๊ฐ™์€ ์ •๋ณด๋ฅผ ๋‹ค์‹œ ํŒจ์นญํ•˜๋Š” ๊ฒƒ์€ ๊ฝค ๋Š๋ฆด ์ˆ˜ ์žˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ์Šคํ† ๋ฆฌ ๋ฆฌ์ŠคํŠธ๋ถ€ํ„ฐ ํ•˜๋‚˜์˜ ์•„์ดํ…œ๊นŒ์ง€ ์ฐพ์•„ ๋‚ด๋ ค๊ฐ€๊ณ  ๋‹ค์‹œ ์Šคํ† ๋ฆฌ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ฐพ๊ธฐ ์œ„ํ•ด ๋˜๋Œ์•„์˜ค๋Š” ๊ฒฝ๋กœ๋Š” ๊ฒฐ๊ตญ ๋ฆฌ์ŠคํŠธ ์ž์ฒด๋ฅผ ๋‹ค์‹œ ํŒจ์น˜ํ•ด์•ผ ํ•จ์„ ์˜๋ฏธํ•œ๋‹ค.

GraphQL์€ โ€œ์บ์‹ฑโ€์ด๋ผ๋Š” ํ•ด๊ฒฐ์ฑ…์„ ์ œ์‹œํ•œ๋‹ค.

์ž์› ๊ธฐ๋ฐ˜์˜ REST ์‹œ์Šคํ…œ์˜ ๊ฒฝ์šฐ, URI์— ๊ธฐ๋ฐ˜ํ•˜์—ฌ ์‘๋‹ต ์บ์‹œ๋ฅผ ์œ ์ง€ํ•œ๋‹ค.

var _cache = new Map();
// uri
rest.get = uri => {
  if (!_cache.has(uri)) {
    _cache.set(uri, fetch(uri));
  }
  return _cache.get(uri);
};

์ด๋Ÿฌํ•œ ์‘๋‹ต ์บ์‹ฑ์€ GraphQL์—๋„ ์ ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.

๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ์ ‘๊ทผ ๋ฐฉ์‹์€ REST ๋ฒ„์ „๊ณผ ๋น„์Šทํ•˜๋‹ค.

์ด ๋•Œ ์ฟผ๋ฆฌ (ํ…์ŠคํŠธ) ์ž์ฒด๊ฐ€ ์บ์‹œ ํ‚ค๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค.

var _cache = new Map();
// queryText
graphql.get = queryText => {
  if (!_cache.has(queryText)) {
    _cache.set(queryText, fetchGraphQL(queryText));
  }
  return _cache.get(queryText);
};

์ด์ „์— ์บ์‹œ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•  ๊ฒฝ์šฐ, ์ถ”๊ฐ€์ ์ธ ๋„คํŠธ์›Œํฌ ์š”์ฒญ ์—†์ด GraphQL์€ ์ฆ‰๊ฐ์ ์œผ๋กœ ์บ์‹œ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

์ด ์‹ค์šฉ์ ์ธ ๋ฐฉ์‹์€ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ง€๊ฐ๋˜๋Š” performance๋ฅผ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

ํ•˜์ง€๋งŒ, ์ด๋Ÿฌํ•œ ์บ์‹ฑ ๋ฐฉ๋ฒ•์€ ๋ฐ์ดํ„ฐ ์•ˆ์ •์„ฑ์˜ ์ธก๋ฉด์—์„œ ๋ฌธ์ œ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

์บ์‹œ ์ผ๊ด€์„ฑ

GraphQL์„ ์‚ฌ์šฉํ•˜๋‹ค ๋ณด๋ฉด, ์—ฌ๋Ÿฌ ์ฟผ๋ฆฌ์˜ ๊ฒฐ๊ณผ๊ฐ€ ์ค‘๋ณต๋˜๋Š” ๊ฒƒ์„ ์‰ฝ๊ฒŒ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

ํ•˜์ง€๋งŒ, ์ด์ „ ์„น์…˜์˜ ์‘๋‹ต ์บ์‹œ๋Š” ์ด๋Ÿฌํ•œ ์ค‘๋ณต๊ณผ ๊ด€๋ จ์ด ์—†๋‹ค - ์‘๋‹ต ์บ์‹œ๋Š” ๊ฐœ๋ณ„์ ์ธ ์ฟผ๋ฆฌ์— ๊ธฐ๋ฐ˜ํ•˜์—ฌ ์บ์‹ฑ๋œ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ์Šคํ† ๋ฆฌ๋ฅผ ํŒจ์น˜ํ•˜๊ธฐ ์œ„ํ•ด ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค๊ณ  ํ•ด๋ณด์ž.

query {
	stories { 
		id, 
		text, 
		likeCount 
	} 
}

์ดํ›„, likeCount ๊ฐ€ ์ฆ๊ฐ€ํ•œ ์Šคํ† ๋ฆฌ ํ•˜๋‚˜๋ฅผ ๋‹ค์‹œ ํŒจ์น˜ํ•œ๋‹ค๊ณ  ํ•ด๋ณด์ž.

query {
	stories(id: "123") { 
		id, 
		text, 
		likeCount 
	} 
}

์—ฌ๊ธฐ์„œ ์Šคํ† ๋ฆฌ๊ฐ€ ์ ‘๊ทผ๋œ ๋ฐฉ์‹์ด ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์—, ์šฐ๋ฆฌ๋Š” ๋‹ค๋ฅธ likeCount ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์ฒซ๋ฒˆ์งธ ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•œ ๋ทฐ๋Š” ๊ตฌ์‹์˜ count ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์„ ๊ฒƒ์ด๊ณ , ๋‘๋ฒˆ์งธ ์ฟผ๋ฆฌ๋ฅผ ์ด์šฉํ•œ ๋ทฐ๋Š” ์—…๋ฐ์ดํŠธ ๋œ count ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์„ ๊ฒƒ์ด๋‹ค.

๊ทธ๋ž˜ํ”„ ์บ์‹ฑ

GraphQL์„ ์บ์‹ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๊ณ„์ธต์ ์ธ ์‘๋‹ต์„ ํ”Œ๋žซํ•œ ๋ ˆ์ฝ”๋“œ ์ง‘ํ•ฉ์œผ๋กœ ์ •๊ทœํ™” ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

Relay๋Š” ์ด๋ ‡๊ฒŒ ์ •๊ทœํ™”ํ•œ ์บ์‹œ๋ฅผ ID์™€ Record๋ฅผ ๋งคํ•‘ํ•˜์—ฌ ์ €์žฅํ•œ๋‹ค

๊ฐ๊ฐ์˜ ๋ ˆ์ฝ”๋“œ๋Š” ํ•„๋“œ ์ด๋ฆ„์—์„œ ํ•„๋“œ ๊ฐ’์œผ๋กœ ๋งคํ•‘๋˜์–ด ์žˆ๋”ฐ.

๋ ˆ์ฝ”๋“œ๋Š” ๋‹ค๋ฅธ ๋ ˆ์ฝ”๋“œ๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์œผ๋ฉฐ, ์ด๋Š” ์ˆœํ™˜์ ์ธ ๊ทธ๋ž˜ํ”„๋ฅผ ๋ฌ˜์‚ฌํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋Ÿฌํ•œ ์—ฐ๊ฒฐ ๋งํฌ๋Š” ์ตœ์ƒ์œ„ ๋งต์„ ๋‹ค์‹œ ์ฐธ์กฐํ•˜๋Š” ๊ตฌ์ฒด์ ์ธ ํ‚ค ๊ฐ’์œผ๋กœ ์‚ฌ์šฉ๋œ๋‹ค.

์ด๋Ÿฌํ•œ ์ ‘๊ทผ ๋ฐฉ์‹์„ ์ด์šฉํ•ด, ๊ฐ๊ฐ์˜ ์„œ๋ฒ„ ๋ ˆ์ฝ”๋“œ๋Š” ์–ด๋–ป๊ฒŒ ํŒจ์น˜๋˜์—ˆ๋Š๋ƒ์— ๊ด€๊ณ„์—†์ด ๋‹จ ํ•œ ๋ฒˆ ์ €์žฅ๋œ๋‹ค.

์Šคํ† ๋ฆฌ ํ…์ŠคํŠธ์™€ ์ž‘๊ฐ€ ์ด๋ฆ„์„ ํŒจ์น˜ํ•˜๋Š” ์ฟผ๋ฆฌ๊ฐ€ ์žˆ๋‹ค๊ณ  ํ•ด๋ณด์ž.

query {
  story(id: "1") {
    text,
    author {
      name
    }
  }
}

๋‹ค์Œ์€ ์‘๋‹ต ๊ฒฐ๊ณผ์ด๋‹ค.

{
  "query": {
    "story": {
      "text": "Relay is open-source!",
      "author": {
        "name": "Jan"
      }
    }
  }
}

์‘๋‹ต ๊ฒฐ๊ณผ๋Š” ๊ณ„์ธต์ ์ผ ์ง€๋ผ๋„, GraphQL์€ ๋ชจ๋“  ๋ ˆ์ฝ”๋“œ๋ฅผ ํ‰๋ฉดํ™”ํ•˜์—ฌ ์บ์‹œํ•œ๋‹ค. Relay๊ฐ€ ์ด๋Ÿฌํ•œ ์ฟผ๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ์บ์‹œํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

Map {
  // `story(id: "1")`
  1: Map {
    text: 'Relay is open-source!',
    author: Link(2),
  },
  // `story.author`
  2: Map {
    name: 'Jan',
  },
};

์ด๊ฑด ๊ฐ„๋‹จํ•œ ์˜ˆ์‹œ์ด๊ณ , ์‹ค์ œ๋กœ ์บ์‹œ๋Š” 1:๋‹ค์˜ ๊ด€๊ณ„์™€ ํŽ˜์ด์ง€๋„ค์ด์…˜ ๋ฐ ๋‹ค๋ฅธ ๊ฒƒ๋“ค์„ ๋™์‹œ์— ํ•ธ๋“ค๋ง ํ•ด์•ผ ํ•œ๋‹ค.

์บ์‹œ ์‚ฌ์šฉํ•˜๊ธฐ

๊ทธ๋ž˜์„œ ์šฐ๋ฆฌ๋Š” ์ด๋Ÿฌํ•œ ์บ์‹œ๋ฅผ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์„๊นŒ?

์‘๋‹ต์„ ๋ฐ›์œผ๋ฉด ์บ์‹œ๋ฅผ ์“ฐ๊ณ , ์ฟผ๋ฆฌ๋ฅผ ์ง€์—ญ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ๊ฒฐ์ •ํ•˜๊ธฐ ์œ„ํ•ด ์บ์‹œ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๋Š”๋‹ค. (์ด๋Š” _cache.has(key) ์™€ ๋™์ผํ•˜์ง€๋งŒ, graph ์ƒ์—์„œ ์ž‘๋™ํ•œ๋‹ค.)

์บ์‹œ ๋ถ„ํฌ์‹œํ‚ค๊ธฐ

์บ์‹œ๋ฅผ ๋ถ„์‚ฐ์‹œํ‚ค๋Š” ๊ฒƒ์€ GraphQL ์‘๋‹ต์˜ ๊ณ„์ธต์„ ๋”ฐ๋ผ๊ฐ€๋ฉฐ ์ •๊ทœํ™”๋œ ์บ์‹œ ๋ ˆ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์—…๋ฐ์ดํŠธํ•˜๋Š” ๊ณผ์ •์„ ํฌํ•จํ•œ๋‹ค.

์ฒ˜์Œ์—๋Š”, ์‘๋‹ต ์ž์ฒด๋กœ์จ ์ถฉ๋ถ„ํ•ด ๋ณด์ด์ง€๋งŒ, ์ด๊ฒƒ์€ ๋งค์šฐ ๊ฐ„๋‹จํ•œ ์ฟผ๋ฆฌ์—๋งŒ ํ•ด๋‹นํ•œ๋‹ค.

user(id: "456") { photo(size: 32) { uri } }

์œ„์˜ ๊ฒฝ์šฐ์—์„œ photo ๋ฅผ ์–ด๋–ป๊ฒŒ ์ €์žฅํ• ๊นŒ?

photo ๋ฅผ ์บ์‹œ์˜ ํ•„๋“œ ์ด๋ฆ„์œผ๋กœ ์‚ฌ์šฉํ•˜๋ฉด ์ž‘๋™ํ•˜์ง€ ์•Š์„ ๊ฒƒ์ด๋‹ค. ์™œ๋ƒํ•˜๋ฉด ๋‹ค๋ฅธ ์ฟผ๋ฆฌ๋Š” ๊ฐ™์€ ํ•„๋“œ๋ฅผ ํŒจ์น˜ํ•˜์ง€๋งŒ ๋‹ค๋ฅธ ์ธ์ž๊ฐ’์„ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

ํŽ˜์ด์ง€๋„ค์ด์…˜์—์„œ๋„ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

stories(first: 10, offset: 10) ๋ฅผ ํ†ตํ•ด 11~20๋ฒˆ์˜ ์Šคํ† ๋ฆฌ๋ฅผ ํŒจ์น˜ํ•˜๋ฉด, ์ด ์ƒˆ๋กœ์šด ๊ฐ’์€ ์ด๋ฏธ ์กด์žฌํ•˜๋Š” ๋ฆฌ์ŠคํŠธ์— ๋ถ™์—ฌ์•ผ ํ•œ๋‹ค.

๊ทธ๋ž˜์„œ, ์ •๊ทœํ™”๋œ ์‘๋‹ต ์บ์‹œ๋Š” payload์™€ ์ฟผ๋ฆฌ๋ฅผ ๋ณ‘๋ ฌ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ณผ์ •์ด ํ•„์š”ํ•˜๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ์œ„์˜ photo ํ•„๋“œ๋Š” uniqueํ•œ ํ•„๋“œ์™€ ์ธ์ž๊ฐ’์„ ๊ตฌ๋ณ„ํ•ด๋‚ด๊ธฐ ์œ„ํ•ด photo_size(32) ์™€ ๊ฐ™์ด ์ƒ์„ฑ๋œ ํ•„๋“œ ์ด๋ฆ„๊ณผ ํ•จ๊ป˜ ์บ์‹œ๋œ๋‹ค.

์บ์‹œ ์ฝ๊ธฐ

์บ์‹œ๋กœ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•œ ํ›„ ๊ฐ ํ•„๋“œ๋ฅผ resolve ํ•˜๋ฉด ๋œ๋‹ค.

๊ทผ๋ฐ ์ด๊ฑด ์ •ํ™•ํžˆ GraphQL ์„œ๋ฒ„๊ฐ€ ์ฟผ๋ฆฌ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ณผ์ •๊ณผ ๋˜‘๊ฐ™์•„ ๋ณด์ธ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋งž๋‹ค!

์บ์‹œ๋กœ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๋Š” ๊ฒƒ์€

  1. ๋ชจ๋“  ๊ฒฐ๊ณผ๊ฐ€ ๊ณ ์ •๋œ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋กœ๋ถ€ํ„ฐ ์˜ค๊ธฐ ๋•Œ๋ฌธ์— user-defined ํ•„๋“œ ํ•จ์ˆ˜๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š๋‹ค.

  2. ๊ฒฐ๊ณผ๋Š” ํ•ญ์ƒ ๋™๊ธฐํ™”๋œ๋‹ค. - ๋ฐ์ดํ„ฐ๋Š” ์บ์‹œ๋˜์—ˆ๊ฑฐ๋‚˜ ๊ฐ€์ง€๊ณ  ์žˆ์ง€ ์•Š๋‹ค.

๋Š” ์ ์—์„œ ํŠน๋ณ„ํ•œ ์‹คํ–‰ ๊ณผ์ •์„ ์˜๋ฏธํ•œ๋‹ค.

Relay๋Š” Query traversal์„ ์œ„ํ•ด ์—ฌ๋Ÿฌ ์ดํ˜•์„ ๊ฐ–๊ณ  ์žˆ๋‹ค. Query traversal์ด๋ž€ ์ฟผ๋ฆฌ์™€ ํ•จ๊ป˜ ์บ์‹œ๋‚˜ ์‘๋‹ต payload์™€ ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋„ ๊ฒ€์‚ฌํ•˜๋Š” operation์„ ์˜๋ฏธํ•œ๋‹ค.

  1. ์˜ˆ๋ฅผ ๋“ค์–ด, ์ฟผ๋ฆฌ๊ฐ€ ํŒจ์น˜๋˜์—ˆ์„ ๋•Œ, Relay๋Š” diff traversal์„ ํ†ตํ•ด ์–ด๋–ค ํ•„๋“œ๊ฐ€ ๋น ์กŒ๋Š”์ง€ ๊ฒฐ์ •ํ•œ๋‹ค. (์ด๋Š” ๋ฆฌ์•กํŠธ๊ฐ€ ๊ฐ€์ƒ ๋” ํŠธ๋ฆฌ๋ฅผ ๋น„๊ตํ•˜๋Š” ๊ฒƒ๊ณผ ๋น„์Šทํ•˜๊ฒŒ ์ž‘๋™ํ•œ๋‹ค.)

    ์ด๋Š” ํŒจ์น˜๋œ ๋ฐ์ดํ„ฐ์˜ ์–‘์„ ์ค„์ด๊ณ  Relay๋กœ ํ•˜์—ฌ๊ธˆ ๋ชจ๋“  ์ฟผ๋ฆฌ๊ฐ€ ์บ์‹œ๋œ ์ƒํƒœ์—์„œ ๋ถˆํ•„์š”ํ•œ ๋„คํŠธ์›Œํฌ ์š”์ฒญ์„ ํ”ผํ•œ๋‹ค.

์บ์‹œ ์—…๋ฐ์ดํŠธ

์ด๋ ‡๊ฒŒ ์ •๊ทœํ™”๋œ ์บ์‹œ ๊ตฌ์กฐ๋Š” ๋ฐ˜๋ณต๋˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ์ค‘๋ณต ์—†์ด ์ฒ˜๋ฆฌํ•˜๋„๋ก ํ•œ๋‹ค.

๊ฐ๊ฐ์˜ ๋ ˆ์ฝ”๋“œ๋Š” ์–ด๋–ป๊ฒŒ ํŒจ์น˜๋˜์—ˆ๋Š”์ง€์™€ ๊ด€๊ณ„์—†์ด ๋‹จ ํ•œ ๋ฒˆ ์ €์žฅ๋œ๋‹ค.

์ผ์ •ํ•˜์ง€ ์•Š์€ ๋ฐ์ดํ„ฐ ์˜ˆ์‹œ๋ฅผ ํ†ตํ•ด ์ด๋Ÿฌํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ ์–ด๋–ป๊ฒŒ ์บ์‹œ๊ฐ€ ์ž‘๋™ํ•˜๋Š”์ง€ ๋ณด์ž.

์ฒซ๋ฒˆ์งธ ์ฟผ๋ฆฌ๋Š” ์Šคํ† ๋ฆฌ ๋ฆฌ์ŠคํŠธ์˜€๋‹ค:

query {
	stories { 
		id, 
		text, 
		likeCount 
	} 
} 

์ •๊ทœํ™”๋œ ์บ์‹œ ์‘๋‹ต์„ ํ†ตํ•ด, ๋ ˆ์ฝ”๋“œ๋Š” ๋ฆฌ์ŠคํŠธ์˜ ๊ฐ ์Šคํ† ๋ฆฌ๋งˆ๋‹ค ์ƒ์„ฑ๋œ๋‹ค.

stories ํ•„๋“œ๋Š” ์ด๋Ÿฌํ•œ ๋ ˆ์ฝ”๋“œ ๊ฐ๊ฐ์— ๋งํฌ๋œ๋‹ค.

๋‘๋ฒˆ์งธ ์ฟผ๋ฆฌ๋Š” ๊ทธ ์ค‘ ํ•˜๋‚˜์˜ ์Šคํ† ๋ฆฌ๋ฅผ refetch ํ•œ๋‹ค.

query {
	stories(id: "123") { 
		id, 
		text, 
		likeCount 
	} 
}

์ด๋Ÿฌํ•œ ์‘๋‹ต์ด ์ •๊ทœํ™” ๋˜๋ฉด, Relay๋Š” id ์— ๊ธฐ๋ฐ˜ํ•˜์—ฌ ์กด์žฌํ•˜๋Š” ๋ฐ์ดํ„ฐ์™€ ์ค‘๋ณต๋˜๋Š”์ง€ ๊ฐ์ง€ํ•œ๋‹ค.

์ƒˆ๋กœ์šด ๋ ˆ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค, Relay๋Š” ๊ธฐ์กด์˜ 123 ๋ ˆ์ฝ”๋“œ๋ฅผ ์—…๋ฐ์ดํŠธํ•œ๋‹ค.

์ƒˆ๋กœ์šด likeCount ๋Š” ์–‘ ์ชฝ์˜ ์ฟผ๋ฆฌ ๋ชจ๋‘์—์„œ ์ด์šฉ ๊ฐ€๋Šฅํ•˜๋ฉฐ, ํ•ด๋‹น ์Šคํ† ๋ฆฌ๋ฅผ ๋ชจ๋‘ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ฐ์ดํ„ฐ/ ๋ทฐ ์ผ๊ด€์„ฑ

์ •๊ทœํ™”๋œ ์บ์‹œ๋Š” ์บ์‹œ์˜ ์ผ์ •ํ•จ์„ ๋ณด์žฅํ•œ๋‹ค.

ํ•˜์ง€๋งŒ ๋ทฐ๋Š” ์–ด๋–จ๊นŒ?

์ด์ƒ์ ์œผ๋กœ๋Š”, React ๋ทฐ๋Š” ์บ์‹œ๋กœ๋ถ€ํ„ฐ ์ตœ์‹ ์˜ ์ •๋ณด๋ฅผ ํ•ญ์ƒ ๋ฐ˜์˜ํ•ด์•ผ ํ•œ๋‹ค.

์Šคํ† ๋ฆฌ์˜ ํ…์ŠคํŠธ์™€ ์ฝ”๋ฉ˜ํŠธ๋ฅผ ์ž‘๊ธฐ ์ด๋ฆ„, ์‚ฌ์ง„๊ณผ ํ•จ๊ป˜ ๋ Œ๋”๋งํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž. ์ด์— ๋Œ€ํ•œ GraphQL ์ฟผ๋ฆฌ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

query {
  story(id: "1") {
    text,
    author { name, photo },
    comments {
      text,
      author { name, photo }
    }
  }
}

์ด ์Šคํ† ๋ฆฌ๋ฅผ ์ดˆ๊ธฐ์— ํŒจ์นญํ•œ ํ›„์˜ ์บ์‹œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์„ ๊ฒƒ์ด๋‹ค. ์ด ๋•Œ ์Šคํ† ๋ฆฌ์™€ ์ฝ”๋ฉ˜ํŠธ๋Š” author ๊ณผ ๊ฐ™์€ ๋ ˆ์ฝ”๋“œ์™€ ์—ฐ๊ฒฐ๋œ๋‹ค๋Š” ๊ฒƒ์„ ๋ช…์‹ฌํ•˜์ž.

Map {
  // `story(id: "1")`
  1: Map {
    text: 'got GraphQL?',
    author: Link(2),
    comments: [Link(3)],
  },
  // `story.author`
  2: Map {
    name: 'Yuzhi',
    photo: 'http://.../photo1.jpg',
  },
  // `story.comments[0]`
  3: Map {
    text: 'Here\'s how to get one!',
    author: Link(2),
  },
}

์ด ์Šคํ† ๋ฆฌ์˜ ์ž‘๊ฐ€๋Š” ๋Œ“๊ธ€๋„ ๋‹ฌ์•˜์„ ๊ฒƒ์ด๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ๋‹ค๋ฅธ ๋ทฐ๊ฐ€ ์ด ์ž‘๊ฐ€์— ๋Œ€ํ•œ ์ƒˆ๋กœ์šด ์ •๋ณด๋ฅผ ํŒจ์น˜ํ–ˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•  ๋•Œ, ๊ทธ๋…€์˜ ํ”„๋กœํ•„ ์‚ฌ์ง„์ด ์ƒˆ๋กœ์šด URI๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ๋‹ค๊ณ  ํ•ด๋ณด์ž.

๋‹ค์Œ์€ ์บ์‹œ๋œ ๋ฐ์ดํ„ฐ์—์„œ ๋ณ€๊ฒฝ๋œ ์œ ์ผํ•œ ๋ถ€๋ถ„์ด๋‹ค.

Map {
  ...
  2: Map {
    ...
    photo: 'http://.../photo2.jpg',
  },
}

photo ํ•„๋“œ ๊ฐ’์€ ๋ณ€๊ฒฝ๋˜์—ˆ๊ณ , ๋”ฐ๋ผ์„œ ๋ ˆ์ฝ”๋“œ 2 ๋˜ํ•œ ๋ณ€๊ฒฝ๋˜์—ˆ๋‹ค๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด๊ฒŒ ์ „๋ถ€๋‹ค!

๋‹ค๋ฅธ ์บ์‹œ ์ •๋ณด๋Š” ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๋Š”๋‹ค.

ํ•˜์ง€๋งŒ ์šฐ๋ฆฌ ๋ทฐ๋Š” ์ด๋Ÿฌํ•œ ์—…๋ฐ์ดํŠธ๋ฅผ ๋ฐ˜์˜ํ•ด์•ผ ํ•œ๋‹ค: UI์˜ ์Šคํ† ๋ฆฌ์™€ ์ฝ”๋ฉ˜ํŠธ ๋ชจ๋‘์—์„œ ์ž‘๊ฐ€์˜ ์ƒˆ๋กœ์šด ์‚ฌ์ง„์„ ๋ณด์—ฌ์ค˜์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์ผ๋ฐ˜์ ์ธ ๋‹ต์€ โ€œimmutable data structure๋ฅผ ์ด์šฉํ•˜๋ผโ€ ์ผ ๊ฒƒ์ด๋‹ค. ํ•˜์ง€๋งŒ ๊ทธ๋ ‡๊ฒŒ ํ•  ์‹œ,

ImmutableMap {
  1: ImmutableMap // same as before
  2: ImmutableMap {
    ... // other fields unchanged
    photo: 'http://.../photo2.jpg',
  },
  3: ImmutableMap // same as before
}

2 ๋ฅผ ์ƒˆ๋กœ์šด immutable ๋ ˆ์ฝ”๋“œ๋กœ ๋Œ€์ฒดํ•œ๋‹ค๋ฉด, ์บ์‹œ ๊ฐ์ฒด์— ๋Œ€ํ•œ ์ƒˆ๋กœ์šด immutable ์ธ์Šคํ„ด์Šค๋ฅผ ์–ป๊ฒŒ ๋  ๊ฒƒ์ด๋‹ค. ํ•˜์ง€๋งŒ ๋ ˆ์ฝ”๋“œ 1 ๊ณผ 3 ์€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š”๋‹ค.

๋ฐ์ดํ„ฐ๊ฐ€ ์ •๊ทœํ™”๋˜์—ˆ๊ธฐ(์ค‘๋ณต์ด ์ œ๊ฑฐ๋˜์—ˆ๊ธฐ) ๋•Œ๋ฌธ์—, story ๋งŒ ๋ณด๊ณ ์„œ๋Š” ์Šคํ† ๋ฆฌ์˜ ์ปจํ…์ธ  ๋˜ํ•œ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•˜๋‹ค๊ณ  ํ™•์‹ ํ•  ์ˆ˜ ์—†๋‹ค.

๋ทฐ ์ผ๊ด€์„ฑ ๋‹ฌ์„ฑํ•˜๊ธฐ

ํ‰๋ฉดํ™”๋œ ์บ์‹œ๋ฅผ ์ด์šฉํ•ด ๋ทฐ๋ฅผ ์ตœ์‹  ๋ฒ„์ „์œผ๋กœ ์—…๋ฐ์ดํŠธ ํ•  ์ˆ˜ ์žˆ๋Š” ๋‹ค์–‘ํ•œ ํ•ด๊ฒฐ์ฑ…์ด ์กด์žฌํ•œ๋‹ค.

Relay๋Š” ๊ฐ๊ฐ์˜ UI ๋ทฐ์™€ ๋ทฐ๊ฐ€ ์ฐธ์กฐํ•˜๋Š” ID ์„ธํŠธ๋ฅผ ๋งคํ•‘ํ•˜์—ฌ ์œ ์ง€ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ฑ„ํƒํ•œ๋‹ค.

์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ, ์Šคํ† ๋ฆฌ ๋ทฐ๋Š” ์Šคํ† ๋ฆฌ์™€ ์ž‘๊ฐ€, ๊ทธ๋ฆฌ๊ณ  ์ฝ”๋ฉ˜ํŠธ ๋“ฑ์ด ์—…๋ฐ์ดํŠธ ๋˜์—ˆ๋Š”์ง€ ๊ตฌ๋…ํ•  ๊ฒƒ์ด๋‹ค.

๋ฐ์ดํ„ฐ๋ฅผ ์บ์‹œ์— ์“ธ ๋•Œ, Relay๋Š” ์–ด๋–ค ID๊ฐ€ ์˜ํ–ฅ์„ ๋ฐ›๋Š”์ง€ ํŠธ๋ž˜ํ‚นํ•˜๊ณ  ์˜ํ–ฅ์„ ๋ฐ›๋Š” ID์™€ ์—ฐ๊ด€๋œ ๋ทฐ์—๊ฒŒ๋งŒ notify ํ•  ๊ฒƒ์ด๋‹ค.

์ด๋ ‡๊ฒŒ ์˜ํ–ฅ์„ ๋ฐ›๋Š” ๋ทฐ๋Š” ๋ฆฌ๋ Œ๋”๋ง ๋˜๊ณ , ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๋Š” ๋ทฐ๋Š” ์„ฑ๋Šฅ ํ–ฅ์ƒ์„ ์œ„ํ•ด ๋ฆฌ๋ Œ๋”๋ง์„ ํ•˜์ง€ ์•Š๋Š”๋‹ค. (Relay๋Š” ์•ˆ์ „ํ•˜์ง€๋งŒ ํšจ๊ณผ์ ์ธ shouldComponentUpdate ๋ฅผ ๊ธฐ๋ณธ์œผ๋กœ ์ œ๊ณตํ•œ๋‹ค.)

์ด๋Ÿฌํ•œ ์ „๋žต ์—†์ด๋Š” ๋ชจ๋“  ๋ทฐ๊ฐ€ ์ž‘์€ ๋ณ€ํ™”์—๋„ ๋ฆฌ๋ Œ๋”๋ง ๋  ๊ฒƒ์ด๋‹ค.

์บ์‹œ๊ฐ€ ์—…๋ฐ์ดํŠธ ๋  ๋•Œ ์˜ํ–ฅ์„ ๋ฐ›๋Š” ๋ทฐ์— notify ํ•˜๊ณ , write๋Š” ๊ทธ๋ ‡๊ฒŒ ์บ์‹œ๋ฅผ ์—…๋ฐ์ดํŠธ ํ•˜๋Š” ํ•˜๋‚˜์˜ ๋ฐฉ๋ฒ•์ด๊ธฐ ๋•Œ๋ฌธ์—, ์ด๋Ÿฌํ•œ ํ•ด๊ฒฐ์ฑ…์€ ์บ์‹œ๋ฅผ ์ž‘์„ฑํ•จ์— ์žˆ์–ด์„œ๋„ ์ ์šฉ๋œ๋‹ค.

Mutations

์ง€๊ธˆ๊นŒ์ง€๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ฟผ๋ฆฌํ•˜๊ณ  ๋ทฐ๋ฅผ ์ตœ์‹  ๋ฒ„์ „์œผ๋กœ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๊ณผ์ •์„ ๋ณด์•˜์ง€๋งŒ, write์— ๋Œ€ํ•ด์„œ๋Š” ์•Œ์•„๋ณด์ง€ ์•Š์•˜๋‹ค.

GraphQL์—์„œ๋Š”, write๋ฅผ mutation ์ด๋ผ ์นญํ•œ๋‹ค.

์ด๋Š” side effect๊ฐ€ ์žˆ๋Š” ์ฟผ๋ฆฌ๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค.

๋‹ค์Œ์€ ํŠน์ • ์Šคํ† ๋ฆฌ๊ฐ€ ํ˜„์žฌ ์œ ์ €์— ์˜ํ•ด liked๋œ ์ƒํƒœ๋ฅผ ํ‘œ์‹œํ•˜๋Š” mutation์„ ๋ฐœ์ƒ์‹œํ‚ค๋Š” ์˜ˆ์ œ์ด๋‹ค.

mutation StoryLike($storyID: String) {
	// mutation ํ•  ํ•„๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ๋ณ€๊ฒฝํ•  side effect๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค.
   storyLike(storyID: $storyID) {
		// mutation ์‹คํ–‰ ์ดํ›„ re-ํŒจ์น˜ํ•  ํ•„๋“œ๋ฅผ ์ •์˜ํ•œ๋‹ค.
     likeCount
   }
}

์ด๋Š” mutation์˜ ๊ฒฐ๊ณผ๋กœ ๋ณ€๊ฒฝ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฟผ๋ฆฌํ•˜๋Š” ๊ฒƒ์ž„์„ ๋ช…์‹ฌํ•˜์ž.

๊ทธ๋ ‡๋‹ค๋ฉด ๋ช…๋ฐฑํ•œ ์งˆ๋ฌธ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค:

์™œ ์„œ๋ฒ„๋Š” ์–ด๋–ค ๊ฒƒ์ด ๋ณ€๊ฒฝ๋๋Š”์ง€ ๊ทธ๋ƒฅ ์•Œ๋ ค์ฃผ์ง€ ์•Š๋Š”๊ฐ€?

๋‹ต์€:

๋ณต์žกํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

GraphQL๋Š” ์—ฌ๋Ÿฌ ์†Œ์Šค์˜ ์ง‘ํ•ฉ์ด๋‚˜ ๋ฐ์ดํ„ฐ storage layer๋ฅผ ์ถ”์ƒํ™” ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ๋ชจ๋“  ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์™€ ์ž‘์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ฒŒ๋‹ค๊ฐ€, GraphQL์˜ ๋ชฉ์ ์€ ํ”„๋กœ๋•ํŠธ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋ทฐ๋ฅผ ์™„์„ฑํ•˜๋Š”๋ฐ ์œ ์šฉํ•œ ํ˜•ํƒœ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ณตํ•จ์— ์žˆ๋‹ค.

GraphQL ์Šคํ‚ค๋งˆ๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ์–ด๋–ค ๋””์Šคํฌ์— ์ €์žฅ๋˜์–ด ์žˆ๋Š”์ง€์— ๋”ฐ๋ผ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๋‹ค.

๊ฐ„๋‹จํžˆ ๋งํ•ด์„œ: ๋ฐ์ดํ„ฐ๊ฐ€ ์ €์žฅ๋˜์–ด ์žˆ๋Š” ์ €์žฅ์†Œ (๋””์Šคํฌ) ์™€ product-visible ์Šคํ‚ค๋งˆ (GraphQL) ๋Š” 1:1๋กœ ๋งค์นญ๋˜์ง€ ์•Š๋Š”๋‹ค.

์ด๋ฅผ ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ๋Š” ์™„๋ฒฝํ•œ ์˜ˆ์‹œ๋Š” ํ”„๋ผ์ด๋ฒ„์‹œ์ด๋‹ค: age ์™€ ๊ฐ™์ด ์œ ์ €์— ๋Œ€ํ•œ ํ•„๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒฝ์šฐ, ํ˜„์žฌ ํ™œ์„ฑํ™”๋œ ์œ ์ €๊ฐ€ ๊ทธ age ํ•„๋“œ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋Š”์ง€ ๊ฒฐ์ •ํ•˜๊ธฐ ์œ„ํ•ด data-storage ๋ ˆ์ด์–ด์— ์ €์žฅ๋œ ์ˆ˜๋งŽ์€ ๋ ˆ์ฝ”๋“œ์— ์ ‘๊ทผํ•ด์•ผ ํ•œ๋‹ค. (์นœ๊ตฌ์ธ๊ฐ€? ๋‚˜์ด๊ฐ€ ๊ณต์œ ๋˜๋Š”๊ฐ€? ์ฐจ๋‹จํ–ˆ๋Š”๊ฐ€? ๋“ฑ์„ ๊ณ ๋ คํ•ด์•ผ ํ•จ.)

์ด๋Ÿฌํ•œ ํ˜„์‹ค์ ์ธ ์ œ์•ฝ์„ ๊ณ ๋ คํ–ˆ์„ ๋•Œ, GraphQL ์ ‘๊ทผ๋ฒ•์€ mutation ์ดํ›„์— ๋ณ€๊ฒฝ๋  ๋ฐ์ดํ„ฐ๋ฅผ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ฟผ๋ฆฌํ•˜๊ธฐ์— ์ ํ•ฉํ•˜๋‹ค.

ํ•˜์ง€๋งŒ ์ •ํ™•ํžˆ ์ฟผ๋ฆฌ์— ๋ฌด์—‡์„ ๋„ฃ์–ด์•ผ ํ• ๊นŒ?

Relay๋ฅผ ๊ฐœ๋ฐœํ•˜๋Š” ๋™์•ˆ ์—ฌ๋Ÿฌ ์•„์ด๋””์–ด๊ฐ€ ์žˆ์—ˆ๋‹ค - ์™œ Relay๊ฐ€ ์ด๋Ÿฌํ•œ ์ ‘๊ทผ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋Š”์ง€ ๊ณ ๋ คํ–ˆ๋˜ ์—ฌ๋Ÿฌ ์˜ต์…˜๋“ค์„ ํ†ตํ•ด ๊ฐ„๋‹จํžˆ ์•Œ์•„๋ณด์ž:

  • ์•ฑ์ด ์ฟผ๋ฆฌํ–ˆ๋˜ ๋ชจ๋“  ์ •๋ณด๋ฅผ re-ํŒจ์น˜ํ•œ๋‹ค. ๋ฐ์ดํ„ฐ์˜ ์ž‘์€ subset์ด ๋ณ€๊ฒฝ๋˜์—ˆ๋‹ค ํ•˜๋”๋ผ๋„, ์„œ๋ฒ„๊ฐ€ ์ „์ฒด ์ฟผ๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ๋‹ค์šด๋ฐ›๊ณ , ์ด ๊ณผ์ •์„ ๋ฐ˜๋ณตํ•˜๊ธฐ๊นŒ์ง€ ๊ธฐ๋‹ค๋ ค์•ผ ํ•œ๋‹ค. ๋งค์šฐ ๋น„ํšจ์œจ์ ์ธ ๋ฐฉ์•ˆ์ด๋‹ค.

  • ํ˜„์žฌ ํ™œ์„ฑํ™”๋œ ๋ Œ๋”๋ง ๋ทฐ์—์„œ ํ•„์š”๋กœ ํ•˜๋Š” ์ฟผ๋ฆฌ๋งŒ ๋‹ค์‹œ ํŒจ์น˜ํ•œ๋‹ค. ์˜ต์…˜1๋ณด๋‹ค ์•ฝ๊ฐ„์˜ ํ–ฅ์ƒ์€ ๊ธฐ๋Œ€ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์•„์ง๊นŒ์ง€ ํ™•์ธํ•˜์ง€ ์•Š์•˜๋˜ ๋ฐ์ดํ„ฐ ์ค‘ ์บ์‹œ๋œ ๋ฐ์ดํ„ฐ๋Š” ์—…๋ฐ์ดํŠธ ๋˜์ง€ ์•Š๋Š”๋‹ค. ์ด ๋ฐ์ดํ„ฐ๊ฐ€ ์–ด๋–ป๊ฒŒ๋“  ๋ณ€๊ฒฝ๋˜์—ˆ๋‹ค๊ณ  ํ‘œ์‹œ๋˜์ง€ ์•Š๋Š” ํ•œ, ์ดํ›„์˜ ์ฟผ๋ฆฌ๋Š” ๊ตฌ์‹์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์„ ๊ฒƒ์ด๋‹ค.

  • mutation ์ดํ›„์— ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ๋Š” ๊ณ ์ •๋œ ๋ฆฌ์ŠคํŠธ์˜ ํ•„๋“œ ๊ฐ’๋“ค๋งŒ์„ ๋‹ค์‹œ ํŒจ์น˜ํ•œ๋‹ค. ์ด๋ฅผ fat query ๋ผ๊ณ  ํ•œ๋‹ค. ์ „ํ˜•์ ์ธ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๊ฒฝ์šฐ ์ด ์ค‘ ์ผ๋ถ€๋งŒ์„ ๋ Œ๋”๋งํ•˜์ง€๋งŒ, ์ด ์ ‘๊ทผ๋ฒ•์€ ๋ชจ๋“  ํ•„๋“œ๋ฅผ ํŒจ์นญํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋น„ํšจ์œจ์ ์ด๋‹ค. (๋‹ค์‹œ ํŒจ์นญํ•œ ๊ฐ’ ์ค‘ ์‚ฌ์šฉํ•˜์ง€ ์•Š์„ ๊ฐ’๋“ค์ด ๋งŽ์„ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Œ.)

  • ์–ด๋–ค ๊ฒƒ์ด ๋ณ€ํ• ์ง€์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ๋‹ด์€ ๊ต์ฐจ๋ถ€๋ถ„๊ณผ ์บ์‹œ์˜ ๋ฐ์ดํ„ฐ๋งŒ์„ ๋‹ค์‹œ ํŒจ์นญํ•œ๋‹ค. (fat query) ์—ฌ๊ธฐ์— ๋”ํ•ด์„œ, Relay๋Š” ๊ฐ ์•„์ดํ…œ์„ ํŒจ์น˜ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋œ ์ฟผ๋ฆฌ ๋˜ํ•œ ๊ธฐ์–ตํ•œ๋‹ค. ์ด๋ฅผ tracked queries ๋ผ๊ณ  ์ผ์ปซ๋Š”๋‹ค. ์ด๋Ÿฌํ•œ tracked & fat queries ์˜ ๊ต์ง‘ํ•ฉ์„ ์ด์šฉํ•ด, Relay๋Š” ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์—…๋ฐ์ดํŠธ ํ•  ์ •๋ณด๋งŒ์„ ์ฟผ๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ฐ์ดํ„ฐ ํŒจ์นญ APIs

์ง€๊ธˆ๊นŒ์ง€ ๋ฐ์ดํ„ฐ ํŒจ์นญ์„ ์œ„ํ•œ ์ €๋ ˆ๋ฒจ ์ธก๋ฉด๊ณผ ์ต์ˆ™ํ•œ ์—ฌ๋Ÿฌ ์ปจ์…‰์ด ์–ด๋–ป๊ฒŒ GraphQL๋กœ ๋ณ€ํ™˜๋˜์—ˆ๋Š”์ง€ ์•Œ์•„๋ณด์•˜๋‹ค.

๋‹ค์Œ๋ฒˆ์—”, ๊ณ ์ฐจ์›์ ์ธ ๊ฐœ๋…์„ ํ†ตํ•ด ํ”„๋กœ๋•ํŠธ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋ฐ์ดํ„ฐ ํŒจ์นญ์„ ํ•˜๋Š” ๊ณผ์ •์—์„œ ์ง๋ฉดํ•˜๋Š” ์—ฌ๋Ÿฌ ๋ฌธ์ œ๋ฅผ ์•Œ์•„๋ณด์ž:

  • ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ๋ทฐ ๊ณ„์ธต์˜ ์ธก๋ฉด์—์„œ ํŒจ์นญํ•œ๋‹ค.

  • ๋น„๋™๊ธฐ์ ์ธ ์ƒํƒœ ์ด์ „๊ณผ ๋™์‹œ๋‹ค๋ฐœ์ ์ธ ์š”์ฒญ์„ ๊ด€๋ฆฌํ•œ๋‹ค.

  • ์—๋Ÿฌ๋ฅผ ์ปจํŠธ๋กคํ•œ๋‹ค.

  • ์‹คํŒจํ•œ ์š”์ฒญ์„ ๋‹ค์‹œ ์š”์ฒญํ•œ๋‹ค.

  • query/ mutation ์‘๋‹ต์„ ๋ฐ›์€ ํ›„์˜ ์ง€์—ญ ์บ์‹œ๋ฅผ ์—…๋ฐ์ดํŠธํ•œ๋‹ค.

  • race condition์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด mutation์„ ํ์ž‰ํ•œ๋‹ค.

  • ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ mutation์— ๋Œ€ํ•œ ์‘๋‹ต์„ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋™์•ˆ UI ์—…๋ฐ์ดํŠธ๋ฅผ ์ตœ์ ํ™”ํ•œ๋‹ค.

imperative API๋ฅผ ์ด์šฉํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ํŒจ์นญํ•˜๋Š” ์ „ํ˜•์ ์ธ ๋ฐฉ๋ฒ•์€ ๊ฐœ๋ฐœ์ž๋กœ ํ•˜์—ฌ๊ธˆ ๋ถˆํ•„์š”ํ•˜๊ฒŒ ๋†’์€ ๋ณต์žก์„ฑ์„ ๊ฐ๋‹นํ•˜๋„๋ก ํ•œ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, UI ์—…๋ฐ์ดํŠธ๋ฅผ ์ตœ์ ํ™”ํ•˜๋Š” ๊ฒƒ์„ ์ƒ๊ฐํ•ด๋ณด์ž.

์ด๋Š” ์„œ๋ฒ„ ์‘๋‹ต์„ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋™์•ˆ ์œ ์ €์—๊ฒŒ ํ”ผ๋“œ๋ฐฑ์„ ์ฃผ๋Š” ๊ฒƒ์ด ๋  ์ˆ˜ ์žˆ๋‹ค.

์–ด๋–ค ๊ฒƒ์„ ํ•ด์•ผํ•˜๋Š”์ง€๋Š” ๊ฝค ๋ถ„๋ช…ํ•˜๋‹ค: ์œ ์ €๊ฐ€ โ€œlikeโ€ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด, ์Šคํ† ๋ฆฌ๋ฅผ liked ์ฒ˜๋ฆฌํ•˜๊ณ  ์„œ๋ฒ„์— ์š”์ฒญ์„ ๋ณด๋‚ธ๋‹ค.

ํ•˜์ง€๋งŒ ๊ตฌํ˜„์€ ๋ณดํ†ต ๋” ๋ณต์žกํ•˜๋‹ค.

UI์— ๋„๋‹ฌํ•œ ํ›„ ๋ฒ„ํŠผ์„ ํ† ๊ธ€ํ•˜๊ณ , ๋„คํŠธ์›Œํฌ ์š”์ฒญ์„ ๊ฐœ์‹œํ•˜๊ณ  ํ•„์š”ํ•  ๊ฒฝ์šฐ ์ด๋ฅผ ๋‹ค์‹œ ์‹œ๋„ํ•˜๋ฉฐ, ๋งŒ์•ฝ ์‹คํŒจํ•  ์‹œ ์—๋Ÿฌ๋ฅผ ๋ณด์—ฌ์ค˜์•ผ ํ•œ๋‹ค. ๋˜ ๋ฒ„ํŠผ์„ ์–ธํ† ๊ธ€ํ•ด์•ผ ํ•œ๋‹ค. ๋“ฑ๋“ฑ์ด ์žˆ๋‹ค.

๋ฐ์ดํ„ฐ ํŒจ์น˜๋„ ์œ„์™€ ๋™์ผํ•˜๋‹ค: ์–ด๋–ค ๋ฐ์ดํ„ฐ๋ฅผ ํ•„์š”๋กœ ํ•˜๋Š”์ง€ ๊ตฌ์ฒดํ™”ํ•˜๋Š” ๊ฒƒ์€ ๋ณดํ†ต ์–ด๋–ป๊ฒŒ, ์–ธ์ œ ๋ฐ์ดํ„ฐ๊ฐ€ ํŒจ์น˜๋˜๋Š”์ง€ ๋‚˜ํƒ€๋‚ด์•ผ ํ•œ๋‹ค.

์ด๋Ÿฌํ•œ ๊ณ ๋ฏผ์„ Relay๋กœ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ๋‹ค์Œ ์žฅ์—์„œ ์•Œ์•„๋ณผ ๊ฒƒ์ด๋‹ค.

To be continued...

Last updated