Jieunny์˜ ๋ธ”๋กœ๊ทธ

S4) Unit 6. [API] GraphQL ๋ณธ๋ฌธ

CodeStates/learning contents

S4) Unit 6. [API] GraphQL

Jieunny 2023. 3. 28. 13:30

๐Ÿ“ฃ  GraphQL

๐Ÿญ. GraphQL ์ด๋ž€?

โœ”๏ธ Facebook์—์„œ ์ฒ˜์Œ์œผ๋กœ ๊ฐœ๋ฐœํ–ˆ๊ณ , ์˜คํ”ˆ ์†Œ์Šค๋กœ ์ œ๊ณต๋œ ์ฟผ๋ฆฌ ์–ธ์–ด

โžฐ Graph + Query Language

โžฐ Query Language ์ค‘์—์„œ๋„ Server API ๋ฅผ ํ†ตํ•ด ์ •๋ณด๋ฅผ ์ฃผ๊ณ ๋ฐ›๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” Query Language

 

๐Ÿฎ. ์™œ GraphQL ๋ฅผ ์‚ฌ์šฉํ• ๊นŒ?

โœ”๏ธ GraphQL์€ REST API ๋ฐฉ์‹์˜ ๊ณ ์ •๋œ ์ž์›์ด ์•„๋‹Œ ํด๋ผ์ด์–ธํŠธ ์š”์ฒญ์— ๋”ฐ๋ผ ์œ ์—ฐํ•˜๊ฒŒ ์ž์›์„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

โžฐ GraphQL์—์„œ๋Š” ๋ชจ๋“  ๋ฐ์ดํ„ฐ๊ฐ€ ๊ทธ๋ž˜ํ”„ ํ˜•ํƒœ๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋‹ค๊ณ  ์ „์ œํ•œ๋‹ค.

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

 

๐Ÿฏ. GraphQL๋กœ ๊ทธ๋ž˜ํ”„ ์ˆœํšŒ

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

โžฐ ์—”ํ‹ฐํ‹ฐ : ์‚ฌ๋ฌผ์˜ ๊ตฌ์กฐ๋‚˜ ์ƒํƒœ, ๋™์ž‘ ๋“ฑ์„ ๋ชจ๋ธ๋กœ ํ‘œํ˜„ํ•˜๋Š” ๊ฒฝ์šฐ, ๊ทธ ๋ชจ๋ธ์˜ ๊ตฌ์„ฑ์š”์†Œ

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

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

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

 

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

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

// ์œ„์˜ ๊ทธ๋ž˜ํ”„์—์„œ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ์ฟผ๋ฆฌ
// ์œ„ ์ฟผ๋ฆฌ๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด๋ฉด 

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

// ์ด๋ ‡๊ฒŒ ์ฟผ๋ฆฌ๊ฐ€ ๋Œ์•„์˜จ๋‹ค.

1. ISBN ๋ฒˆํ˜ธ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์„ ํƒํ•œ '์ฑ…' ๋…ธ๋“œ์—์„œ ์‹œ์ž‘ํ•œ๋‹ค.

2. GraphQL์€ ์ค‘์ฒฉ๋œ ๊ฐ ํ•„๋“œ๋กœ ํ‘œ์‹œ๋œ ๊ฐ„์„ ์„ ๋”ฐ๋ผ ๊ทธ๋ž˜ํ”„๋ฅผ ํƒ์ƒ‰ํ•˜๊ธฐ ์‹œ์ž‘ํ•œ๋‹ค.

3. ์ฟผ๋ฆฌ ๋‚ด ์ค‘์ฒฉ๋œ “์ฑ… ์ด๋ฆ„” ํ•„๋“œ๋ฅผ ํ†ตํ•ด ์ฑ…์˜ ์ œ๋ชฉ์ด ์žˆ๋Š” ๋…ธ๋“œ๋กœ ์ด๋™ํ•œ๋‹ค.

4. “์ €์ž”๋กœ ๋ ˆ์ด๋ธ”์ด ์ง€์ •๋œ “์ฑ…”์˜ ๊ฐ„์„ ์„ ๋”ฐ๋ผ๊ฐ€ “์ €์ž” ๋…ธ๋“œ๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ , ๊ฐ ์ €์ž์˜ “์ด๋ฆ„"์„ ์–ป์–ด์˜จ๋‹ค.

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

โžฐ GraphQL์€ ํŠธ๋ฆฌ ๊ตฌ์กฐ๋กœ ์ฟผ๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›๊ธฐ ์œ„ํ•ด ๊ทธ๋ž˜ํ”„๋ฅผ ํƒ์ƒ‰ํ•˜๋Š” ์ฟผ๋ฆฌ ์–ธ์–ด

 

๐Ÿฐ. GraphQL์˜ ํŠน์ง•

1๏ธโƒฃ GraphQL์€ HTTP๋ฅผ ํ†ตํ•ด API ์„œ๋ฒ„๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ  ์‘๋‹ต์„ ๋ฐ›๋Š”๋‹ค.

2๏ธโƒฃ ์‘๋‹ต์„ ๋ฐ›์„ ์‹œ, ๋ฐ์ดํ„ฐ ๊ฒฐ๊ณผ๋ฅผ JSON ํ˜•์‹์œผ๋กœ ๋ฐ›๋Š”๋‹ค.

3๏ธโƒฃ GraphQL์€ ์„œ๋ฒ„ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ž‘์„ฑํ•œ ๊ฐ ํ•„๋“œ์— ๋Œ€์‘ํ•˜๋Š” resolver ํ•จ์ˆ˜๋กœ ๊ฐ ํ•„๋“œ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค.

4๏ธโƒฃ GraphQL์€ GraphQL ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์กฐํšŒ ๋Œ€์ƒ schema๊ฐ€ ์œ ํšจํ•œ์ง€ ๊ฒ€์‚ฌํ•œ๋‹ค.


๐Ÿ“ฃ  GraphQL vs REST API

Q. ์ด๋ฏธ REST API๋ผ๋Š” ๋ฐฉ๋ฒ•๋ก ์ด ์กด์žฌํ•˜๊ณ  ์žˆ์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ์™œ GraphQL์ด ํƒ„์ƒํ–ˆ์„๊นŒ?

๐Ÿญ. REST API์˜ ํ•œ๊ณ„

1๏ธโƒฃ Overfetch :  ํ•„์š” ์—†๋Š” ๋ฐ์ดํ„ฐ๊นŒ์ง€ ์ œ๊ณตํ•œ๋‹ค.

2๏ธโƒฃ Underfetch: endpoint ๊ฐ€ ํ•„์š”ํ•œ ์ •๋ณด๋ฅผ ์ถฉ๋ถ„ํžˆ ์ œ๊ณตํ•˜์ง€ ๋ชปํ•œ๋‹ค.

โžฐ ํด๋ผ์ด์–ธํŠธ๋Š” ํ•„์š”ํ•œ ์ •๋ณด๋ฅผ ๋ชจ๋‘ ํ™•๋ณดํ•˜๊ธฐ ์œ„ํ•˜์—ฌ ์ถ”๊ฐ€์ ์ธ ์š”์ฒญ์„ ๋ณด๋‚ด์•ผ ํ•œ๋‹ค.3๏ธโƒฃ ํด๋ผ์ด์–ธํŠธ ๊ตฌ์กฐ ๋ณ€๊ฒฝ ์‹œ ์—”๋“œํฌ์ธํŠธ ๋ณ€๊ฒฝ ๋˜๋Š” ๋ฐ์ดํ„ฐ ์ˆ˜์ •์ด ํ•„์š”ํ•˜๋‹ค.

โžฐ REST API์—์„œ๋Š” ์ž์›์˜ ํฌ๊ธฐ์™€ ํ˜•ํƒœ๋ฅผ ์„œ๋ฒ„์—์„œ ๊ฒฐ์ •ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ง์ ‘ ๋ฐ์ดํ„ฐ์˜ ํ˜•ํƒœ๋ฅผ ๊ฒฐ์ •ํ•  ์ˆ˜ ์—†๋‹ค.

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

 

๐Ÿฎ. REST API์™€ GraphQL์˜ ๋‹ค๋ฅธ์ 

(์™ผ) REST API / (์˜ค) GraphQL

1๏ธโƒฃ REST API๋Š” Resource์— ๋Œ€ํ•œ ํ˜•ํƒœ ์ •์˜์™€ ๋ฐ์ดํ„ฐ ์š”์ฒญ ๋ฐฉ๋ฒ•์ด ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์ง€๋งŒ, GraphQL์—์„œ๋Š” Resource์— ๋Œ€ํ•œ ํ˜•ํƒœ ์ •์˜์™€ ๋ฐ์ดํ„ฐ ์š”์ฒญ์ด ์™„์ „ํžˆ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ๋‹ค.

2๏ธโƒฃ REST API๋Š” Resource์˜ ํฌ๊ธฐ์™€ ํ˜•ํƒœ๋ฅผ ์„œ๋ฒ„์—์„œ ๊ฒฐ์ •ํ•˜์ง€๋งŒ, GraphQL์—์„œ๋Š” Resource์— ๋Œ€ํ•œ ์ •๋ณด๋งŒ ์ •์˜ํ•˜๊ณ , ํ•„์š”ํ•œ ํฌ๊ธฐ์™€ ํ˜•ํƒœ๋Š” ํด๋ผ์ด์–ธํŠธ ๋‹จ์—์„œ ์š”์ฒญ ์‹œ ๊ฒฐ์ •ํ•œ๋‹ค.

3๏ธโƒฃ REST API๋Š” URI๊ฐ€ Resource๋ฅผ ๋‚˜ํƒ€๋‚ด๊ณ  Method๊ฐ€ ์ž‘์—…์˜ ์œ ํ˜•์„ ๋‚˜ํƒ€๋‚ด์ง€๋งŒ, GraphQL์—์„œ๋Š” GraphQL Schema๊ฐ€ Resource๋ฅผ ๋‚˜ํƒ€๋‚ด๊ณ  Query, Mutation ํƒ€์ž…์ด ์ž‘์—…์˜ ์œ ํ˜•์„ ๋‚˜ํƒ€๋‚ธ๋‹ค.

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

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

 

๐Ÿฏ. GraphQL์˜ ์žฅ์ 

1๏ธโƒฃ ํ•˜๋‚˜์˜ endpoint ์š”์ฒญ

โžฐ /graphql์ด๋ผ๋Š” ํ•˜๋‚˜์˜ endpoint ๋กœ ์š”์ฒญ์„ ๋ฐ›๊ณ  ๊ทธ ์š”์ฒญ์— ๋”ฐ๋ผ query , mutation์„ resolver ํ•จ์ˆ˜๋กœ ์ „๋‹ฌํ•ด์„œ ์š”์ฒญ์— ์‘๋‹ตํ•œ๋‹ค.

โžฐ ๋ชจ๋“  ํด๋ผ์ด์–ธํŠธ ์š”์ฒญ์€ POST ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

2๏ธโƒฃ No under & overfetching

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

3๏ธโƒฃ ๊ฐ•๋ ฅํ•œ playground

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

4๏ธโƒฃ ํด๋ผ์ด์–ธํŠธ ๊ตฌ์กฐ ๋ณ€๊ฒฝ์—๋„ ์ง€์žฅ์ด ์—†๋‹ค.

โžฐ ํด๋ผ์ด์–ธํŠธ ๊ตฌ์กฐ๊ฐ€ ๋ฐ”๋€Œ์–ด๋„ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฒฐ์ •ํ•˜๊ณ  ๋ฐ›๋Š” ์ฃผ์ฒด๊ฐ€ ํด๋ผ์ด์–ธํŠธ์ด๊ธฐ ๋•Œ๋ฌธ์— ์„œ๋ฒ„์— ์ง€์žฅ์ด ์—†๋‹ค

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

 

๐Ÿฐ. GraphQL์˜ ๋‹จ์ 

1๏ธโƒฃ REST API์— ์นœ์ˆ™ํ•œ ๊ฐœ๋ฐœ์ž์˜ ๊ฒฝ์šฐ GraphQL๋ฅผ ํ•™์Šตํ•˜๋Š” ๋ฐ ์‹œ๊ฐ„์ด ํ•„์š”ํ•˜๋‹ค.

2๏ธโƒฃ ์บ์‹ฑ์ด REST๋ณด๋‹ค ํ›จ์”ฌ ๋ณต์žกํ•˜๋‹ค.

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

โžฐ ์ด๋ฅผ ๋ณด์™„ํ•˜๊ธฐ ์œ„ํ•ด Apollo ์—”์ง„์˜ ์บ์‹ฑ๊ณผ ์˜์† ์ฟผ๋ฆฌ ๋“ฑ์ด ๋“ฑ์žฅํ–ˆ๋‹ค.

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


๐Ÿ“ฃ  GraphQL ๊ตฌ์กฐ

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

โœ”๏ธ ํ•„๋“œ(field)

{
  hero {
    name
  }
}
// hero์˜ name์„ ์ฟผ๋ฆฌ

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

// ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ–ˆ์„ ๋•Œ์˜ ๊ฒฐ๊ณผ

---------------------------------------------------------------

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

// ํžˆ์–ด๋กœ์˜ ์ด๋ฆ„๊ณผ ํžˆ์–ด๋กœ์˜ ์นœ๊ตฌ ์ด๋ฆ„์„ ๊ฐ™์ด ์ฟผ๋ฆฌ

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

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

โžฐ ํ•„๋“œ์˜ name์€ String ํƒ€์ž…์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

โžฐ ์ฟผ๋ฆฌ์™€ ๊ฒฐ๊ณผ๊ฐ€ ์ •ํ™•ํ•˜๊ฒŒ ๊ฐ™์€ ๋ชจ์–‘์„ ํ•˜๊ณ  ์žˆ์Œ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ด ๋ถ€๋ถ„์€ GraphQL์— ์žˆ์–ด์„œ ํ•„์ˆ˜์ ์ด๋‹ค.

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

 

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

โžฐ friends ํ•„๋“œ๋Š” ๋ฐฐ์—ด์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

โžฐ 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 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
    }
  }
}

โžฐ ์˜คํผ๋ ˆ์ด์…˜ ๋„ค์ž„ ์˜†์— ๋ณ€์ˆ˜๋ฅผ $๋ณ€์ˆ˜ ์ด๋ฆ„: ํƒ€์ž… ํ˜•ํƒœ ๋กœ ์ •์˜ํ•œ๋‹ค.

 

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

โœ”๏ธ GraphQL์€ ์„œ๋ฒ„์ธก ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•˜๊ธฐ๋„ ํ•œ๋‹ค.

โžฐ mutation์ด๋ผ๋Š” ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋ฒ„ ์ธก ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•œ๋‹ค.

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

 

๐Ÿฏ. ์Šคํ‚ค๋งˆ/ํƒ€์ž…(Schema/Type)

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

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

โžฐ Character๋Š” GraphQL ๊ฐ์ฒด ํƒ€์ž…(ํ•„๋“œ๊ฐ€ ์žˆ๋Š” ํƒ€์ž…)์ด๋‹ค.

    ใ„ด ์Šคํ‚ค๋งˆ์— ์žˆ๋Š” ๋Œ€๋ถ€๋ถ„์˜ ํƒ€์ž…์€ ๊ฐ์ฒด ํƒ€์ž…

โžฐ name ๊ณผ appearIn ์€ Character ํƒ€์ž…์˜ ํ•„๋“œ์ด๋‹ค.

    ใ„ด name ๊ณผ appearIn ์€ GraphQL ์ฟผ๋ฆฌ์˜ Character ํƒ€์ž… ์–ด๋””์„œ๋“  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ•„๋“œ

โžฐ String์€ ๋‚ด์žฅ๋œ ์Šค์นผ๋ผ ํƒ€์ž… ์ค‘ ํ•˜๋‚˜์ด๋‹ค.

    ใ„ด ๋‹จ์ผ ์Šค์นผ๋ผ ๊ฐ์ฒด๋กœ ํ™•์ธ๋˜๋Š” ์œ ํ˜•์ด๋ฉฐ ์ฟผ๋ฆฌ์—์„œ ํ•˜์œ„ ์„ ํƒ์„ ๊ฐ€์งˆ ์ˆ˜ ์—†๋‹ค.

    ใ„ด ์Šค์นผ๋ผ ํƒ€์ž…์—๋Š” ID, Int๋„ ์žˆ๋‹ค.

 

๐Ÿฐ. ๋ฆฌ์กธ๋ฒ„(Resolver)

โœ”๏ธ ์š”์ฒญ์— ๋Œ€ํ•œ ์‘๋‹ต์„ ๊ฒฐ์ •ํ•ด์ฃผ๋Š” ํ•จ์ˆ˜๋กœ, GraphQL์˜ ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ํƒ€์ž… ์ค‘ Query, Mutation, Subscription๊ณผ ๊ฐ™์€ ํƒ€์ž…์˜ ์‹ค์ œ ์ผํ•˜๋Š” ๋ฐฉ์‹(๋กœ์ง)์„ ์ž‘์„ฑํ•œ๋‹ค.

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์—์„œ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ตฌ์ฒด์ ์ธ ๊ณผ์ •์„ ์ง์ ‘ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜๋ฏ€๋กœ ์ด์™€ ๊ฐ™์€ ์ž‘์—…์€ Resolver๊ฐ€ ๋‹ด๋‹นํ•œ๋‹ค.