roqkf

[API] GraphQL ๋ณธ๋ฌธ

๐Ÿ’ป Development/๊ธฐ๋ก

[API] GraphQL

ahyeon7 2023. 3. 1. 16:36

๐Ÿ“Œ GraphQL

  • Facebook์—์„œ ์ฒ˜์Œ์œผ๋กœ ๊ฐœ๋ฐœ, ์˜คํ”ˆ ์†Œ์Šค๋กœ ์ œ๊ณต๋œ ์ฟผ๋ฆฌ ์–ธ์–ด
  • Graph + Query Language์˜ ์ค„์ž„๋ง๋กœ Query Language ์ค‘์—์„œ๋„ Server API ๋ฅผ ํ†ตํ•ด ์ •๋ณด๋ฅผ ์ฃผ๊ณ ๋ฐ›๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” Query Language
  • API๋ฅผ ์œ„ํ•œ ์ฟผ๋ฆฌ ์–ธ์–ด

๐Ÿค” ์™œ Graph๋ฅผ ์‚ฌ์šฉํ•˜๋‚˜์š”?

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

 

[๊ทธ๋ฆผ] ๊ทธ๋ž˜ํ”„ ์ž๋ฃŒ๊ตฌ์กฐ

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


[๊ทธ๋ฆผ] ๊ทธ๋ž˜ํ”„ ์ž๋ฃŒ๊ตฌ์กฐ์™€ ํŠธ๋ฆฌ ์ž๋ฃŒ๊ตฌ์กฐ์˜ ์ฐจ์ด

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


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

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

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

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


[๊ทธ๋ฆผ] ๋„์„œ ๋ชฉ๋ก ์‹œ์Šคํ…œ ๊ตฌ์ถ•์„ ์œ„ํ•œ ๊ทธ๋ž˜ํ”„

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

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

์ด๋ ‡๊ฒŒ ๊ทธ๋ž˜ํ”„๋ฅผ ๊ทธ๋ฆด ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค๋ฉด, GraphQL์„ ์‚ฌ์šฉํ•ด ํŠธ๋ฆฌ๋ฅผ ์ถ”์ถœํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

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

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

GraphQL ์ฟผ๋ฆฌ์™€ ์œ„์˜ ๊ทธ๋ž˜ํ”„์—์„œ ํŠธ๋ฆฌ๋ฅผ ์ถ”์ถœํ•ด๋ณด๋„๋ก ํ•˜์ž. ์œ„์˜ ๊ทธ๋ž˜ํ”„์—์„œ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ์ฟผ๋ฆฌ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

query {
	์ฑ…(ISBN์ด "9780674430006") {
		์ฑ… ์ด๋ฆ„
		์ €์ž {
			์ด๋ฆ„
		}
	}
}

์œ„์˜ ๊ทธ๋ž˜ํ”„๋Š” ๊ฐ„๋‹จํ•˜๊ฒŒ ํ‘œํ˜„ํ–ˆ์ง€๋งŒ ์‚ฌ์‹ค ์ฑ…์ด๋ž€ ๊ฐ์ฒด๊ฐ€ ๊ฐ€์ง€๋Š” ์†์„ฑ์€ ์ฑ… ์ด๋ฆ„ ์™ธ์—๋„ ๋งŽ์„ ๊ฒƒ์ด๋‹ค. ๋”ฐ๋ผ์„œ ํ•œ ๊ถŒ์˜ ์ฑ…๋งŒ ๊ฒ€์ƒ‰ํ•˜๊ธฐ ์œ„ํ•ด, ISBN์ด "9780674430006์ธ ์กฐ๊ฑด์„ ๊ฑธ์–ด์ฃผ์ž. ์ด ๋ฐฉ์‹์œผ๋กœ ์„œ๋ฒ„์— ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ , ์„œ๋ฒ„๊ฐ€ ํ•ด๋‹น ์š”์ฒญ์„ ํ•ด๊ฒฐํ•œ๋‹ค๋ฉด, ๋Œ์•„์˜จ ์ฟผ๋ฆฌ๋Š” ์ด๋Ÿด ๊ฒƒ์ด๋‹ค.

{
	์ฑ… : {
		์ฑ… ์ด๋ฆ„ : "GraphQL์€ ์–ด๋ ต์ง€ ์•Š๋‹ค",
		์ €์ž : [
			{ ์ด๋ฆ„ : "๊น€์ฝ”๋”ฉ"},
			{ ์ด๋ฆ„ : "๋ฐ•ํ•ด์ปค"},
		]
	}
}

๊ทธ๋Ÿผ ์ด๊ฒƒ์„ ๊ทธ๋ž˜ํ”„์˜ ๊ด€์ ์—์„œ ๋ณธ๋‹ค๋ฉด ์–ด๋–จ๊นŒ?


[๊ทธ๋ฆผ] GraphQL๋กœ ์ฟผ๋ฆฌํ•œ ๊ฒƒ์„ ๊ทธ๋ž˜ํ”„์˜ ๊ด€์ ์œผ๋กœ ๋„์‹ํ™”

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


[๊ทธ๋ฆผ] GraphQL๋กœ ์ฟผ๋ฆฌํ•œ ๊ฒƒ์„ ํŠธ๋ฆฌ ๊ตฌ์กฐ๋กœ ๋„์‹ํ™”

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

โœจ GraphQL์˜ ํŠน์ง•

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

๐Ÿ“Œ GraphQL VS REST API

โœจ REST API์˜ ํ•œ๊ณ„

์•ž์„œ ๋‹ค๋ฃฌ REST API๋ผ๋Š” ๋ฐฉ๋ฒ•๋ก ์ด ์žˆ์Œ์—๋„ ์™œ GraphQL์ด ํƒ„์ƒํ–ˆ์„๊นŒ? ์˜ˆ์ œ๋ฅผ ํ†ตํ•ด REST API์˜ ํ•œ๊ณ„์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์ž.


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

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

โœจ REST API๋กœ Blog ์•ฑ์„ ๊ตฌํ˜„ํ•  ๋•Œ

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

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

 

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

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

๊ทธ๋Ÿฌ๋ฏ€๋กœ REST API์™€ GraphQL์€ ์ด๋Ÿฐ ๋ถ€๋ถ„์—์„œ ๋‹ค๋ฅด๋‹ค๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

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

- REST API๋Š” ์—ฌ๋Ÿฌ Resource์— ์ ‘๊ทผํ•˜๊ณ ์ž ํ•  ๋•Œ ์—ฌ๋Ÿฌ ๋ฒˆ์˜ ์š”์ฒญ์ด ํ•„์š”ํ•˜์ง€๋งŒ, GraphQL์—์„œ๋Š” ํ•œ๋ฒˆ์˜ ์š”์ฒญ์—์„œ ์—ฌ๋Ÿฌ Resource์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.

  • REST API์—์„œ ๊ฐ ์š”์ฒญ์€ ํ•ด๋‹น ์—”๋“œํฌ์ธํŠธ์— ์ •์˜๋œ ํ•ธ๋“ค๋ง ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜์ง€๋งŒ, GraphQL์—์„œ๋Š” ์š”์ฒญ ๋ฐ›์€ ๊ฐ ํ•„๋“œ์— ๋Œ€ํ•œ resolver๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•œ๋‹ค.

๐Ÿ“Œ GraphQL์˜ ์žฅ๋‹จ์ 

์œ„์™€ ๊ฐ™์€ REST API์˜ ํ•œ๊ณ„๋•Œ๋ฌธ์— ์ •๋ณด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ธก์—์„œ ์›ํ•˜๋Š” ๋Œ€๋กœ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๊ณ , ๋ณด๋‹ค ํŽธํ•˜๊ฒŒ ์ •๋ณด๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ํ‘œ์ค€ํ™”๋œ Query language ๋ฅผ ๋งŒ๋“ค๊ฒŒ ๋˜์—ˆ๊ณ  ์ด๊ฒƒ์ด GraphQL์ด๋‹ค. ๋™์ผํ•œ ์˜ˆ์ œ๋ฅผ ํ†ตํ•ด GraphQL์˜ ์žฅ์ ์„ ์•Œ์•„๋ณด์ž.

โœจ GraphQL๋กœ Blog ์•ฑ์„ ๊ตฌํ˜„ํ•  ๋•Œ

 

โœจ ์žฅ์ 

  • ํ•˜๋‚˜์˜ endpoint ์š”์ฒญ
    /graphql์ด๋ผ๋Š” ํ•˜๋‚˜์˜ endpoint ๋กœ ์š”์ฒญ์„ ๋ฐ›๊ณ  ๊ทธ ์š”์ฒญ์— ๋”ฐ๋ผ query , mutation์„ resolver ํ•จ์ˆ˜๋กœ ์ „๋‹ฌํ•ด์„œ ์š”์ฒญ์— ์‘๋‹ตํ•œ๋‹ค. ๋ชจ๋“  ํด๋ผ์ด์–ธํŠธ ์š”์ฒญ์€ POST ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
  • No! under & overfetching
    ์—ฌ๋Ÿฌ ๊ฐœ์˜ endpoint ์š”์ฒญ์„ ํ•  ํ•„์š”์—†์ด ํ•˜๋‚˜์˜ endpoint์—์„œ ์ฟผ๋ฆฌ๋ฅผ ์ด์šฉํ•ด ์›ํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ •ํ™•ํ•˜๊ฒŒ API์— ์š”์ฒญํ•˜๊ณ  ์‘๋‹ต์œผ๋กœ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.
  • ๊ฐ•๋ ฅํ•œ playground
    graphql ์„œ๋ฒ„๋ฅผ ์‹คํ–‰ํ•˜๋ฉด playground๋ผ๋Š” GUI๋ฅผ ์ด์šฉํ•ด resolver ์™€ schema ๋ฅผ ํ•œ ๋ˆˆ์— ๋ณด๊ณ  ํ…Œ์ŠคํŠธ ํ•ด ๋ณผ ์ˆ˜ ์žˆ๋‹ค. (POSTMAN ๊ณผ ๋น„์Šท)
  • ํด๋ผ์ด์–ธํŠธ ๊ตฌ์กฐ ๋ณ€๊ฒฝ์—๋„ ์ง€์žฅ์ด ์—†์Œ
    ํด๋ผ์ด์–ธํŠธ ๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€Œ์–ด๋„ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฒฐ์ •ํ•˜๊ณ  ๋ฐ›๋Š” ์ฃผ์ฒด๊ฐ€ ํด๋ผ์ด์–ธํŠธ์ด๊ธฐ ๋•Œ๋ฌธ์— ์„œ๋ฒ„์— ์ง€์žฅ์ด ์—†๋‹ค. ํด๋ผ์ด์–ธํŠธ์—์„œ๋Š” ๋ฌด์Šจ ๋ฐ์ดํ„ฐ๊ฐ€ ํ•„์š”ํ•œ ์ง€์— ๋Œ€ํ•ด์„œ๋งŒ ์š”๊ตฌ์‚ฌํ•ญ์„ ์ฟผ๋ฆฌ๋กœ ์ž‘์„ฑํ•˜๋ฉด ๋œ๋‹ค.

โœจ GraphQL์˜ ๋‹จ์ 

์•ž์„  ์˜ˆ์ œ๋งŒ ๋ณด๋ฉด GraphQL์ด ๊ธฐ์กด REST API ๋ฐฉ์‹์ด ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๋ชจ๋“  ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ๋งŒ๋Šฅํ‚ค๋กœ ๋ณด์ด์ง€๋งŒ GraphQL์—๋„ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋‹จ์ ์ด ์กด์žฌํ•œ๋‹ค.

  • REST API์— ์นœ์ˆ™ํ•œ ๊ฐœ๋ฐœ์ž์˜ ๊ฒฝ์šฐ GraphQL๋ฅผ ํ•™์Šตํ•˜๋Š” ๋ฐ ์‹œ๊ฐ„์ด ํ•„์š”ํ•˜๋‹ค.
  • ์บ์‹ฑ์ด REST๋ณด๋‹ค ํ›จ์”ฌ ๋ณต์žกํ•˜๋‹ค.
    HTTP์—์„  ๊ฐ ๋ฉ”์†Œ๋“œ์— ๋”ฐ๋ผ ์บ์‹ฑ์ด ๊ตฌํ˜„๋˜์–ด ์žˆ๋‹ค. ํ•˜์ง€๋งŒ GraphQL์—์„  POST ๋ฉ”์†Œ๋“œ๋งŒ์„ ์ด์šฉํ•ด ์š”์ฒญ์„ ๋ณด๋‚ด๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ ๋ฉ”์†Œ๋“œ์— ๋”ฐ๋ฅธ ์บ์‹ฑ์„ ์ง€์›๋ฐ›์„ ์ˆ˜ ์—†๋‹ค. ๊ทธ๋ž˜์„œ ์ด๋ฅผ ๋ณด์™„ํ•˜๊ธฐ ์œ„ํ•ด Apollo ์—”์ง„์˜ ์บ์‹ฑ๊ณผ ์˜์† ์ฟผ๋ฆฌ ๋“ฑ์ด ๋“ฑ์žฅํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค.
  • ๊ณ ์ •๋œ ์š”์ฒญ๊ณผ ์‘๋‹ต๋งŒ ํ•„์š”ํ•  ๊ฒฝ์šฐ์—๋Š” Query ๋กœ ์ธํ•ด ์š”์ฒญ์˜ ํฌ๊ธฐ๊ฐ€ RESTful API ์˜ ๊ฒฝ์šฐ๋ณด๋‹ค ๋” ์ปค์ง„๋‹ค.

๐Ÿ“Œ GraphQL ๊ตฌ์กฐ

โœจ GraphQL Keywords

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

๋” ๋‚˜์•„๊ฐ€ GraphQL์—์„œ๋Š” ๊ตฌ๋…(Subscription)์ด๋ผ๋Š” ๊ฐœ๋…์„ ์ œ๊ณตํ•˜๋ฉฐ ์ด๋ฅผ ์ด์šฉํ•ด ์‹ค์‹œ๊ฐ„ ์—…๋ฐ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

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

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

๐Ÿ“Œ ์ฟผ๋ฆฌ(query, ๋ฐ์ดํ„ฐ ์กฐํšŒ)

โœจ ํ•„๋“œ(field)

๋งค์šฐ ๊ฐ„๋‹จํ•œ query(๋ฐ์ดํ„ฐ ์กฐํšŒ, ์ดํ•˜ ์ฟผ๋ฆฌ)์™€ ์‹คํ–‰ ํ–ˆ์„ ๋•Œ ์–ป์€ ๊ฒฐ๊ณผ๋ถ€ํ„ฐ ์‚ดํŽด๋ณด์ž.

{
  hero {
    name
  }
}

[์ฝ”๋“œ] hero์˜ name์„ ์ฟผ๋ฆฌ

{
  "data": {
    "hero": {
      "name": "R2-D2"
    }
  }
}

[์ฝ”๋“œ] ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ–ˆ์„ ๋•Œ์˜ ๊ฒฐ๊ณผ

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

์ด๋ฒˆ์—๋Š” ๋‹ค๋ฅธ ์˜ˆ์‹œ๋ฅผ ์‚ดํŽด๋ณด์ž.

{
  hero {
    name
    # ์ด๋Ÿฐ ์‹์œผ๋กœ GraphQL ๋‚ด์—์„œ ์ฃผ์„๋„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.
    friends {
      name
    }
  }
}

[์ฝ”๋“œ] ํžˆ์–ด๋กœ์˜ ์ด๋ฆ„๊ณผ ํžˆ์–ด๋กœ์˜ ์นœ๊ตฌ ์ด๋ฆ„์„ ๊ฐ™์ด ์ฟผ๋ฆฌ

{
  "data": {
    "hero": {
      "name": "R2-D2",
      "friends": [
        {
          "name": "Luke Skywalker"
        },
        {
          "name": "Han Solo"
        },
        {
          "name": "Leia Organa"
        }
      ]
    }
  }
}

[์ฝ”๋“œ] ํžˆ์–ด๋กœ์˜ ์ด๋ฆ„๊ณผ ํžˆ์–ด๋กœ์˜ ์นœ๊ตฌ์˜ ์ด๋ฆ„์ด ์กฐํšŒ๋˜์–ด ๋‚˜์˜จ๋‹ค.

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

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

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

{
  human(id: "1000") {
    name
    height
  }
}

[์ฝ”๋“œ] id๊ฐ€ 1000์ธ human์˜ name๊ณผ height๋ฅผ ์ฟผ๋ฆฌ

{
  "data": {
    "human": {
      "name": "Luke Skywalker",
      "height": 1.72
    }
  }
}

[์ฝ”๋“œ] ์ฟผ๋ฆฌ ๊ฒฐ๊ณผ

์ด๋Ÿฐ ์‹์œผ๋กœ id๊ฐ€ 1000์ธ human์˜ ์ด๋ฆ„๊ณผ ํ‚ค๋ฅผ ์ฟผ๋ฆฌํ•ด ์˜ฌ ์ˆ˜ ์žˆ๋‹ค. REST์™€ ๊ฐ™์€ ์‹œ์Šคํ…œ์—์„œ๋Š” ๋‹จ์ผ ์ธ์ˆ˜ ์ง‘ํ•ฉ(์š”์ฒญ์˜ ์ฟผ๋ฆฌ ๋งค๊ฐœ๋ณ€์ˆ˜ ๋ฐ URL ์„ธ๊ทธ๋จผํŠธ)๋งŒ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด REST API๋ฅผ ์ด์šฉํ•œ๋‹ค๋ฉด ?id=1000 ์ด๊ฑฐ๋‚˜ /1000(/:id)์ผ ๋•Œ์™€ ๊ฐ™์€ ๋ชฉ์ ์œผ๋กœ ์ฟผ๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

โœจ ๋ณ„๋ช…(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 keyword์™€ query name์„ ์ž‘์„ฑํ•œ๋‹ค.

{
  "data": {
    "hero": {
      "name": "R2-D2",
      "friends": [
        {
          "name": "Luke Skywalker"
        },
        {
          "name": "Han Solo"
        },
        {
          "name": "Leia Organa"
        }
      ]
    }
  }
}

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

โœจ ๋ณ€์ˆ˜(Variables)

์—ฌํƒœ๊ป ๊ณ ์ •๋œ ์ธ์ˆ˜๋ฅผ ๋ฐ›์•„ ์ฟผ๋ฆฌํ–ˆ์ง€๋งŒ, ์‹ค์ œ ์•ฑ์„ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ๊ณ ์ •๋œ ์ธ์ˆ˜๋ฅผ ๋ฐ›๋Š” ๊ฒƒ๋ณด๋‹ค๋Š” ๋™์ ์œผ๋กœ ์ธ์ˆ˜๋ฅผ ๋ฐ›์•„ ์ฟผ๋ฆฌํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋Œ€๋‹ค์ˆ˜์ด๋‹ค. ๋ณ€์ˆ˜๋Š” ๊ทธ๋Ÿฐ ์ธ์ˆ˜๋“ค์„ ๋™์ ์œผ๋กœ ๋ฐ›๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

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

[์ฝ”๋“œ] ๋ณ€์ˆ˜๋ฅผ ์จ์„œ ์ž‘์„ฑ๋œ ์ฟผ๋ฆฌ

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

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

GraphQL์€ ๋Œ€๊ฐœ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐ์— ์ค‘์ ์„ ๋‘๊ณ  ์žˆ์ง€๋งŒ ์„œ๋ฒ„์ธก ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•˜๊ธฐ๋„ ํ•œ๋‹ค.

REST API์—์„œ GET ์š”์ฒญ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ , POST ํ˜น์€ PUT ์š”์ฒญ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ 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๋ผ ๋ถ€๋ฅธ๋‹ค.

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 () => {
      ...
		}
  }
};

GraphQL์—์„œ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ตฌ์ฒด์ ์ธ ๊ณผ์ •์„ ์ง์ ‘ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜๋Š”๋ฐ ์ด์™€ ๊ฐ™์€ ์ž‘์—…(e.g. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ฟผ๋ฆฌ, ์›๊ฒฉ API ์š”์ฒญ)์„ Resolver๊ฐ€ ๋‹ด๋‹นํ•˜๊ฒŒ ๋œ๋‹ค.