Front End/Web

GraphQL

๐ŸŒ

GraphQL

GraphQL์€ ํŽ˜์ด์Šค๋ถ์—์„œ ๋งŒ๋“  ์˜คํ”ˆ ์†Œ์Šค ์ฟผ๋ฆฌ ์–ธ์–ด์ด๋‹ค. Graph + Query Language์˜ ์ค„์ž„๋ง๋กœ Server API๋ฅผ ํ†ตํ•ด ์ •๋ณด๋ฅผ ์ฃผ๊ณ ๋ฐ›๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” Query Language๋ฅผ ๋œปํ•œ๋‹ค. ์‰ฝ๊ฒŒ ๋งํ•ด API๋ฅผ ์œ„ํ•œ ์ฟผ๋ฆฌ ์–ธ์–ด๋กœ, 2016๋…„ ์ฒ˜์Œ ๋“ฑ์žฅํ•ด ํ˜„์žฌ๊นŒ์ง€ ์ธ์ง€๋„ ๋ฐ ๋งŒ์กฑ ๋ถ€๋ถ„์—์„œ ๋†’์€ ๋น„์œจ์„ ์ฐจ์ง€ํ•˜๊ณ  ์žˆ๋‹ค.

Graph๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ 

GraphQL์€ ๊ทธ๋ž˜ํ”„๋กœ ์ƒ๊ฐํ•œ๋‹ค๋Š” ์•„์ด๋””์–ด์—์„œ ์ถœ๋ฐœํ–ˆ๋‹ค. ๊ทธ๋ž˜ํ”„๋ผ๋Š” ์ž๋ฃŒ๊ตฌ์กฐ๋Š” ์ธ๊ฐ„์˜ ๋‡Œ ๊ตฌ์กฐ ๋ฐ ์–ธ์–ด์ ์ธ ์„ค๋ช…๊ณผ ๋น„์Šทํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์ œ ํ˜„์‹ค ์„ธ๊ณ„์˜ ๋งŽ์€ ํ˜„์ƒ๋“ค์„ ๋ชจ๋ธ๋งํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ์ด๋‹ค. ๊ทธ๋ž˜ํ”„ ์ž๋ฃŒ ๊ตฌ์กฐ๋ฅผ ์‚ดํŽด๋ณด๋ฉด ํŠน์ • ๊ฐœ๋…์„ ํ•™์Šตํ•˜๊ณ  ์—ฐ๊ด€์‹œํ‚ฌ๋•Œ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์‚ฌ์šฉํ•˜๋Š” ๋งˆ์ธ๋“œ๋งต๊ณผ ์œ ์‚ฌํ•œ ๋ฐ์ดํ„ฐ๊ตฌ์กฐ์ž„์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋ž˜ํ”„๋Š” ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ ๋“ค์ด ์„œ๋กœ ๋ณต์žกํ•˜๊ฒŒ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋Š” ๊ด€๊ณ„๋ฅผ ํ‘œํ˜„ํ•œ ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ๋œปํ•œ๋‹ค. ๊ฐ ๋…ธ๋“œ(์ •์ )๊ฐ„์˜ ๊ด€๊ณ„๊ฐ€ ์ง์ ‘์ ์ด๋ผ๋ฉด ๊ฐ„์„ ์œผ๋กœ ์—ฐ๊ฒฐ๋˜๊ณ , ๊ฐ„์ ‘์ ์ธ ๊ด€๊ณ„๋ผ๋ฉด ๋ช‡๊ฐœ์˜ ๋…ธ๋“œ์™€ ์„ ์— ๊ฑธ์ณ ์ด์–ด์ง„๋‹ค. ๋˜ํ•œ ๊ฐ ๋…ธ๋“œ๊ฐ„์˜ ๊ฐ„์„ ์„ ํ†ตํ•ด ํŠน์ •ํ•œ ์ˆœ์„œ์— ๋”ฐ๋ผ ๊ทธ๋ž˜ํ”„๋ฅผ ์žฌ๊ท€์ ์œผ๋กœ ํƒ์ƒ‰ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

๊ทธ๋ž˜ํ”„์™€ ํŠธ๋ฆฌ ์ž๋ฃŒ๊ตฌ์กฐ๋Š” ์—ฐ๊ฒฐ์ด ๊ณ„์ธต์ ์ธ์ง€ ์•„๋‹Œ์ง€์— ๋”ฐ๋ผ ์ฐจ์ด๊ฐ€ ๋“œ๋Ÿฌ๋‚œ๋‹ค.

GraphQL์—์„œ๋Š” ๋ชจ๋“  ๋ฐ์ดํ„ฐ๊ฐ€ ๊ทธ๋ž˜ํ”„ ํ˜•ํƒœ๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋‹ค๊ณ  ์ „์ œํ•œ๋‹ค. ์ผ๋Œ€์ผ๋กœ ์—ฐ๊ฒฐ๋˜์–ด๋„, ์—ฌ๋Ÿฌ ๊ณ„์ธต(ํŠธ๋ฆฌ ๊ตฌ์กฐ)์œผ๋กœ ์ด๋ฃจ์–ด์ ธ๋„ ๋…ธ๋“œ์™€ ๋…ธ๋“œ๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” ๊ฐ„์„ ์œผ๋กœ ๊ตฌ์„ฑ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ชจ๋‘ ๊ทธ๋ž˜ํ”„์ด๋‹ค. ๋‹จ์ง€ ๊ทธ ๊ทธ๋ž˜ํ”„๋ฅผ ๋ˆ„๊ตฌ์˜ ์ž…์žฅ์—์„œ ์ •๋ ฌํ•˜๋Š๋ƒ, ์ฆ‰ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์–ด๋–ค ๋ฐ์ดํ„ฐ๋ฅผ ํ•„์š”๋กœ ํ•˜๋Š๋ƒ์— ๋”ฐ๋ผ ํŠธ๋ฆฌ ๊ตฌ์กฐ๋ฅผ ์ด๋ฃฐ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.

ํŠธ๋ฆฌ ๊ตฌ์กฐ๋กœ ์ •๋ ฌ๋œ ๊ทธ๋ž˜ํ”„์™€ GraphQL

์ด๋ฅผ ํ†ตํ•ด GraphQL์€ ํด๋ผ์ด์–ธํŠธ์˜ ์š”์ฒญ์— ๋”ฐ๋ผ ์œ ์—ฐํ•˜๊ฒŒ ํŠธ๋ฆฌ ๊ตฌ์กฐ์˜ JSON ๋ฐ์ดํ„ฐ๋ฅผ ์‘๋‹ต์œผ๋กœ ์ „์†กํ•  ์ˆ˜ ์žˆ๋‹ค. ๋‹ค์‹œ ๋งํ•ด GraphQL์€ REST API ๋ฐฉ์‹์˜ ๊ณ ์ •๋œ ์ž์›์ด ์•„๋‹Œ ํด๋ผ์ด์–ธํŠธ ์š”์ฒญ์— ๋”ฐ๋ผ ์œ ์—ฐํ•˜๊ฒŒ ์ž์›์„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค๋Š” ์ด์ ์„ ๊ฐ–๋Š”๋‹ค.

GraphQL๋กœ ๊ทธ๋ž˜ํ”„ ์ˆœํšŒ

GraqhQL๋กœ ๊ทธ๋ž˜ํ”„๋ฅผ ์ˆœํšŒํ•˜๊ธฐ ์œ„ํ•ด ๋„์„œ๊ด€์˜ ๋„์„œ ๋ชฉ๋ก ์‹œ์Šคํ…œ์„ ๊ตฌ์ถ•ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•œ๋‹ค๋ฉด, ํ•˜๋‚˜์˜ ๋„์„œ ๋ชฉ๋ก์—๋Š” ๋งŽ์€ ์ฑ…๊ณผ ์ €์ž๊ฐ€ ์žˆ์„ ๊ฒƒ์ด๋ฉฐ ๊ฐ ์ฑ…์—๋Š” ์ตœ์†Œ ํ•œ ๋ช…์˜ ์ €์ž, ๊ทธ๋ฆฌ๊ณ  ์ตœ์†Œํ•œ ํ•œ ๊ถŒ์˜ ์ฑ…์„ ๊ฐ™์ด ์“ด ๊ณต๋™์ €์ž๋„ ์žˆ์„ ๊ฒƒ์ด๋‹ค.

์œ„์˜ ๊ทธ๋ž˜ํ”„๋Š” ๋ฐฉ๊ธˆ์˜ ๊ฐ€์ •์„ ๊ทธ๋ž˜ํ”„ ํ˜•ํƒœ๋กœ ์‹œ๊ฐํ™”ํ•œ ๊ฒƒ์ด๋‹ค. ์ด๋ ‡๊ฒŒ ๊ทธ๋ž˜ํ”„๋กœ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์šฐ๋ฆฌ๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๋ฐ์ดํ„ฐ์˜ ์กฐ๊ฐ๋“ค์ด๋‚˜ ๋‚˜ํƒ€๋‚ด๊ณ ์ž ํ•˜๋Š” ์—”ํ‹ฐํ‹ฐ(์ฑ…, ์ €์ž) ๊ฐ„์˜ ๊ด€๊ณ„๋ฅผ ๋‚˜ํƒ€๋‚ผ ์ˆ˜ ์žˆ๊ณ , GraphQL์„ ์‚ฌ์šฉํ•ด ํŠธ๋ฆฌ๋ฅผ ์ถ”์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.

โ“
์—”ํ‹ฐํ‹ฐ๋Š” ์‚ฌ๋ฌผ์˜ ๊ตฌ์กฐ๋‚˜ ์ƒํƒœ, ๋™์ž‘ ๋“ฑ์„ ๋ชจ๋ธ๋กœ ํ‘œํ˜„ํ•  ๋•Œ ๋ชจ๋ธ์˜ ๊ตฌ์„ฑ์š”์†Œ๋ฅผ ๋งํ•œ๋‹ค. ์ •๋ณด์˜ ์ธก๋ฉด์—์„œ ๋ณผ ๋•Œ ์—”ํ‹ฐํ‹ฐ๋Š” ๊ทธ ์ž์ฒด๋งŒ์œผ๋กœ ์ค‘์š”ํ•œ ์˜๋ฏธ๋ฅผ ํ‘œํ˜„ํ•˜์ง€ ๋ชปํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‹จ๋…์œผ๋กœ ์กด์žฌํ•˜์ง„ ๋ชปํ•˜์ง€๋งŒ, ํŠน์ •ํ•œ ๊ฐ์ฒด๋ฅผ ๊ตฌ์„ฑํ•ด์„œ ํ‘œํ˜„ํ•  ๋•Œ๋Š” ํฐ ์˜๋ฏธ๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋‹ค. โ‡’ ex. โ€œํ•™์ƒโ€ ์ด๋ผ๋Š” ๊ฐ์ฒด : ํ•™๋ฒˆ, ์ด๋ฆ„, ํ•™๊ณผ ๋“ฑ

๊ทธ๋ž˜ํ”„์—์„œ ํŠธ๋ฆฌ๋ฅผ ์ถ”์ถœํ•˜๋Š” ๋ฐฉ๋ฒ•

๊ธฐ๋ณธ์ ์œผ๋กœ ํŠธ๋ฆฌ๋Š” ๋ฐฉํ–ฅ์„ฑ์€ ์กด์žฌํ•˜๋‚˜ ์‚ฌ์ดํด์€ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋น„์ˆœํ™˜ ๊ทธ๋ž˜ํ”„์ด๋‹ค. ๋ฃจํŠธ์™€ ๋ชจ์„œ๋ฆฌ๋ฅผ ํ†ตํ•ด ๋…ธ๋“œ๋ฅผ ๋”ฐ๋ผ ์ˆœํšŒํ•  ์ˆ˜๋Š” ์žˆ์ง€๋งŒ ๋™์ผํ•œ ๋…ธ๋“œ๋กœ ๋Œ์•„์˜ฌ ์ˆ˜ ์—†๋Š” ์†์„ฑ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. GraphQL ์ฟผ๋ฆฌ์™€ ์œ„์˜ ๊ทธ๋ž˜ํ”„์—์„œ ํŠธ๋ฆฌ๋ฅผ ์ถ”์ถœํ•œ๋‹ค๋ฉด ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ์ฟผ๋ฆฌ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

query {
	์ฑ…(ISBN์ด "9780674430006") { // ํ•œ ๊ถŒ์˜ ์ฑ…๋งŒ ๊ฒ€์ƒ‰ํ•˜๊ธฐ ์œ„ํ•œ ํŠน์ • ์กฐ๊ฑด
		์ฑ… ์ด๋ฆ„
		์ €์ž {
			์ด๋ฆ„
		}
	}
}

์œ„์˜ ๋ฐฉ์‹์œผ๋กœ ์„œ๋ฒ„์— ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ  ์„œ๋ฒ„๊ฐ€ ํ•ด๋‹น ์š”์ฒญ์„ ํ•ด๊ฒฐํ•œ๋‹ค๋ฉด ๋Œ์•„์˜จ ์ฟผ๋ฆฌ๋Š” ์•„๋ž˜์™€ ๊ฐ™์„ ๊ฒƒ์ด๋‹ค.

{
	์ฑ… : {
		์ฑ… ์ด๋ฆ„ : "GraphQL์€ ์–ด๋ ต์ง€ ์•Š๋‹ค",
		์ €์ž : [
			{ ์ด๋ฆ„ : "๊น€์ฝ”๋”ฉ"},
			{ ์ด๋ฆ„ : "๋ฐ•ํ•ด์ปค"},
		]
	}
}
GraphQL๋กœ ์ฟผ๋ฆฌํ•œ ๊ฒƒ์„ ๊ทธ๋ž˜ํ”„์˜ ๊ด€์ ์œผ๋กœ ๋„์‹ํ™”ํ•˜๋ฉด ์ด์™€ ๊ฐ™๋‹ค.

์ด ์˜ˆ์—์„œ๋Š” ISBN ๋ฒˆํ˜ธ๋ฅผ ์‚ฌ์šฉํ•ด ์„ ํƒํ•œ ์ฑ… ๋…ธ๋“œ์—์„œ ์‹œ์ž‘ํ•œ๋‹ค. ๊ทธ ๋‹ค์Œ GraphQL์€ ์ค‘์ ‘๋œ ๊ฐ ํ•„๋“œ๋กœ ํ‘œ์‹œ๋œ ๊ฐ„์„ ์„ ๋”ฐ๋ผ ๊ทธ๋ž˜ํ”„๋ฅผ ํƒ์ƒ‰ํ•˜๊ธฐ ์‹œ์ž‘ํ•œ๋‹ค. ์ฆ‰, ์ฟผ๋ฆฌ ๋‚ด ์ค‘์ฒฉ๋œ ์ฑ… ์ด๋ฆ„ ํ•„๋“œ๋ฅผ ํ†ตํ•ด ์ฑ…์˜ ์ œ๋ชฉ์ด ์žˆ๋Š” ๋…ธ๋“œ๋กœ ์ด๋™ํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด์„œ ์ €์ž๋กœ ๋ ˆ์ด๋ธ”์ด ์ง€์ •๋œ ์ฑ…์˜ ๊ฐ„์„ ์„ ๋”ฐ๋ผ ์ €์ž ๋…ธ๋“œ๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ , ๊ฐ ์ €์ž์˜ ์ด๋ฆ„์„ ์–ป์–ด์˜ค๋Š” ๊ฒƒ์ด๋‹ค. ์ด๋ฅผ ํŠธ๋ฆฌ ๊ตฌ์กฐ๋กœ ํ‘œํ˜„ํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

์ด๋ ‡๊ฒŒ GraphQL์˜ ์ค‘์ฒฉ๋œ ํ•„๋“œ๋ฅผ ๊ณ„์ธต ๊ตฌ์กฐ๋กœ ํ‘œํ˜„ํ•˜๋ฉด ์ด๋ ‡๊ฒŒ ํŠธ๋ฆฌ ๊ตฌ์กฐ๋กœ๋„ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค. ์ฆ‰, GraphQL์€ ํŠธ๋ฆฌ ๊ตฌ์กฐ๋กœ ์ฟผ๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›๊ธฐ ์œ„ํ•ด ๊ทธ๋ž˜ํ”„๋ฅผ ํƒ์ƒ‰ํ•˜๋Š” ์ฟผ๋ฆฌ ์–ธ์–ด๋ผ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

GraphQL์˜ ํŠน์ง•

  • HTTP๋ฅผ ํ†ตํ•ด API ์„œ๋ฒ„๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ  ์‘๋‹ต์„ ๋ฐ›๋Š”๋‹ค.
  • ์‘๋‹ต์„ ๋ฐ›์„ ์‹œ, ๋ฐ์ดํ„ฐ ๊ฒฐ๊ณผ๋ฅผ JSON ํ˜•์‹์œผ๋กœ ๋ฐ›๋Š”๋‹ค.
  • ์„œ๋ฒ„ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ž‘์„ฑํ•œ ๊ฐ ํ•„๋“œ์— ๋Œ€์‘ํ•˜๋Š” resolver ํ•จ์ˆ˜๋กœ ๊ฐ ํ•„๋“œ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค.
  • GraphQL ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์กฐํšŒ ๋Œ€์ƒ schema๊ฐ€ ์œ ํšจํ•œ์ง€ ๊ฒ€์‚ฌํ•œ๋‹ค.

GraphQL vs. REST API

GraphQL์ด ์ƒ๊ธฐ๊ธฐ ์ด์ „์— API๋ฅผ ์œ„ํ•ด ์ด๋ฏธ REST API๋ผ๋Š” ๋ฐฉ๋ฒ•๋ก ์ด ์กด์žฌํ–ˆ๋‹ค. ๊ทธ๋Ÿผ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  GraphQL์ด ์ƒ๊ฒจ๋‚œ ์ด์œ ๋Š” REST API์˜ ํ•œ๊ณ„์ ์ด ์กด์žฌํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

REST API์˜ ํ•œ๊ณ„

๊ฐ€์ƒ์˜ ๋ธ”๋กœ๊ทธ ์•ฑ์„ ๊ตฌํ˜„ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž. ์œ„์˜ ํ™”๋ฉด์„ ๊ฐ€์ง„ ์•ฑ์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋‹ค์Œ์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

  • ์‚ฌ์šฉ์ž์˜ ์ด๋ฆ„
  • ์‚ฌ์šฉ์ž์˜ ํฌ์ŠคํŒ… ๋ชฉ๋ก
  • ์‚ฌ์šฉ์ž์˜ ํŒ”๋กœ์›Œ ๋ชฉ๋ก

์ด๋Ÿฐ ๋ฐ์ดํ„ฐ๋ฅผ REST API๋กœ ๋ฐ›์•„์˜จ๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฌธ์ œ์ ์ด ์กด์žฌํ•œ๋‹ค.

  1. Overfetch : ํ•„์š”์—†๋Š” ๋ฐ์ดํ„ฐ๊นŒ์ง€ ์ œ๊ณตํ•จ

    ๋ธ”๋กœ๊ทธ ์•ฑ ์˜ˆ์ œ์ฒ˜๋Ÿผ ์œ ์ €์˜ ์ด๋ฆ„๋งŒ ํ•„์š”ํ•œ ์ƒํ™ฉ์—์„œ REST API๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด, ์‘๋‹ต ๋ฐ์ดํ„ฐ์—๋Š” ์œ ์ €์˜ ์ฃผ์†Œ, ์ƒ์ผ ๋“ฑ๊ณผ ๊ฐ™์ด ์‹ค์ œ ํด๋ผ์ด์–ธํŠธ์—๋Š” ํ•„์š”์—†๋Š” ์ •๋ณด๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค.

  1. Underfetch : Endpoint๊ฐ€ ํ•„์š”ํ•œ ์ •๋ณด๋ฅผ ์ถฉ๋ถ„ํžˆ ์ œ๊ณตํ•˜์ง€ ๋ชปํ•จ

    Underfetch์˜ ๊ฒฝ์šฐ ํด๋ผ์ด์–ธํŠธ๋Š” ํ•„์š”ํ•œ ์ •๋ณด๋ฅผ ๋ชจ๋‘ ํ™•๋ณดํ•˜๊ธฐ ์œ„ํ•ด ์ถ”๊ฐ€์ ์ธ ์š”์ฒญ์„ ๋ณด๋‚ด์•ผ๋งŒ ํ•œ๋‹ค. ๋ธ”๋กœ๊ทธ ์•ฑ ์˜ˆ์ œ ํ™”๋ฉด์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด์„  ์œ ์ € ์ •๋ณด ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์œ ์ €์˜ ํฌ์ŠคํŒ… ๋ชฉ๋ก ๋ฐ ์œ ์ €๊ฐ€ ๋ณด์œ ํ•œ ํŒ”๋กœ์›Œ๊นŒ์ง€ ํ•„์š”ํ•˜๋‹ค. ์ด๋•Œ ํ•„์š”ํ•œ ์ •๋ณด๋ฅผ ๋ชจ๋‘ ๊ฐ€์ ธ์˜ค๋ ค๋ฉด REST API์—์„œ๋Š” ๊ฐ๊ฐ์˜ ์ž์›์— ๋”ฐ๋ผ ์—”๋“œํฌ์ธํŠธ๋ฅผ ๊ตฌ๋ถ„ํ•˜๊ธฐ ๋•Œ๋ฌธ์— 3๊ฐ€์ง€ ์—”๋“œํฌ์ธํŠธ์— ์š”์ฒญ์„ ๋ณด๋‚ด์•ผ ํ•œ๋‹ค.

  1. ํด๋ผ์ด์–ธํŠธ ๊ตฌ์กฐ ๋ณ€๊ฒฝ ์‹œ ์—”๋“œํฌ์ธํŠธ ๋ณ€๊ฒฝ ๋˜๋Š” ๋ฐ์ดํ„ฐ ์ˆ˜์ •์ด ํ•„์š”ํ•จ

    REST API์—์„œ๋Š” ์ž์›์˜ ํฌ๊ธฐ์™€ ํ˜•ํƒœ๋ฅผ ์„œ๋ฒ„์—์„œ ๊ฒฐ์ •ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ง์ ‘ ๋ฐ์ดํ„ฐ์˜ ํ˜•ํƒœ๋ฅผ ๊ฒฐ์ •ํ•  ์ˆ˜ ์—†๋‹ค. ์ด๋กœ ์ธํ•ด ๋งŒ์•ฝ ํด๋ผ์ด์–ธํŠธ์—์„œ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ์˜ ๋‚ด์šฉ์ด ๋ณ€ํ•  ๊ฒฝ์šฐ ๋‹ค๋ฅธ endpoint๋ฅผ ํ†ตํ•ด ๋ณ€๊ฒฝ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ฑฐ๋‚˜ ์ˆ˜์ •ํ•ด์•ผ ํ•œ๋‹ค.

REST API์™€ GraphQL์˜ ๋‹ค๋ฅธ ์ 

REST APIGraphQL
Resource์— ๋Œ€ํ•œ ํ˜•ํƒœ ์ •์˜์™€ ๋ฐ์ดํ„ฐ ์š”์ฒญ ๋ฐฉ๋ฒ•์ด ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋‹ค.Resource์— ๋Œ€ํ•œ ํ˜•ํƒœ ์ •์˜์™€ ๋ฐ์ดํ„ฐ ์š”์ฒญ์ด ์™„์ „ํžˆ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ๋‹ค.
Resource์˜ ํฌ๊ธฐ์™€ ํ˜•ํƒœ๋ฅผ ์„œ๋ฒ„์—์„œ ๊ฒฐ์ •ํ•œ๋‹ค.Resource์— ๋Œ€ํ•œ ์ •๋ณด๋งŒ ์ •์˜ํ•˜๊ณ , ํ•„์š”ํ•œ ํฌ๊ธฐ์™€ ํ˜•ํƒœ๋Š” ํด๋ผ์ด์–ธํŠธ ๋‹จ์—์„œ ์š”์ฒญ ์‹œ ๊ฒฐ์ •ํ•œ๋‹ค.
URI๊ฐ€ Resource๋ฅผ ๋‚˜ํƒ€๋‚ด๊ณ  Method๊ฐ€ ์ž‘์—…์˜ ์œ ํ˜•์„ ๋‚˜ํƒ€๋‚ธ๋‹ค.GraphQL Schema๊ฐ€ Resource๋ฅผ ๋‚˜ํƒ€๋‚ด๊ณ  Query, Mutation ํƒ€์ž…์ด ์ž‘์—…์˜ ์œ ํ˜•์„ ๋‚˜ํƒ€๋‚ธ๋‹ค.
์—ฌ๋Ÿฌ Resource์— ์ ‘๊ทผํ•˜๊ณ ์ž ํ•  ๋•Œ ์—ฌ๋Ÿฌ ๋ฒˆ์˜ ์š”์ฒญ์ด ํ•„์š”ํ•˜๋‹ค.ํ•œ๋ฒˆ์˜ ์š”์ฒญ์—์„œ ์—ฌ๋Ÿฌ Resource์— ์ ‘๊ทผ ๊ฐ€๋Šฅํ•˜๋‹ค.
๊ฐ ์š”์ฒญ์€ ํ•ด๋‹น ์—”๋“œํฌ์ธํŠธ์— ์ •์˜๋œ ํ•ธ๋“ค๋ง ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•œ๋‹ค.์š”์ฒญ ๋ฐ›์€ ๊ฐ ํ•„๋“œ์— ๋Œ€ํ•œ resolver๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•œ๋‹ค.

GraphQL์˜ ์žฅ์ 

GraphQL์˜ ๊ฐ€์žฅ ํฐ ์žฅ์ ์€ ์ •๋ณด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ธก์—์„œ ์›ํ•˜๋Š” ๋Œ€๋กœ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๊ณ , ๋ณด๋‹ค ํŽธํ•˜๊ฒŒ ์ •๋ณด๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ํ‘œ์ค€ํ™”๋œ ์ฟผ๋ฆฌ ์–ธ์–ด๋ผ๋Š” ์ ์ด๋‹ค.

์œ„์˜ ์˜ˆ์ œ์ธ ๋ธ”๋กœ๊ทธ ์•ฑ์„ GraphQL๋กœ ์š”์ฒญ/์‘๋‹ต์„ ๋ฐ›์œผ๋ฉด ์ด์™€ ๊ฐ™์€ ํ˜•ํƒœ๋ฅผ ๊ฐ€์ง„๋‹ค.
  • ํ•˜๋‚˜์˜ endpoint ์š”์ฒญ

    /graphql์ด๋ผ๋Š” ํ•˜๋‚˜์˜ endpoint ๋กœ ์š”์ฒญ์„ ๋ฐ›๊ณ  ๊ทธ ์š”์ฒญ์— ๋”ฐ๋ผ query , mutation์„ resolver ํ•จ์ˆ˜๋กœ ์ „๋‹ฌํ•ด์„œ ์š”์ฒญ์— ์‘๋‹ตํ•œ๋‹ค. ๋ชจ๋“  ํด๋ผ์ด์–ธํŠธ ์š”์ฒญ์€ POST ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

  • No under & overfetching

    ์—ฌ๋Ÿฌ ๊ฐœ์˜ endpoint ์š”์ฒญ์„ ํ•  ํ•„์š”์—†์ด ํ•˜๋‚˜์˜ endpoint์—์„œ ์ฟผ๋ฆฌ๋ฅผ ์ด์šฉํ•ด ์›ํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ •ํ™•ํ•˜๊ฒŒ API์— ์š”์ฒญํ•˜๊ณ  ์‘๋‹ต์œผ๋กœ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.

  • ๊ฐ•๋ ฅํ•œ playground

    graphql ์„œ๋ฒ„๋ฅผ ์‹คํ–‰ํ•˜๋ฉด playground๋ผ๋Š” GUI(POSTMAN ๊ณผ ๋น„์Šทํ•จ)๋ฅผ ์ด์šฉํ•ด resolver ์™€ schema ๋ฅผ ํ•œ ๋ˆˆ์— ๋ณด๊ณ  ํ…Œ์ŠคํŠธ ํ•ด ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

  • ํด๋ผ์ด์–ธํŠธ ๊ตฌ์กฐ ๋ณ€๊ฒฝ์—๋„ ์ง€์žฅ์ด ์—†์Œ

    ํด๋ผ์ด์–ธํŠธ ๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€Œ์–ด๋„ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฒฐ์ •ํ•˜๊ณ  ๋ฐ›๋Š” ์ฃผ์ฒด๊ฐ€ ํด๋ผ์ด์–ธํŠธ์ด๊ธฐ ๋•Œ๋ฌธ์— ์„œ๋ฒ„์— ์ง€์žฅ์ด ์—†์Šต๋‹ˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ์—์„œ๋Š” ๋ฌด์Šจ ๋ฐ์ดํ„ฐ๊ฐ€ ํ•„์š”ํ•œ ์ง€์— ๋Œ€ํ•ด์„œ๋งŒ ์š”๊ตฌ์‚ฌํ•ญ์„ ์ฟผ๋ฆฌ๋กœ ์ž‘์„ฑํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

GraphQL์˜ ๋‹จ์ 

  • REST API์— ์นœ์ˆ™ํ•œ ๊ฐœ๋ฐœ์ž์˜ ๊ฒฝ์šฐ GraphQL์„ ํ•™์Šตํ•˜๋Š” ๋ฐ ์‹œ๊ฐ„์ด ํ•„์š”ํ•˜๋‹ค.
  • ์บ์‹ฑ์ด REST๋ณด๋‹ค ํ›จ์”ฌ ๋ณต์žกํ•˜๋‹ค.

    HTTP์—์„  ๊ฐ ๋ฉ”์†Œ๋“œ์— ๋”ฐ๋ผ ์บ์‹ฑ์ด ๊ตฌํ˜„๋˜์–ด ์žˆ์ง€๋งŒ, GraphQL์—์„  POST ๋ฉ”์†Œ๋“œ๋งŒ์„ ์ด์šฉํ•ด ์š”์ฒญ์„ ๋ณด๋‚ด๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ ๋ฉ”์†Œ๋“œ์— ๋”ฐ๋ฅธ ์บ์‹ฑ์„ ์ง€์›๋ฐ›์„ ์ˆ˜ ์—†๋‹ค. ์ด๋ฅผ ๋ณด์™„ํ•˜๊ธฐ ์œ„ํ•ด Apollo ์—”์ง„์˜ ์บ์‹ฑ๊ณผ ์˜์† ์ฟผ๋ฆฌ ๋“ฑ์ด ๋“ฑ์žฅํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค.

  • ๊ณ ์ •๋œ ์š”์ฒญ๊ณผ ์‘๋‹ต๋งŒ ํ•„์š”ํ•œ ๊ฒฝ์šฐ Query๋กœ ์ธํ•ด ์š”์ฒญ์˜ ํฌ๊ธฐ๊ฐ€ RESTful API๋ณด๋‹ค ๋” ์ปค์ง„๋‹ค.

GraphQL์˜ ๊ตฌ์กฐ

GraphQL Keywords

์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒ(Read)ํ•˜๋Š” ๊ฒฝ์šฐ GraphQL์—์„œ๋Š” Query๋ฅผ ์ด์šฉํ•ด ์›ํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•  ์ˆ˜ ์žˆ๊ณ , Create, Delete์™€ ๊ฐ™์ด ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ๊ฒฝ์šฐ Mutation์„ ์ด์šฉํ•ด ์ด๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

์—ฌ๊ธฐ์—์„œ ๋” ๋‚˜์•„๊ฐ€ ๊ตฌ๋…(Subscription)์ด๋ผ๋Š” ๊ฐœ๋…์„ ์ œ๊ณตํ•˜์—ฌ ์ด๋ฅผ ์ด์šฉํ•ด ์‹ค์‹œ๊ฐ„ ์—…๋ฐ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. Subscription์€ ์ „ํ†ต์ ์ธ Client(์š”์ฒญ)โ†”Server(์‘๋‹ต) ๋ชจ๋ธ์„ ๋”ฐ๋ฅด๋Š” Query์™€ Mutation๊ณผ ๋‹ฌ๋ฆฌ, ๋ฐœํ–‰/๊ตฌ๋…(publish/subscribe) ๋ชจ๋ธ์„ ๋”ฐ๋ฅธ๋‹ค. ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์–ด๋–ค ์ด๋ฒคํŠธ๋ฅผ ๊ตฌ๋…ํ•˜๋ฉด, ํด๋ผ์ด์–ธํŠธ๋Š” ์„œ๋ฒ„์™€ WebSocket์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ง€์†์ ์ธ ์—ฐ๊ฒฐ์„ ํ˜•์„ฑํ•˜๊ณ  ์œ ์ง€ํ•˜๊ฒŒ ๋œ๋‹ค. ๊ทธ ํ›„ ํŠน์ • ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์„œ๋ฒ„๋Š” ๋Œ€์‘ํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ํด๋ผ์ด์–ธํŠธ์— ํ‘ธ์‹œํ•ด์ค€๋‹ค.

  • Query: ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ (REST์˜ GET๊ณผ ๋น„์Šทํ•ฉ๋‹ˆ๋‹ค.)
  • Mutation:ย ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ ์ˆ˜์ •ํ•˜๊ธฐ
    • Create: ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ ์ƒ์„ฑ
    • Update: ๊ธฐ์กด์˜ ๋ฐ์ดํ„ฐ ์ˆ˜์ •
    • Delete: ๊ธฐ์กด์˜ ๋ฐ์ดํ„ฐ ์‚ญ์ œ
  • Subscription: ํŠน์ • ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒ ์‹œ ์„œ๋ฒ„๊ฐ€ ๋Œ€์‘ํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์ „์†ก

์ฟผ๋ฆฌ(Query, ๋ฐ์ดํ„ฐ ์กฐํšŒ)

ํ•„๋“œ(field)

๊ฐ„๋‹จํ•œ query๋ฅผ ์‹คํ–‰ํ–ˆ์„ ๋•Œ ์–ป์€ ๊ฐ’์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

# ์š”์ฒญ
# hero์˜ name์„ ์ฟผ๋ฆฌ
{
  hero {
    name
  }
}
// ์‘๋‹ต
{
  "data": {
    "hero": {
      "name": "R2-D2"
    }
  }
}

ํ•„๋“œ์˜ name์€ String ํƒ€์ž…์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์ฟผ๋ฆฌ์™€ ๊ฒฐ๊ณผ๊ฐ€ ์ •ํ™•ํ•˜๊ฒŒ ๊ฐ™์€ ๋ชจ์–‘์„ ํ•˜๊ณ  ์žˆ์Œ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ด ๋ถ€๋ถ„์€ GraphQL์— ์žˆ์–ด ํ•„์ˆ˜์ ์ธ ๋ถ€๋ถ„์ด๋‹ค. GraphQL์€ ์„œ๋ฒ„์— ์š”์ฒญํ–ˆ์„ ๋•Œ ์˜ˆ์ƒํ–ˆ๋˜ ๋Œ€๋กœ ๋Œ๋ ค๋ฐ›๊ณ , ์„œ๋ฒ„๋Š” GraphQL์„ ํ†ตํ•ด ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์š”๊ตฌํ•˜๋Š” ํ•„๋“œ๋ฅผ ์ •ํ™•ํžˆ ์•Œ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

# ์š”์ฒญ
# ์›ํ•˜๋Š” ํ•„๋“œ๋ฅผ ์ค‘์ฒฉํ•˜์—ฌ ์ฟผ๋ฆฌ๋„ ๊ฐ€๋Šฅ
{
  hero {
    name
    friends {
      name
    }
  }
}
// ์‘๋‹ต
{
  "data": {
    "hero": {
      "name": "R2-D2",
      "friends": [
        {
          "name": "Luke Skywalker"
        },
        {
          "name": "Han Solo"
        },
        {
          "name": "Leia Organa"
        }
      ]
    }
  }
}

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

์ „๋‹ฌ์ธ์ž(Arguments)

ํ•„๋“œ์— ์ธ์ˆ˜๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๋ถ€๋ถ„์„ ์ถ”๊ฐ€ํ•˜๊ฒŒ ๋˜๋ฉด ์ฟผ๋ฆฌ์˜ ํ•„๋“œ ๋ฐ ์ค‘์ฒฉ๋œ ๊ฐ์ฒด๋“ค์— ์ „๋‹ฌํ•ด ์›ํ•˜๋Š” ๋ฐ์ดํ„ฐ๋งŒ ๋ฐ›์•„์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

# ์š”์ฒญ
# id๊ฐ€ 1000์ธ 
# human์˜ name๊ณผ height๋ฅผ ์ฟผ๋ฆฌ
{
  human(id: "1000") {
    name
    height
  }
}
// ์‘๋‹ต
{
  "data": {
    "human": {
      "name": "Luke Skywalker",
      "height": 1.72
    }
  }
}

๋ณ„๋ช…(Aliases)

ํ•„๋“œ ์ด๋ฆ„์„ ์ค‘๋ณตํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ, ํ•„๋“œ ์ด๋ฆ„์„ ์ค‘๋ณต์œผ๋กœ ์‚ฌ์šฉํ•ด์„œ ์ฟผ๋ฆฌ๋ฅผ ํ•ด์•ผ ํ•  ๋•Œ๋Š” ๋ณ„๋ช…์„ ๋ถ™์—ฌ์„œ ์ฟผ๋ฆฌ๋ฅผ ํ•œ๋‹ค.

# ์ž˜๋ชป๋œ ๋ฐฉ์‹
{
	hero(episode: EMPIRE) {
    name
  }
  hero(episode: JEDI) {
    name
  }
}

# ๋ณ„๋ช…์„ ๋ถ™์ด๋ฉด ์ฟผ๋ฆฌ ๊ฐ€๋Šฅ
{
  empireHero: hero(episode: EMPIRE) {
    name
  }
  jediHero: hero(episode: JEDI) {
    name
  }
}
// ์š”์ฒญ ๊ฒฐ๊ณผ

{
  "data": {
    "empireHero": {
      "name": "Luke Skywalker"
    },
    "jediHero": {
      "name": "R2-D2"
    }
  }
}

์˜คํผ๋ ˆ์ด์…˜ ๋„ค์ž„(Operation name)

์‹ค์ œ ์•ฑ์—์„œ๋Š” ์ฟผ๋ฆฌ์™€ ์ฟผ๋ฆฌ ๋„ค์ž„์„ ๋ชจ๋‘ ์ƒ๋žตํ•˜์ง€ ์•Š๊ณ  ๋ชจํ˜ธํ•˜์ง€ ์•Š๊ฒŒ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค.

query HeroNameAndFriends {
  hero {
    name
    friends {
      name
    }
  }
}

์•ž์˜ query๋Š” ์˜คํผ๋ ˆ์ด์…˜ ํƒ€์ž…์ด๋ฉฐ, ์—ฌ๊ธฐ์—๋Š” query ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ mutation, subscription, describes ๋“ฑ์ด ์žˆ๋‹ค. ์ฟผ๋ฆฌ๋ฅผ ์•ฝ์‹์œผ๋กœ ์ž‘์„ฑํ•˜์ง€ ์•Š๋Š” ํ•œ ์˜คํผ๋ ˆ์ด์…˜ ํƒ€์ž…์€ ๋ฐ˜๋“œ์‹œ ํ•„์š”ํ•˜๋ฉฐ, ์˜คํผ๋ ˆ์ด์…˜ ๋„ค์ž„์„ ์ž‘์„ฑํ•  ๋•Œ๋Š” ์˜คํผ๋ ˆ์ด์…˜ ํƒ€์ž…์— ๋งž๋Š” ์ด๋ฆ„์œผ๋กœ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

๋ณ€์ˆ˜(Variables)

์‹ค์ œ ์•ฑ์„ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ๊ณ ์ •๋œ ์ธ์ˆ˜๋ฅผ ๋ฐ›๋Š” ๊ฒƒ ๋ณด๋‹ค ๋™์ ์œผ๋กœ ์ธ์ˆ˜๋ฅผ ๋ฐ›์•„ ์ฟผ๋ฆฌํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋Œ€๋‹ค์ˆ˜์ด๋‹ค. ๋ณ€์ˆ˜๋Š” ๊ทธ๋Ÿฐ ์ธ์ˆ˜๋“ค์„ ๋™์ ์œผ๋กœ ๋ฐ›๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค. ์˜คํผ๋ ˆ์ด์…˜ ๋„ค์ž„ ์˜†์— $๋ณ€์ˆ˜ ์ด๋ฆ„: ํƒ€์ž… ํ˜•ํƒœ๋กœ ์ •์˜ํ•œ๋‹ค. ์•„๋ž˜์˜ ์˜ˆ์‹œ์ฒ˜๋Ÿผ $episode: Episode ์ผ ๋•Œ, ๋’ค์— !๊ฐ€ ๋ถ™๋Š”๋‹ค๋ฉด episode๋Š” ๋ฐ˜๋“œ์‹œ Episode์—ฌ์•ผ ํ•œ๋‹ค๋Š” ๋œป์ด๋‹ค. !๋Š” ์˜ต์…”๋„ํ•œ ์‚ฌํ•ญ์ด๋‹ค.

query HeroNameAndFriends($episode: Episode) {
  hero(episode: $episode) {
    name
    friends {
      name
    }
  }
}

๋ฎคํ…Œ์ด์…˜(mutation, ๋ฐ์ดํ„ฐ ์ˆ˜์ •)

GraphQL์€ ๋Œ€๊ฐœ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐ์— ์ค‘์ ์„ ๋‘๊ณ  ์žˆ์ง€๋งŒ ์„œ๋ฒ„์ธก ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•˜๊ธฐ๋„ ํ•œ๋‹ค. REST API์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•  ๋•Œ POST๋‚˜ PUT, PATCH๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ ์ฒ˜๋Ÿผ GraphQL๋„ ์œ ์‚ฌํ•˜๋‹ค. GraphQL์€ mutation์ด๋ผ๋Š” ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋ฒ„ ์ธก ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•œ๋‹ค.

mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) {
  createReview(episode: $ep, review: $review) {
    stars
    commentary
  }
}

์Šคํ‚ค๋งˆ/ํƒ€์ž…(Schema/Type)

GraphQL ์Šคํ‚ค๋งˆ์˜ ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ๊ตฌ์„ฑ ์š”์†Œ๋Š” ์„œ๋น„์Šค์—์„œ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋Š” ๊ฐ์ฒด์˜ ์ข…๋ฅ˜, ๊ทธ๋ฆฌ๊ณ  ํฌํ•จํ•˜๋Š” ํ•„๋“œ๋Š” ๋‚˜ํƒ€๋‚ด๋Š” ๊ฐ์ฒด ์œ ํ˜•์ด๋‹ค.

type Character {
  name: String!
  appearsIn: [Episode!]!
}
  • Character๋Š” GraphQL ๊ฐ์ฒด ํƒ€์ž…์ด๋ฉฐ, ์ฆ‰ ํ•„๋“œ๊ฐ€ ์žˆ๋Š” ํƒ€์ž…์ž„์„ ์˜๋ฏธํ•œ๋‹ค. ์Šคํ‚ค๋งˆ์— ์žˆ๋Š” ๋Œ€๋ถ€๋ถ„์˜ ํƒ€์ž…์€ ๊ฐ์ฒด ํƒ€์ž…์ด๋‹ค.
  • nameย ๊ณผย appearInย ์€ย Characterย ํƒ€์ž…์˜ย ํ•„๋“œ๋‹ค. ์ฆ‰ย nameย ๊ณผย appearInย ์€ GraphQL ์ฟผ๋ฆฌ์˜ย Characterย ํƒ€์ž… ์–ด๋””์„œ๋“  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ•„๋“œ์ด๋‹ค.
  • String์€ ๋‚ด์žฅ๋œ ์Šค์นผ๋ผ ํƒ€์ž… ์ค‘ ํ•˜๋‚˜์ด๋‹ค. ์ด๋Š” ๋‹จ์ผ ์Šค์นผ๋ผ ๊ฐ์ฒด๋กœ ํ™•์ธ๋˜๋Š” ์œ ํ˜•์ด๋ฉฐ ์ฟผ๋ฆฌ์—์„œ ํ•˜์œ„ ์„ ํƒ์„ ๊ฐ€์งˆ ์ˆ˜ ์—†์œผ๋ฉฐ, ์Šค์นผ๋ผ ํƒ€์ž…์—๋Š” ID, Int๋„ ์žˆ๋‹ค.
  • !๊ฐ€ ๋ถ™๋Š”๋‹ค๋ฉด ์ด ํ•„๋“œ๋Š” nullableํ•˜์ง€ ์•Š๊ณ  ๋ฐ˜๋“œ์‹œ ๊ฐ’์ด ๋“ค์–ด์˜จ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค. ์ด๊ฒƒ์„ ๋ถ™์—ฌ ์ฟผ๋ฆฌํ•œ๋‹ค๋ฉด ๋ฐ˜๋“œ์‹œ ๊ฐ’์„ ๋ฐ›์„ ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋ž€ ์˜ˆ์ƒ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • [ ]๋Š” ๋ฐฐ์—ด์„ ์˜๋ฏธํ•œ๋‹ค. ๋ฐฐ์—ด์—๋„ !๊ฐ€ ๋ถ™์„ ์ˆ˜ ์žˆ๋Š”๋ฐ, ์—ฌ๊ธฐ์„œ๋Š” ! ์ด ๋’ค์— ๋ถ™์–ด ์žˆ์–ด null ๊ฐ’์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ํ•ญ์ƒ 0๊ฐœ ์ด์ƒ์˜ ์š”์†Œ๋ฅผ ํฌํ•จํ•œ ๋ฐฐ์—ด์„ ๊ธฐ๋Œ€ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

๋ฆฌ์กธ๋ฒ„(Resolver)

์š”์ฒญ์— ๋Œ€ํ•œ ์‘๋‹ต์„ ๊ฒฐ์ •ํ•ด์ฃผ๋Š” ํ•จ์ˆ˜๋กœ์จ GraphQL์˜ ์—ฌ๋Ÿฌ ํƒ€์ž… ์ค‘ Query, Mutation, Subscription๊ณผ ๊ฐ™์€ ํƒ€์ž…์˜ ์‹ค์ œ ์ผํ•˜๋Š” ๋ฐฉ์‹, ์ฆ‰ ๋กœ์ง์„ ์ž‘์„ฑํ•œ๋‹ค. ๋‹ค์‹œ ๋งํ•ด ์œ„์™€ ๊ฐ™์ด ์Šคํ‚ค๋งˆ๋ฅผ ์ •์˜ํ•˜๋ฉด ๊ทธ ์Šคํ‚ค๋งˆ ํ•„๋“œ์— ์‚ฌ์šฉ๋˜๋Š” ํ•จ์ˆ˜์˜ ์‹ค์ œ ํ–‰๋™์„ Resolver์—์„œ ์ •์˜ํ•œ๋‹ค. ๋ณดํ†ต ์ด๋Ÿฐ ํ•จ์ˆ˜๋“ค์ด ๋ชจ์—ฌ์žˆ๊ธฐ ๋•Œ๋ฌธ์— Resolvers๋ผ ๋ถ€๋ฅธ๋‹ค. GraphQL์—์„œ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ตฌ์ฒด์ ์ธ ๊ณผ์ •์„ ์ง์ ‘ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜๋Š”๋ฐ ์ด์™€ ๊ฐ™์€ ์ž‘์—…(e.g. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ฟผ๋ฆฌ, ์›๊ฒฉ API ์š”์ฒญ)์„ Resolver๊ฐ€ ๋‹ด๋‹นํ•˜๊ฒŒ ๋œ๋‹ค.

const db = require("./../db")
const resolvers = {
  Query: { // **Query :** ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ (REST ์— GET ๊ณผ ๋น„์Šทํ•ฉ๋‹ˆ๋‹ค.)
		getUser: async (_, { email, pw }) => {
			db.findOne({
				where: { email, pw }
			}) ... // ์‹ค์ œ ๋””๋น„์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋กœ์ง์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. 
			...
		}
  },
  Mutation: { // **Mutation :** ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ ์ˆ˜์ •ํ•˜๊ธฐ ( Create , Update , Delete )
		createUser: async (_, { email, pw, name }) => {
			...
		}
  }
  Subscription: { // **Subscription :** ์‹ค์‹œ๊ฐ„ ์—…๋ฐ์ดํŠธ
    newUser: async () => {
      ...
		}
  }
};

Uploaded by N2T