Hello Ocean! ๐ŸŒผ

[TIL] ํ”„๋ฆฌ์˜จ๋ณด๋”ฉ ๋‘ ๋ฒˆ์งธ ๊ณผ์ œ_MAPIA ๋ณธ๋ฌธ

TIL

[TIL] ํ”„๋ฆฌ์˜จ๋ณด๋”ฉ ๋‘ ๋ฒˆ์งธ ๊ณผ์ œ_MAPIA

bba_dda 2021. 11. 25. 02:35
๋ฐ˜์‘ํ˜•

๋‘ ๋ฒˆ์งธ ๊ณผ์ œ ๐Ÿ”ฅ 

11์›” 4์ผ ~ 11์›” 6์ผ๊นŒ์ง€ ๋‘ ๋ฒˆ์งธ ๊ณผ์ œ๋ฅผ ์ง„ํ–‰ํ–ˆ๋‹ค.

๋‘ ํšŒ์‚ฌ์˜ ๊ณผ์ œ์ค‘์— ์›ํ•˜๋Š” ๊ฒƒ์„ ๊ณจ๋ผ์„œ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ด์—ˆ๋Š”๋ฐ,

ํ•œ ๊ณผ์ œ๋Š” ๋ณดํŽธ์ ์œผ๋กœ ๋งŽ์ด ์“ฐ์ผ ๊ฒƒ ๊ฐ™์€ ๋‚ด์šฉ์ด์—ˆ๊ณ ,

ํ•œ ๊ณผ์ œ๋Š” graphDB์™€ graphQL์„ ์ด์šฉํ•œ ์ƒ‰๋‹ค๋ฅธ ๋‚ด์šฉ์ด์—ˆ๋‹ค.

์šฐ๋ฆฌํŒ€์€ ๋งŒ์žฅ์ผ์น˜๋กœ ์ƒ‰๋‹ค๋ฅธ ๋‚ด์šฉ์˜ ๋งˆํ”ผ์•„์ปดํผ๋‹ˆ ๊ณผ์ œ๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ธฐ๋กœ ํ–ˆ๋‹ค.

์‚ฌ์‹ค ๊ณผ์ œ๋ฅผ ์ •ํ•  ๋•Œ ์ข€ ๋†€๋ž๋‹ค. ๋ณดํŽธ์ ์œผ๋กœ ๋งŽ์ด ์“ฐ์ด๋Š” ๋‚ด์šฉ์„ ์„ ํƒํ•˜๋Š” ํŒ€์›์ด ์žˆ์„ ์ค„ ์•Œ์•˜๋Š”๋ฐ,

๋‹ค๋“ค ์žฌ๋ฏธ์žˆ์–ด ๋ณด์ด๊ณ , ๋„์ „์ ์ธ ๊ณผ์ œ๋ฅผ ์„ ํƒํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋ชจ๋‘ ๊ฐ™์€ ์ƒ๊ฐ์ด๋ผ๋Š” ๊ฒƒ์ด ์ข‹์•˜๋‹ค.

์Œ์•… ์ŠคํŠธ๋ฆฌ๋ฐ ์„œ๋น„์Šค์—์„œ, ๋ฎค์ง€์…˜, ๊ณก, ์•จ๋ฒ”์˜ ์„ธ ๊ฐ€์ง€ ์š”์†Œ๊ฐ€ ์กด์žฌํ•  ๋•Œ, CRUD API๋ฅผ ๊ตฌ์„ฑํ•ด์•ผ ํ–ˆ๋‹ค.

 

ํ™”๋ฉด๋ณ„ Read API ์š”๊ตฌ์‚ฌํ•ญ (GraphQL)

๊ณก ํŽ˜์ด์ง€

โœ… ํ•ด๋‹น ๊ณก์ด ์†ํ•œ ์•จ๋ฒ”์„ ๊ฐ€์ ธ์˜ค๋Š” API

โœ… ํ•ด๋‹น ๊ณก์„ ์“ด ๋ฎค์ง€์…˜ ๋ชฉ๋ก์„ ๊ฐ€์ ธ์˜ค๋Š” API

 

์•จ๋ฒ” ํŽ˜์ด์ง€

โœ… ํ•ด๋‹น ์•จ๋ฒ”์„ ์“ด ๋ฎค์ง€์…˜ ๋ชฉ๋ก ๊ฐ€์ ธ์˜ค๋Š” API

โœ… ํ•ด๋‹น ์•จ๋ฒ”์˜ ๊ณก ๋ชฉ๋ก์„ ๊ฐ€์ ธ์˜ค๋Š” API

 

๋ฎค์ง€์…˜ ํŽ˜์ด์ง€

โœ… ํ•ด๋‹น ๋ฎค์ง€์…˜์˜ ๋ชจ๋“  ์•จ๋ฒ” API

โœ… ํ•ด๋‹น ๋ฎค์ง€์…˜์˜ ๊ณก ๋ชฉ๋ก ๊ฐ€์ ธ์˜ค๋Š” API

 

Create, Update, Delete API ์š”๊ตฌ์‚ฌํ•ญ (RESTful API)

โœ… ์•จ๋ฒ” ์ƒ์„ฑ API

โœ… ๋ฎค์ง€์…˜ - ๊ณก ์—ฐ๊ฒฐ

โœ… ๊ณก - ์•จ๋ฒ” ์—ฐ๊ฒฐ

โœ… ๊ณก - ์•จ๋ฒ”์—ฐ๊ฒฐํ•ด์ œ API

โœ… ๋ฎค์ง€์…˜ - ๊ณก ์—ฐ๊ฒฐํ•ด์ œ API

โœ… ๋ฎค์ง€์…˜ ์ƒ์„ฑ API

โœ… ๊ณก ์ƒ์„ฑ API

 

github Repository ์ฃผ์†Œ : https://github.com/preOnboarding-Team13/Assignment_2_MAPIA

Neo4j (GraphDB) ๐Ÿ—๏ธ 

์ด๋ฒˆ ๊ณผ์ œ๋ฅผ ํ†ตํ•ด graphDB๋ฅผ ์ฒ˜์Œ ์จ๋ดค๋‹ค. ์ด์ „์— NoSQL์„ ๊ณต๋ถ€ํ–ˆ์„ ๋•Œ, ์ด๋Ÿฐ ์ข…๋ฅ˜๊ฐ€ ์žˆ๋‹ค~ ๋ผ๊ณ ๋งŒ ๋“ค์—ˆ์—ˆ๋Š”๋ฐ ์‹ค์ œ๋กœ ์จ๋ณด๊ฒŒ ๋˜์–ด ๋‘๊ทผ๊ฑฐ๋ ธ๋‹ค.

๊ณผ์ œ ๊ธฐํ•œ๋„ ์งง์€๋ฐ, ์ƒˆ๋กœ ๋ฐฐ์›Œ์„œ ์จ์•ผํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋‹ˆ ๋ถ€๋‹ด๊ฐ์ด ๋“ค๊ธฐ๋„ ํ–ˆ๋‹ค. ๊ทธ๋ž˜์„œ ํŒ€์›๋“ค๊ณผ ํšŒ์˜ ์ „์— ๊ณต์‹๋ฌธ์„œ์™€ ๊ฐ์ข… ๋ธ”๋กœ๊ทธ๋“ค์„ ์—ด์‹ฌํžˆ ์ฐพ์•„๋ดค๋‹ค.

๋‹คํ–‰ํžˆ๋„ ์ปจ์…‰์ด ๊ทธ๋ž˜ํ”„ ์ž๋ฃŒ๊ตฌ์กฐ์™€ ๊ฑฐ์˜ ๊ฐ™์•„์„œ ์ดํ•ดํ•˜๋Š”๋ฐ ํฌ๊ฒŒ ์–ด๋ ต์ง€ ์•Š์•˜๋‹ค.

์ฟผ๋ฆฌ ์—ญ์‹œ ๊นŠ๊ฒŒ ๊ณต๋ถ€ํ•˜์ง€๋Š” ๋ชปํ–ˆ์ง€๋งŒ, ๊ณผ์ œ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š”๋ฐ ํ•„์š”ํ•œ ์ •๋„์˜ ์ฟผ๋ฆฌ๋Š” ์–ด๋ ต์ง€ ์•Š๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

๊ณต๋ถ€ํ•˜๋ฉด์„œ ๊ต‰์žฅํžˆ ์ง๊ด€์ ์ธ DB๋ผ๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค. ์ธ๋ฑ์Šค๋‚˜, ๊ด€๊ณ„ ์„ค์ •์ด๋‚˜, ๋ณต์žกํ•œ ๊ตฌ์กฐ๊ฐ€ ์—†์ด Node์™€ Relationship๋งŒ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ด€๊ณ„๋ฅผ ํ•˜๋‚˜์˜ ๊ฐ์ฒด์ฒ˜๋Ÿผ ๋ณด๋Š” ๊ด€์ ๋„ ์ƒˆ๋กœ์› ๋‹ค.

Neo4j Browser๋ฅผ ํ†ตํ•ด ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•ด๋ณด๊ณ , ์ฟผ๋ฆฌ์˜ ๊ฒฐ๊ณผ๋ฅผ ์‹œ๊ฐ์ ์œผ๋กœ ๋ฐ”๋กœ๋ฐ”๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด์„œ ํŽธ๋ฆฌํ–ˆ๋‹ค.

 

DB Modeling๐ŸŽก 

๊ณต์‹๋ฌธ์„œ์— ๋ชจ๋ธ๋ง ๊ฐ€์ด๋“œ๊ฐ€ ๋ช…ํ™•ํ•˜๊ฒŒ ์ž‘์„ฑ๋˜์–ด ์žˆ์–ด ํฐ ๊ณ ๋ฏผ์—†์ด ๋ชจ๋ธ๋ง์„ ํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

https://neo4j.com/developer/guide-data-modeling/

 

Graph Modeling Guidelines - Developer Guides

This guide is designed to walk you through the graph data modeling lifecycle of Neo4j. You will be introduced to the basic process of designing a graph data model that can answer a wide range of business questions across a variety of domains.

neo4j.com

Node๋ฅผ ๋งŒ๋“ค๊ณ , Node์•ˆ์— ํ•„์š”ํ•œ property๋ฅผ ๋„ฃ๊ณ , Node๋ฅผ ์ ์ ˆํ•œ Relationship์œผ๋กœ ์—ฐ๊ฒฐํ•˜๋ฉด ๋์ด์—ˆ๋‹ค.

ํฅ๋ฏธ๋กœ์šด๊ฑด ์šฐ๋ฆฌ๋Š” ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์—†์—ˆ์ง€๋งŒ  RelationShip์—๋„ property๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ด์—ˆ๋‹ค.

๋ชจ๋ธ๋ง์„ ํ•˜๋ฉด์„œ, RDBMS์—์„œ N:M ๊ด€๊ณ„๋ฅผ ํ•ด์†Œํ–ˆ๋˜ ๊ฒฝํ—˜์ด ๋– ์˜ค๋ฅด๋ฉด์„œ, GraphDB์˜ ์žฅ์ ์„ ํฌ๊ฒŒ ๋Š๋‚„ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

์šฐ๋ฆฌํŒ€์˜ ๋ชจ๋ธ๋ง ๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค!

์œ„์ฒ˜๋Ÿผ ๋‹จ๋ฐฉํ–ฅ์œผ๋กœ ๊ด€๊ณ„๋ฅผ ์„ค์ •ํ–ˆ์„ ๋•Œ, song์—์„œ๋Š” album์ด๋‚˜ musician๊ฐ™์ด ์ž์‹ ์„ ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ๋Š” ๋…ธ๋“œ์— ์ ‘๊ทผ์ด ๋ถˆ๊ฐ€๋Šฅํ•œ ๊ฒƒ์ด ์•„๋‹ˆ๋ƒ๋Š” ๋…ผ์˜๊ฐ€ ์žˆ์—ˆ๋‹ค. ๊ณต์‹๋ฌธ์„œ๋ฅผ ์‚ดํŽด๋ณธ ๊ฒฐ๊ณผ ๋ฐฉํ–ฅ์— ์ƒ๊ด€์—†์ด ์—ฐ๊ฒฐ๋œ ๋…ธ๋“œ์— ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ–ˆ๋‹ค.

 

Query ์ž‘์„ฑ โ›ณ 

์šฐ๋ฆฌํŒ€์€ ์ด๋ฒˆ ๊ณผ์ œ์—์„œ ๋ฌธ์ž์—ด๋กœ ์ฟผ๋ฆฌ๋ฅผ ์งฐ๋‹ค.

๋”ฑํžˆ ๋งˆ๋•…ํ•œ ORM? ODM?์ด ์ƒ๊ฐ๋‚˜์ง€ ์•Š์•˜๊ณ , ์ฒ˜์Œ ์ ‘ํ•˜๋Š” DB์ปจ์…‰์ด๋ฏ€๋กœ ์ง์ ‘ ๋ฌธ์ž์—ด๋กœ ์ฟผ๋ฆฌ๋ฅผ ์งœ๋ณด๋Š” ๊ฒƒ์ด ์˜๋ฏธ ์žˆ์„ ๊ฒƒ ๊ฐ™์•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

TIL์„ ์ž‘์„ฑํ•˜๋ฉด์„œ ์ฐพ์•„๋ณด๋‹ˆ OGM(Object Graph Mapper)๊ฐ€ ์กด์žฌํ–ˆ๋‹ค.

๋‹ค์Œ์— GraphDB๋ฅผ ์“ธ ๋•Œ๋Š” OGM์„ ์ด์šฉํ•˜๋Š” ๊ฒƒ์œผ๋กœ! JS OGM package

๋‚˜์™€ ๋™๊ท ๋‹˜์ด ํ•„์š”ํ•œ ์ฟผ๋ฆฌ๋ฅผ ๋…ธ์…˜์— ํ•˜๋‚˜์”ฉ ์ ์–ด๋‚˜๊ฐ”๋‹ค.

์ ์œผ๋ฉด์„œ ์ด ์ฟผ๋ฆฌ์—์„œ return๊ฐ’์ด ํ•„์š”ํ• ๊นŒ์š”? ๋ณ€์ˆ˜ ์ด๋ฆ„์€ ์–ด๋–ป๊ฒŒ ํ†ต์ผํ• ๊นŒ์š”?๋“ฑ์˜ ๋…ผ์˜๋ฅผ ํ–ˆ๋‹ค.

์ž‘์„ฑํ–ˆ๋˜ ๋ช‡ ๊ฐœ์˜ ์ฟผ๋ฆฌ๋ฅผ ๊ฐ€์ ธ์™€๋ดค๋‹ค.

// MUSICIAN ์ƒ์„ฑ
CREATE(m:MUSICIAN {name: '๋ ˆ๋“œ๋ฒจ๋ฒณ', company: 'JYP'}) return m

// MUSICIAN ์—…๋ฐ์ดํŠธ
MATCH (m:MUSICIAN {name:'๋ ˆ๋“œ๋ฒจ๋ฒณ'}) SET m.company = 'JYP' RETURN m

// MUSICIAN ์‚ญ์ œ
MATCH (m:MUSICIAN {id:'์–ด์ฉŒ๊ตฌ์ €์ฉŒ๊ตฌ'}) DELETE m

// ALBUM๊ณผ ์—ฐ๊ฒฐ๋˜์–ด์žˆ๋Š” MUSICIAN ์ฐพ๊ธฐ 
MATCH (m:MUSICIAN)-[r1:HAVE]->(s:SONG)<-[r2:CONTAIN]-(a:ALBUM)
WHERE a.name = 'Perfect Velvet'
RETURN m

// MUSICIAN, SONG, ALBUM ์—ฐ๊ฒฐ ์—ฌ๋ถ€
MATCH (m:MUSICIAN {name: '๋ ˆ๋“œ๋ฒจ๋ฒณ'}),(s:SONG {name: 'Perfect Velvet'}), (a:ALBUM {name: 'ํ”ผ์นด๋ถ€'}) 
RETURN EXISTS((m)-[:HAVE]-(s)-[:CONTAIN]-(a))

์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ํ…Œ์ŠคํŠธํ•˜๋ฉด์„œ ๋ชจ๋ธ๋ง์„ ์ˆ˜์ •ํ–ˆ๋‹ค.

๊ทธ ์ „์—๋Š” id property๊ฐ€ ์—†์ด name์ด PK๊ฐ™์€ ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์„๊ฑฐ๋ผ๊ณ  ์ƒ๊ฐํ–ˆ๋Š”๋ฐ,

name์œผ๋กœ ํ•˜๋ฉด ํ•ด๋‹น name์„ ๊ฐ€์ง„ ๋ชจ๋“  ๊ฐ์ฒด๊ฐ€ ์˜ํ–ฅ์„ ๋ฐ›๋Š”๋‹ค.

ํ•˜์ง€๋งŒ ์ด๋ฆ„์ด ๊ฐ™์€ ๋ฎค์ง€์…˜, ๋…ธ๋ž˜, ์•จ๋ฒ”์ด ์ถฉ๋ถ„ํžˆ ์กด์žฌํ•  ๊ฒƒ ๊ฐ™์•„ id property๋ฅผ ๊ฐ ๋…ธ๋“œ์— ์ถ”๊ฐ€ํ•˜๊ณ , uuid๋ฅผ ์ƒ์„ฑํ•ด ๋„ฃ์–ด์ฃผ์—ˆ๋‹ค. 

id๊ฐ€ ์ถ”๊ฐ€๋œ ํ›„์˜ ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•œ ์ฟผ๋ฆฌ๋“ค์€ ์—ฌ๊ธฐ์— ์ž˜ ์ž‘์„ฑ๋˜์–ด ์žˆ๋‹ค. 

 

GraphQL ๐Ÿ• 

GraphQL์€ ์ •๋ง ์šฉ์–ด์กฐ์ฐจ๋„ ์ƒ์†Œํ–ˆ๋‹ค. ์ฒ˜์Œ์—๋Š” GraphDB์— ์‚ฌ์šฉํ•˜๋Š” SQL๋ฌธ ๊ฐ™์€๊ฑด๊ฐ€ ์ƒ๊ฐํ–ˆ๋‹ค.

ํ•œ์ฐธ์„ ๊ณ ๋‡Œํ•˜๋‹ค๊ฐ€ ์ด ์˜์ƒ์„ ํ†ตํ•ด ์ดํ•ดํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค. 

https://youtu.be/EkWI6Ru8lFQ

์ปจ์…‰์„ ์ดํ•ดํ•˜๋Š”๋ฐ ์ •๋ง ๋งŽ์€ ๋„์›€์ด ๋˜์—ˆ๋‹ค. ์•ž์œผ๋กœ ๋ˆ„๊ตฐ๊ฐ€ ๋‚˜์—๊ฒŒ GraphQL์ด ๋ญ๋ƒ๊ณ  ๋ฌผ์–ด๋ณด๋ฉด ์ด ์˜์ƒ์„ ๋ณด์—ฌ์ค„ ๊ฒƒ ๊ฐ™๋‹ค.

 

GraphQL์€ Rest API๋ฐ–์— ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๋‚ด ๋จธ๋ฆฟ์†์— ํฐ ์ถฉ๊ฒฉ์„ ์ฃผ์—ˆ๋‹ค. ์•ผ ์ด๊ฒŒ๋˜๋„คใ…‹ใ…‹

Client๊ฐ€ Body์— ๋ญ˜ ๋‹ด์•„๋ณด๋‚ด๋Š๋ƒ์— ๋”ฐ๋ผ Res์— ์กด์žฌํ•˜๋Š” ํ•„๋“œ๊ฐ’๋“ค์ด ๋‹ฌ๋ผ์ง„๋‹ค๋‹ˆ!! ๊ทธ๋ฆฌ๊ณ  ์ด ๊ฒƒ์ด ๋น„๊ต์  ๊ฐ„๋‹จํ•œ ๋กœ์ง์œผ๋กœ ํ•ด๊ฒฐ๋œ๋‹ค๋‹ˆ!! 

 

GraphQL ๊ธฐ๋ณธ์ ์ธ ์„ค์ • ๋ฐ ์ ์šฉ์€ ๋™๊ท ๋‹˜์ด ํ•ด์ฃผ์…จ๊ณ , ๋‚˜๋Š” ํฌ์ง„๋‹˜, ๋‚˜์˜๋‹˜๊ณผ ํ•จ๊ป˜ where์ ˆ์˜ ์กฐ๊ฑด๊ฐ™์€, client๊ฐ€ ํŠน์ • id๋ฅผ ๋„ฃ์–ด๋ณด๋ƒˆ์„ ๋•Œ๋ฅผ ์œ„ํ•œ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค. 

 

Resolver์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•ด์„œ Arg๋กœ id๋ฅผ ๋ฐ›๋„๋ก ํ–ˆ๋Š”๋ฐ, ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜์ง€ ์•Š์•˜๋‹ค. 

// AlbumRead Resolver ์ฝ”๋“œ
...
// ๊ธฐ์กด ์ฝ”๋“œ (๋ชจ๋“  ์•จ๋ฒ”)
@Query(() => [Album])
	async readAllAlbum() {
		return this.readService.readAllAlbum();
}

// ์ถ”๊ฐ€ํ•œ ์ฝ”๋“œ (ํŠน์ • id)
@Query(() => [Album])
	async readAlbum(@Args("id") id: string) {
		return this.readService.readAlbum(id);
}
...

์›์ธ์€ graphqlํŒŒ์ผ์— ์žˆ์—ˆ๋‹ค.

์ด ํŒŒ์ผ์— ์ •์˜๋œ ํ˜•ํƒœ์˜ ์š”์ฒญ๋งŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋”ฐ๋ผ์„œ id๋ฅผ ์ธ์ž๋กœ ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š” Query๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค. 

type Query {
	readAlbum(id: String!): [Album!]! // ์ถ”๊ฐ€!
	readAllAlbum: [Album!]!
}

์ด๋ ‡๊ฒŒ ๋‹จ 2๊ฐ€์ง€๋งŒ ์ถ”๊ฐ€ํ•ด์„œ ํŠน์ • id์— ๋Œ€ํ•œ ๊ฒฐ๊ณผ๋งŒ ๋ณด์—ฌ์ฃผ๋Š” ์ฟผ๋ฆฌ๋ฅผ ์™„์„ฑํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. ๋ฌผ๋ก  ๋™๊ท ๋‹˜์ด GraphQL์„ ์„ค์ •ํ•˜์‹œ๋Š”๋ฐ ๋งŽ์€ ๋…ธ๋ ฅ์ด ๋“ค์–ด๊ฐ”์ง€๋งŒ, API๋ฅผ ์ด๋ ‡๊ฒŒ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์–ด์„œ ์ •๋ง ์‹ ๊ธฐํ–ˆ๋‹ค.

๋‹ค์Œ๋ฒˆ์— GraphQL์„ ์“ฐ๊ฒŒ๋œ๋‹ค๋ฉด, ๋‚ด๊ฐ€ ์„ค์ •์„ ๋งก์•„๋ณด๊ณ  ์‹ถ๋‹ค. 

 

NestJS ๐ŸŽ† 

์ด๋ฒˆ ํ”„๋กœ์ ํŠธ์—์„œ NestJS๋„ ์ฒ˜์Œ ์จ๋ดค๋‹ค. ์ฒซ ๋ฒˆ์งธ ๊ณผ์ œ์—์„œ๋Š” express๋ฅผ ์ด์šฉํ–ˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์ €๋ฒˆ ๊ณผ์ œ์—์„œ NestJS๋ฅผ ์ด์šฉํ•œ ์šฐ๋ฆฌํŒ€ ๊ณผ์ œ ๋ ˆํฌ๋ฅผ ์‚ดํŽด๋ณด๋ฉด์„œ ๊ตฌ์กฐ๋ฅผ ํŒŒ์•…ํ–ˆ๋‹ค. 

์จ๋ณธ์ ์ด ์—†๊ธด ํ–ˆ์ง€๋งŒ, ๋Œ€๊ฐ• ํ›‘์–ด๋ณด๋‹ˆ 'JS์˜ Spring๊ฐ™์€ ์นœ๊ตฌ๊ตฌ๋‚˜'๋ผ๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค.

์ž์œ ๋„๊ฐ€ ๊ต‰์žฅํžˆ ๋†’์•˜๋˜ express์™€ ๋‹ค๋ฅด๊ฒŒ ๋Œ€๋ถ€๋ถ„์ด ์ •ํ˜•ํ™”, ๊ตฌ์กฐํ™” ๋˜์–ด์žˆ์—ˆ๋‹ค. 

์ฒ˜์Œ์—๋Š” ์ด ๋ถ€๋ถ„์ด ์‚ด์ง ๋ถˆํŽธํ•˜๊ธฐ๋„ ํ–ˆ๋Š”๋ฐ, ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋ฉด์„œ ๋ณด๋‹ˆ ์˜คํžˆ๋ ค ํ˜‘์—…ํ•˜๊ธฐ์—๋Š” express๋ณด๋‹ค ํ›จ์”ฌ ํŽธ๋ฆฌํ•˜๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค. 

 

MVCํŒจํ„ด์ด๊ณ , router ๋Œ€์‹ ์— Controller์— ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ url์„ ์„ค์ •ํ•˜๋Š” ๊ฒƒ๋„ ๋‹ฌ๋ž๋‹ค. (Spring์ด๋ž‘ ์ •๋ง ๋น„์Šทํ•˜๋‹ค๊ณ  ๋Š๋‚€ ๋Œ€๋ชฉ์ด์—ˆ๋‹ค.)

* NestJS์—์„œ๋Š” ์–ด๋…ธํ…Œ์ด์…˜์ด์•„๋‹ˆ๋ผ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค. 

 

TS๋„ ์ฒ˜์Œ์จ๋ดค๋Š”๋ฐ, ๋”ฑํžˆ ๋‚ฏ์„ค์ง€ ์•Š์•˜๋‹ค. JS์™€ ๋‹ค๋ฅด๊ฒŒ type์„ ์ •ํ•ด์ค„ ์ˆ˜ ์žˆ๋Š” ์ ์ด ์˜คํžˆ๋ ค ์ข‹์•˜๋‹ค. 

 

Controller, Service, Repository๋ฅผ ๋งŒ๋“ค์–ด์„œ ์‹คํ–‰์„ ์‹œ์ผฐ๋Š”๋ฐ ์—๋Ÿฌ๊ฐ€ ๋‚ฌ๋‹ค. ์˜์กด์„ฑ ์ฃผ์ž…์„ ํ•ด์ฃผ์ง€ ์•Š์•„์„œ์˜€๋‹ค.

๊ธ‰ํ•œ๋Œ€๋กœ ์ €๋ฒˆ๋ ˆํฌ๋ฅผ ๋ณด๊ณ  ๋งŽ์ด ์ฐธ๊ณ ํ–ˆ๋‹ค. ์ด ๋•Œ๋Š” ์˜์กด์„ฑ๋ถ€๋ถ„์€ ์ž˜ ์ดํ•ด๊ฐ€ ๋˜์ง„ ์•Š์•˜์ง€๋งŒ, ํ˜„์žฌ 6๋ฒˆ์งธ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰์ค‘์ธ ์ƒํ™ฉ์—์„œ ์Šค์Šค๋กœ ์˜์กด์„ฑ์ฃผ์ž…์„ ํ•  ์ˆ˜ ์žˆ๋Š” ์ˆ˜์ค€์ด ๋˜์—ˆ๋‹ค. 

 

@Global() ๐ŸŒ 

Neo4jService๋ฅผ ๋งŒ๋“ค์–ด์„œ, ๊ฐ ์—”ํ‹ฐํ‹ฐ(๋…ธ๋“œ)์˜ RepositoryํŒŒ์ผ์—์„œ Neo4jService๋ฅผ importํ•ด์„œ ์‚ฌ์šฉํ–ˆ๋‹ค. 

๊ทธ๋ž˜์„œ ์ผ์ผ์ด ๊ฐ ๋…ธ๋“œ์˜ Module๋งˆ๋‹ค Neo4jModule์„ ์ฃผ์ž…ํ•ด์ฃผ์—ˆ๋Š”๋ฐ, ์ด๊ฒŒ ๋งž๋‚˜ ์‹ถ์—ˆ๋‹ค. 

์—ญ์‹œ๋‚˜, ๋” ํŽธ๋ฆฌํ•œ ๋ฐฉ๋ฒ•์ด ์žˆ์—ˆ๋‹ค. ๋ฐ”๋กœ @Global() ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ!      ๊ณต์‹๋ฌธ์„œ

์ด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์ด์šฉํ•˜๋ฉด Module์„ ์ „์—ญ๋ฒ”์œ„๋กœ ๋งŒ๋“ค์–ด์„œ ํ•„์š”ํ•œ ๊ณณ๋งˆ๋‹ค ์ผ์ผ์ด ๋„ฃ์–ด์ค„ ํ•„์š”๊ฐ€ ์—†์—ˆ๋‹ค.

 

 

๊ณตํ†ต ์‘๋‹ต ํด๋ž˜์Šค ๐Ÿš€ 

์ด์ „์— express๋ฅผ ์ผ์„ ๋•Œ์—๋Š”(์ฒซ ๋ฒˆ์งธ ๊ณผ์ œ), ๊ณตํ†ต Error Handler๋Š” ์ ์šฉํ–ˆ์ง€๋งŒ ์„ฑ๊ณต์‹œ์— res๋ฅผ ๋ณด๋‚ด๋Š” ์ฝ”๋“œ๊ฐ€ ๊ฐ ์ปจํŠธ๋กค๋Ÿฌ๋งˆ๋‹ค ๋”ฐ๋กœ ๋ถ™์–ด์žˆ์—ˆ๋‹ค.

์ด๋ฒˆ ๊ณผ์ œ์—์„œ๋Š” global ํด๋”์— ๊ณตํ†ต ์‘๋‹ต ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด์„œ ์ด์šฉํ–ˆ๋‹ค. github

์ ์šฉํ•˜๊ธฐ ์ด์ „๋ณด๋‹ค ์ฝ”๋“œ๊ฐ€ ๊น”๋”ํ•ด์ง€๊ณ , ๋ชจ๋“ˆํ™”๊ฐ€ ์ž˜ ์ด๋ฃจ์–ด์กŒ๋‹ค๋Š” ๋Š๋‚Œ์ด ๋“ค์—ˆ๋‹ค.

๋ฐ˜์‘ํ˜•