GraphQL๊ณผ Apollo ์—ด ์—ฌ์„ฏ๋ฒˆ์งธ ์ด์•ผ๊ธฐ - Kotlin + Spring Boot์—์„œ GraphQL ์‚ฌ์šฉํ•ด ๋ณด๊ธฐ - ์‹ค์Šต ํ™˜๊ฒฝ ๊ตฌ์„ฑ

2023. 12. 17. 01:08ใ†๊ฐœ๋… ์ •๋ฆฌ ์ž‘์—…์‹ค/Kotlin

728x90
๋ฐ˜์‘ํ˜•

 

 

 

์นด์นด์˜คํŽ˜์ด | ๋งˆ์Œ ๋†“๊ณ  ๊ธˆ์œตํ•˜๋‹ค

์—ฌ๊ธฐ๋ฅผ ๋ˆŒ๋Ÿฌ ๋งํฌ๋ฅผ ํ™•์ธํ•˜์„ธ์š”.

qr.kakaopay.com

 

 

 

 

 

 

์ฝ”ํ‹€๋ฆฐ ์™„๋ฒฝ ๊ฐ€์ด๋“œ

COUPANG

www.coupang.com

"์ด ํฌ์ŠคํŒ…์€ ์ฟ ํŒก ํŒŒํŠธ๋„ˆ์Šค ํ™œ๋™์˜ ์ผํ™˜์œผ๋กœ, ์ด์— ๋”ฐ๋ฅธ ์ผ์ •์•ก์˜ ์ˆ˜์ˆ˜๋ฃŒ๋ฅผ ์ œ๊ณต๋ฐ›์Šต๋‹ˆ๋‹ค."

 




๐Ÿ—‚ ๋ชฉ์ฐจ

โœ… GraphQL๊ณผ Apollo ์ฒซ๋ฒˆ์งธ ์ด์•ผ๊ธฐ - ๊ฐœ๋… ์ตํžˆ๊ธฐ
โœ… GraphQL๊ณผ Apollo ๋‘๋ฒˆ์งธ ์ด์•ผ๊ธฐ - REST API๋ž€?
โœ… GraphQL๊ณผ Apollo ์„ธ๋ฒˆ์งธ ์ด์•ผ๊ธฐ - GraphQL์˜ ์ •๋ณด ์ฃผ๊ณ  ๋ฐ›๋Š” ๋ฐฉ์‹

โœ… GraphQL๊ณผ Apollo ๋„ค๋ฒˆ์งธ ์ด์•ผ๊ธฐ - Apollo๋ž€?
โœ… GraphQL๊ณผ Apollo ๋‹ค์„ฏ๋ฒˆ์งธ ์ด์•ผ๊ธฐ - GraphQL์„ ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ตฌํ˜„ํ•ด ๋ณด์•„์š” ๐Ÿ˜€
โœ… GraphQL๊ณผ Apollo ์—ฌ์„ฏ๋ฒˆ์งธ ์ด์•ผ๊ธฐ - GraphQL Moduleํ™”์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์•„์š” ๐Ÿ˜€
โœ… GraphQL๊ณผ Apollo ์ผ๊ณฑ๋ฒˆ์งธ ์ด์•ผ๊ธฐ - GraphQL Data Type์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์•„์š” ๐Ÿ˜€
โœ… GraphQL๊ณผ Apollo ์—ฌ๋Ÿ๋ฒˆ์งธ ์ด์•ผ๊ธฐ - GraphQL Union๊ณผ Interface ๊ทธ๋ฆฌ๊ณ  ์ธ์ž์™€ ์ธํ’‹ ํƒ€์ž…์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์•„์š” ๐Ÿ˜€
โœ… GraphQL๊ณผ Apollo ์•„ํ™‰๋ฒˆ์งธ ์ด์•ผ๊ธฐ - Java + Spring Boot์—์„œ GraphQL ์‚ฌ์šฉํ•ด ๋ณด๊ธฐ - ์‹ค์Šต ํ™˜๊ฒฝ ๊ตฌ์„ฑ
โœ… GraphQL๊ณผ Apollo ์—ด๋ฒˆ์งธ ์ด์•ผ๊ธฐ - Java + Spring Boot์—์„œ GraphQL ์‚ฌ์šฉํ•ด ๋ณด๊ธฐ - ์‹ค์Šต ํ•ด๋ณด๊ธฐ
โœ… GraphQL๊ณผ Apollo ์—ด ํ•œ๋ฒˆ์งธ ์ด์•ผ๊ธฐ - TypeScript + Nest.js์—์„œ GraphQL ์‚ฌ์šฉํ•ด ๋ณด๊ธฐ - ์‹ค์Šต ํ™˜๊ฒฝ ๊ตฌ์„ฑ
โœ… 
GraphQL๊ณผ Apollo ์—ด ๋‘๋ฒˆ์งธ ์ด์•ผ๊ธฐ - TypeScript + Nest.js์—์„œ GraphQL ์‚ฌ์šฉํ•ด ๋ณด๊ธฐ - ์‹ค์Šต ํ™˜๊ฒฝ ํ…Œ์ŠคํŠธ
โœ… GraphQL๊ณผ Apollo ์—ด ์„ธ๋ฒˆ์งธ ์ด์•ผ๊ธฐ - TypeScript + Nest์—์„œ GraphQL ์‚ฌ์šฉํ•ด ๋ณด๊ธฐ - ์‹ค์Šต ํ•ด๋ณด๊ธฐ
โœ… 
GraphQL๊ณผ Apollo ์—ด ๋„ค๋ฒˆ์งธ ์ด์•ผ๊ธฐ - React์™€ Apollo Client
โœ… GraphQL๊ณผ Apollo ์—ด๋‹ค์„ฏ๋ฒˆ์งธ ์ด์•ผ๊ธฐ - React์™€ Apollo Client - Query์™€ Mutation ์‚ฌ์šฉํ•˜์—ฌ ์›น ํŽ˜์ด์ง€ ๋งŒ๋“ค๊ธฐ
โœ… GraphQL๊ณผ Apollo ์—ด ์—ฌ์„ฏ๋ฒˆ์งธ ์ด์•ผ๊ธฐ - Kotlin + Spring Boot์—์„œ GraphQL ์‚ฌ์šฉํ•ด ๋ณด๊ธฐ - ์‹ค์Šต ํ™˜๊ฒฝ ๊ตฌ์„ฑ
โœ… GraphQL๊ณผ Apollo ์—ด ์ผ๊ณฑ๋ฒˆ์งธ ์ด์•ผ๊ธฐ - Kotlin + Spring Boot์—์„œ GraphQL ์‚ฌ์šฉํ•ด ๋ณด๊ธฐ - ์‹ค์Šต ํ•ด๋ณด๊ธฐ


๐Ÿค” ๋‚ด๊ฐ€ ๋งŒ๋‚œ ๋ฌธ์ œ

โš ๏ธ [Nest.js] TypeORM Table ๊ด€๊ณ„๊ฐ€ ๋งบ์–ด์กŒ์„ ๋•Œ, Seeding (feat. Migration)
โš ๏ธ [Spring Boot 3.0] Could not resolve org.springframework.boot:spring-boot-gradle-plugin
โš ๏ธ [Spring Boot 3] Spring Doc(Swagger) White Label Error


๐Ÿ“‹ ๋ถ€๋ก

๐Ÿ” [Nest.js] ์ดˆ๊ธฐ ํ™˜๊ฒฝ ๊ตฌ์„ฑ (feat. TypeORM, QueryBuilder, GraphQL, Apollo)
๐Ÿ” [SOLID][Nest.js][Java + Spring] Interface๋ฅผ ํ™œ์šฉํ•œ ๊ฒฐํ•ฉ๋„ ๋ถ„๋ฆฌ (Interface๋ฅผ ์ด์šฉํ•œ Dependency Injection - DI)

 

 

 

 

GitHub - junyharang-coding-study/GraphQL-Study: GraphQL์„ ๊ณต๋ถ€ํ•˜๊ณ , ์‹ค์Šตํ•œ ์ฝ”๋“œ์—์š” ๐Ÿ˜€

GraphQL์„ ๊ณต๋ถ€ํ•˜๊ณ , ์‹ค์Šตํ•œ ์ฝ”๋“œ์—์š” ๐Ÿ˜€. Contribute to junyharang-coding-study/GraphQL-Study development by creating an account on GitHub.

github.com

 

 

 

๐Ÿš€ GraphQL๊ณผ Apollo ์—ด ์—ฌ์„ฏ๋ฒˆ์งธ ์ด์•ผ๊ธฐ

    ๐Ÿ”ฝ  Kotlin + Spring Boot ์—์„œ GraphQL ์‚ฌ์šฉํ•ด ๋ณด๊ธฐ - ์‹ค์Šต ํ™˜๊ฒฝ ๊ตฌ์„ฑ

        ๐Ÿ“ฆ ๊ฐœ์š”

์ด๋ฒˆ ๊ธ€์—์„œ๋Š” ์žํ”„๋ง(Java + Spring Boot)์œผ๋กœ ๊ฐœ๋ฐœํ•œ GraphQL ์‹ค์Šต ์ฝ”๋“œ๋ฅผ ์ฝ”ํ”„๋ง(Kotlin + Spring Boot)๋กœ ๋ฐ”๊ฟ”์„œ ์‹ค์Šตํ•˜๋Š” ์‹œ๊ฐ„์„ ๊ฐ€์ ธ๋ณด๋ ค๊ณ  ํ•ด์š”.

 

 

 

 

 

 

    ๐Ÿ”ฝ  ํ™˜๊ฒฝ ๊ตฌ์„ฑ

        ๐Ÿ“ฆ Kotlin + Spring Boot (์žํ”„๋ง)

์ด๋ฒˆ ๊ธ€์„ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ดํ•˜๊ธฐ ์œ„ํ•ด์„  Kotlin(์ฝ”ํ‹€๋ฆฐ) ๋ฌธ๋ฒ•์„ ์–ด๋Š์ •๋„ ์•Œ์•„์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ด์š”.
์ด ๊ณณ์— ํ•ด๋‹น ๋‚ด์šฉ ์ •๋ฆฌ๋ฅผ ํ•ด ๋‘์—ˆ์œผ๋‹ˆ ๋„์›€์ด ๋˜์‹œ๊ธธ ๋ฐ”๋ž„๊ฒŒ์š”.

 

[Kotlin(์ฝ”ํ‹€๋ฆฐ)] ๋ฌธ๋ฒ• ์ด ์ •๋ฆฌ

์ฝ”ํ‹€๋ฆฐ ์™„๋ฒฝ ๊ฐ€์ด๋“œ COUPANG www.coupang.com "์ด ํฌ์ŠคํŒ…์€ ์ฟ ํŒก ํŒŒํŠธ๋„ˆ์Šค ํ™œ๋™์˜ ์ผํ™˜์œผ๋กœ, ์ด์— ๋”ฐ๋ฅธ ์ผ์ •์•ก์˜ ์ˆ˜์ˆ˜๋ฃŒ๋ฅผ ์ œ๊ณต๋ฐ›์Šต๋‹ˆ๋‹ค." ๐Ÿš€ Kotlin ๋ฌธ๋ฒ• ์ด ์ •๋ฆฌ ๐Ÿ”ฝ ๋“ค์–ด๊ฐ€๊ธฐ ๐Ÿ“ฆ ์†Œ๊ฐœ ์•ˆ๋…•ํ•˜์„ธ์š”? Andlo

junyharang.tistory.com

 

์ด๋ฒˆ์—๋„ ์žํ”„๋ง๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ Spring for GrpahQL์„ ์‚ฌ์šฉํ•ด์„œ ์‹ค์Šต ํ•ด ๋ณด๋ ค๊ณ  ํ•ด์š”.


๐Ÿ” graphql-java / graphql-java-spring
๐Ÿ” graphql-java-kickstart / graphql-spring-boot
๐Ÿ” Netflix / dgs-framwork

์Šคํ”„๋ง ์ง„์˜์—์„œ๋Š” ์œ„์™€ ๊ฐ™์ด GraphQL์„ ์ด์šฉํ•˜๊ธฐ ์œ„ํ•œ 3๊ฐ€์ง€ ๋Œ€ํ‘œ์  Library(๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ) / ํ”„๋ ˆ์ž„์›Œํฌ(framwork)๊ฐ€ ์ค€๋น„ ๋˜์–ด ์žˆ๊ณ , ์ด ์ค‘ ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•˜์—ฌ ์Šคํ”„๋ง ์ธก์—์„œ GraphQL์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌ์„ฑํ•œ ๊ฒƒ์œผ๋กœ ๋ณด์—ฌ์š”.

๋ฟŒ๋ฆฌ๊ฐ€ ๋˜๋Š” ํ”„๋กœ์ ํŠธ๋Š” graphql-java / graphql-java-spring ์ด ํ”„๋กœ์ ํŠธ๋กœ ๋ชจ๋“  ํ”„๋กœ์ ํŠธ๊ฐ€ ์ด๊ฑธ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ฐœ๋ฐœ ๋˜์—ˆ๋‹ค๊ณ  ํ•ด์š”. ๋˜ํ•œ, Spring for GraphQL์€ ๊ณต์‹์ ์œผ๋กœ graphql-java์˜ ํ›„์† ํ”„๋กœ์ ํŠธ๋ผ๊ณ  ์†Œ๊ฐœํ•˜๊ณ  ์žˆ์–ด์š”.

์œ„์— ์žˆ๋Š” ํ”„๋กœ์ ํŠธ๋“ค์„ ์ด์šฉํ•˜์—ฌ GraphQL์„ ๊ฐœ๋ฐœํ•˜๋ฉด ์ด ์ „๊นŒ์ง€ ๊ณต๋ถ€ํ–ˆ๋“ฏ์ด Resolver๋ฅผ ๊ฐœ๋ฐœํ•˜๊ณ , ๋ณ„๋„์˜ ์„ค์ • ๋“ฑ์„ ํ•ด์ฃผ์–ด์•ผ ํ–ˆ์ง€๋งŒ, Spring for GraphQL์€ graphql-java์˜ ๋‹จ์ˆœ ํ›„์† ํ”„๋กœ์ ํŠธ ๋ฟ ์•„๋‹ˆ๋ผ, graphql-java ๊ฐœ๋ฐœํŒ€์ด ๊ฐœ๋ฐœ์„ ํ•˜์˜€๊ธฐ ๋•Œ๋ฌธ์— ์Šคํ”„๋ง ์ธก์—์„œ ์ถ”๊ตฌํ•˜๋Š” ๋ฐฉํ–ฅ๋‹ต๊ฒŒ ์ถ”๊ฐ€ ์ฝ”๋“œ ์—†์ด MVC ๊ฐœ๋ฐœํ•˜๋“ฏ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋งŒ๋“ค์–ด ๋‘์—ˆ์–ด์š”.

 

 

 

 

        ๐Ÿ“ฆ ์‹ค์Šต ํ™˜๊ฒฝ

๐Ÿ” JDK 17(Java 17) with Kotlin 1.3.X
๐Ÿ” Spring Boot 3.1.6 (Spring for GraphQL์€ Spring Boot 2.7.0 ์ด์ƒ ์ง€์›)
๐Ÿ” Embedded H2 DBMS(In-Memory)
๐Ÿ” JPA & QueryDsl
๐Ÿ” InteliJ (2023.2.5 Ultimate)



 

        ๐Ÿ“ฆ ์ดˆ๊ธฐ ๊ตฌ์„ฑ


์ตœ์ดˆ ์ธํ…”๋ฆฌ์ œ์ด์—์„œ ์œ„์™€ ๊ฐ™์ด ํ”„๋กœ์ ํŠธ ํƒญ์—์„œ ์ƒˆ ํ”„๋กœ์ ํŠธ๋ฅผ ๋ˆŒ๋Ÿฌ ํ”„๋กœ์ ํŠธ๋ฅผ ๋งŒ๋“ค์–ด ์ค„๊ฒŒ์š”.

 

๊ทธ๋ฆฌ๊ณ  Spring Initializr์—์„œ ์œ„์™€ ๊ฐ™์ด ํ”„๋กœ์ ํŠธ๋ฅผ ๊ตฌ์„ฑํ•ด ์ฃผ์—ˆ์–ด์š”.
์ฐธ๊ณ ๋กœ Comunity ๋ฒ„์ „์„ ์“ฐ์‹œ๋Š” ๋ถ„์€ ์œ„ ๋‚ด์šฉ์ด ์—†์„ ๊ฑฐ์—์š”.

https://start.spring.io/

์œ„ ์‚ฌ์ดํŠธ์—์„œ ํ”„๋กœ์ ํŠธ๋ฅผ ๊ตฌ์„ฑํ•˜๊ณ , ๋‚ด๋ ค ๋ฐ›์œผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์ฐธ๊ณ ๋กœ ์žํ”„๋ง ์‹ค์Šต๋•Œ๋Š” ์Šคํ”„๋ง ๋ฒ„์ „์„ 2.7.X ๋Œ€์—ญ์œผ๋กœ ๋งŒ๋“ค์—ˆ๋Š”๋ฐ,
์ด์ œ Spring ์ง„์˜์—์„œ 2.7 ๋ฒ„์ „์„ ๊ณต์‹์ ์œผ๋กœ EOL ์‹œ์ผฐ๊ธฐ ๋•Œ๋ฌธ์— Spring Initializr์—์„œ ์ƒ์„ฑํ•  ์ˆ˜๊ฐ€ ์—†์–ด์š”.

๊ทธ๋ž˜์„œ 3.1.6 ๋ฒ„์ „์œผ๋กœ ํ”„๋กœ์ ํŠธ ์‹œ์ž‘ํ•ด์š”.



์ดˆ๊ธฐ ์ข…์†์„ฑ์€ ์œ„์˜ ๊ฒƒ๋“ค์„ ์‚ฌ์šฉํ•ด์„œ ์‹ค์Šตํ•ด ๋ณด๋ ค๊ณ  ํ•ด์š”.
์ฐธ๊ณ ๋กœ Lombok์˜ ๊ฒฝ์šฐ Kotlin(์ฝ”ํ‹€๋ฆฐ)์—์„œ๋Š” ํ•„์š” ์—†์–ด์š”.

์ด์ œ ์ƒ์„ฑ์„ ๋ˆŒ๋Ÿฌ ํ”„๋กœ์ ํŠธ๋ฅผ ๋งŒ๋“ค์–ด ์ค„๊ฒŒ์š”.


์œ„์™€ ๊ฐ™์ด ๋งŒ๋“ค์—ˆ์„ ๋•Œ, build.gradle ์ƒ์— ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์–ด์š”.
ํ•ด๋‹น ๋‚ด์šฉ์€ ์ด ๊ณณ์— ์ •๋ฆฌํ•ด ๋‘์—ˆ์–ด์š”.

 

[Spring Boot 3.0] Could not resolve org.springframework.boot:spring-boot-gradle-plugin

์Šคํ”„๋ง ๋ถ€ํŠธ 3 : ์ž๋ฐ” ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ ์ž…๋ฌธ COUPANG www.coupang.com "์ด ํฌ์ŠคํŒ…์€ ์ฟ ํŒก ํŒŒํŠธ๋„ˆ์Šค ํ™œ๋™์˜ ์ผํ™˜์œผ๋กœ, ์ด์— ๋”ฐ๋ฅธ ์ผ์ •์•ก์˜ ์ˆ˜์ˆ˜๋ฃŒ๋ฅผ ์ œ๊ณต๋ฐ›์Šต๋‹ˆ๋‹ค." ๐Ÿ‘ท‍โ™‚๏ธ ์ž‘์—… ์ค‘์ธ ๋‚ด์šฉ Spring Boot(์Šคํ”„๋ง

junyharang.tistory.com

 

build.bradle

๋ฐ˜์‘ํ˜•
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-graphql'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'com.fasterxml.jackson.module:jackson-module-kotlin'
    implementation 'org.jetbrains.kotlin:kotlin-reflect'
    runtimeOnly 'com.h2database:h2'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'org.springframework:spring-webflux'
    testImplementation 'org.springframework.graphql:spring-graphql-test'
}



Spring for GraphQL์€ JPA ํ™˜๊ฒฝ์—์„œ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•ด์ฃผ๊ณ  ์žˆ๋‹ค๊ณ  ํ•ด์š”.
๊ทธ๋ฆฌ๊ณ , WebFlux ํ™˜๊ฒฝ์—์„œ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด์š”.

์ฃผ๋‹ˆ๋Š” Web MVC ๊ธฐ๋ฐ˜์œผ๋กœ ์‹ค์Šตํ•ด ๋ณผ๊ฑฐ์—์š”.

์ตœ์ดˆ ํ”„๋กœ์ ํŠธ Root(์ตœ์ƒ์œ„) Directory(๋””๋ ‰ํ„ฐ๋ฆฌ) ์•ˆ์— ์•„๋ž˜์™€ ๊ฐ™์ด ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด ์ฃผ์–ด์•ผ ํ•ด์š”.

 

 

.graphqlconfig

{
  "name": "Graphql-Example",
  "schemaPath": "src/main/resources/graphql/*.graphqls",
  "extensions": {}
}

 

์œ„์™€ ๊ฐ™์ด GraphQL ์„ค์ • ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด ์ฃผ์—ˆ์–ด์š”.
์ด ํŒŒ์ผ์€ ์ด ์ „์— ๊ณต๋ถ€ํ–ˆ์—ˆ๋˜ GraphQL Schema(์Šคํ‚ค๋งˆ) ๋ฐ ๊ด€๋ จ ์„ค์ • ์ •๋ณด๋ฅผ ์ •์˜ํ•˜๋Š”๋ฐ ์‚ฌ์šฉํ•˜๋Š” ํŒŒ์ผ์ด์—์š”.

์ฆ‰, GraphQL ์Šคํ‚ค๋งˆ์˜ ์œ„์น˜ ๋ฐ ํ”„๋กœ์ ํŠธ์— ๋Œ€ํ•œ ์ถ”๊ฐ€์ ์ธ ์„ค์ •์„ ํ•˜๋Š”๋ฐ ์ด์šฉ๋˜๋Š” ๊ฒƒ์ด์—์š”.

๊ทธ๋Ÿผ ์†์„ฑ๋“ค์„ ์•Œ์•„๋ณผ๊ฒŒ์š”.

โˆ™ name: GraphQL ์„ค์ • ์ด๋ฆ„์œผ๋กœ ์œ„์—์„œ๋Š” "Graphql-Example"๋กœ ์ง€์ •. ์ด๋ฆ„์€ ์ผ๋ฐ˜์ ์œผ๋กœ ํ”„๋กœ์ ํŠธ ๋˜๋Š” Application(์• ํ”Œ๋ฆฌ์ผ€์ด์…˜)์˜ ์ด๋ฆ„๊ณผ ๊ด€๋ จ.

โˆ™ schemaPath: GraphQL ์Šคํ‚ค๋งˆ ํŒŒ์ผ ๊ฒฝ๋กœ ์ง€์ •. ์ด ๊ฒฝ๋กœ๋Š” ํ”„๋กœ์ ํŠธ ์•ˆ์—์„œ GraphQL ์Šคํ‚ค๋งˆ ํŒŒ์ผ ์œ„์น˜ ์ง€์ •.

โˆ™ extensions: ์ถ”๊ฐ€์  ์„ค์ • ์ง€์ •์„ ์œ„ํ•œ ์†์„ฑ์ด๋ฉฐ, ํ•„์š”์— ๋”ฐ๋ผ ์ถ”๊ฐ€์ ์ธ GraphQL ์„ค์ •์„ ํฌํ•จ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Œ.

 

์ด๋ฒˆ์—๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ๊ตฌ์„ฑํ•ด ๋ณผ๊ฑด๋ฐ, ์ฃผ๋‹ˆ๋Š” ์ž„๋ฒ ์ด๋“œ H2 DB์˜ In-Memory Mode๋ฅผ ์‚ฌ์šฉํ•ด๋ณด๋ ค๊ณ  ํ•ด์š”.
์ข…์†์„ฑ์€ ํ”„๋กœ์ ํŠธ ๊ตฌ์„ฑ ์‹œ Spring Initalizr์—์„œ ์ถ”๊ฐ€ํ–ˆ์–ด์š”.

 

application.yml


์œ„์™€ ๊ฐ™์ด application.yml์— ๋“ฑ๋กํ•ด ์ฃผ๋ฉด H2 DB๋ฅผ ๊ตณ์ด ์„ค์น˜ํ•˜์ง€ ์•Š์•„๋„ ํ…Œ์ŠคํŠธ ์šฉ์œผ๋กœ ์•Œ๋งž๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด์š”.

 

spring:
  datasource:
    driver-class-name: org.h2.Driver
    url: jdbc:h2:mem:{DB ์ด๋ฆ„}
    username: sa
    password:


๋งŒ์•ฝ application.yml ์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ์œ„์™€ ๊ฐ™์ด ์ž‘์„ฑํ•ด์ฃผ๋ฉด ๋˜๊ณ ,

spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:{DB ์ด๋ฆ„}
spring.datasource.username=sa
spring.datasource.password=


properties๋Š” ์œ„์™€ ๊ฐ™์ด ์ž‘์„ฑํ•ด ์ฃผ๋ฉด ๋ผ์š”.


์ผ๋‹จ ์—ฌ๊ธฐ๊นŒ์ง€ ์„ค์ •ํ•˜๊ณ , ์„œ๋ฒ„๋ฅผ ๊ธฐ๋™ ์‹œ์ผœ ๋ณด๋ฉด



์œ„์™€ ๊ฐ™์ด ์ •์ƒ์ ์œผ๋กœ ๊ธฐ๋™ ๋˜๋Š” ๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด์š”.

 

http://localhost:8080/h2-console


๊ทธ๋Ÿผ ์œ„์™€ ๊ฐ™์ด H2-console์— ์ ‘๊ทผ ํ•  ์ˆ˜ ์žˆ์–ด์š”.




์œ„์™€ ๊ฐ™์ด ์„ค์ •ํ•˜๊ณ , ์—ฐ๊ฒฐ์„ ํ•˜๋ฉด Embedded H2 DB๋ฅผ In-memory Mode๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด์š”.

 

 

/src/main/resources/init/database


Mock Data(๋ฐ์ดํ„ฐ)๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์œ„์™€ ๊ฐ™์ด Directory(๋””๋ ‰ํ„ฐ๋ฆฌ)๋ฅผ ๋งŒ๋“ค์–ด ์ฃผ์—ˆ์–ด์š”.

/src/main/resources/init/database


๊ทธ๋ฆฌ๊ณ  ์œ„์™€ ๊ฐ™์ด data.sql๊ณผ schema.sql์„ ๋งŒ๋“ค์–ด ์ฃผ์—ˆ์–ด์š”.


schema.sql์€ ๋ง ๊ทธ๋Œ€๋กœ ๋ฏธ๋ฆฌ DB์™€ Table ๊ตฌ์กฐ๋ฅผ ์ •์˜ํ•˜๋Š” ๊ณณ์ด๊ณ ,
data.sql์€ Table์— ๋ฏธ๋ฆฌ ๋„ฃ์–ด๋‘˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ •์˜ํ•˜๋Š” ๊ณณ์ด์—์š”.

์–„์ฝ”๋‹˜์˜ ๊ฐ•์˜์—์„œ ์‚ฌ์šฉ๋œ csv File(ํŒŒ์ผ) ๊ธฐ๋ฐ˜์œผ๋กœ ๊ตฌ์กฐ์™€ ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ์–ด๋‘˜๊ฒŒ์š”.

 

equipments.csv

 

schema.sql

 

data.sql




teams.csv



schema.sql



data.sql








peoples.csv

 

schema.sql

 

data.sql







roles.csv

 

schema.sql

 

data.sql







softwares.csv

 

schema.sql

 

data.sql







supplies.csv

 

schema.sql

 

data.sql

 

์œ„์™€ ๊ฐ™์ด schema.sql๊ณผ data.sql์„ ๋งŒ๋“  ๋’ค ์„œ๋ฒ„๋ฅผ ๊ตฌ๋™ ์‹œํ‚ค๋ฉด

select * from equipment

 

select * from people


์œ„์™€ ๊ฐ™์ด H2 DBMS์— Mock ๋ฐ์ดํ„ฐ๊ฐ€ ์ž˜ ์ž…๋ ฅ๋œ ๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด์š”.

 

 

์ด์ œ ๋‹ค์‹œ GraphQL ์‚ฌ์šฉ์„ ์œ„ํ•œ ์„ค์ •์„ ํ•ด ๋ณผ๊ฒŒ์š”.

application.yml

728x90
  graphql:
    graphiql:
      enabled: true
      printer:
        enable: true


์œ„์™€ ๊ฐ™์ด ๋‚ด์šฉ์„ ์ถ”๊ฐ€ํ•ด ์ฃผ์—ˆ์–ด์š”.

์œ„ ๋‚ด์šฉ์„ ๋ถ„์„ํ•ด ๋ณด๋ฉด graphipql enable์„ ํ—ˆ์šฉํ•˜๋ฉด localhost:8080/h2-console๊ณผ ๊ฐ™์ด localhost:8080/graphiql์„ ํ†ตํ•ด Query Test๊ฐ€ ๊ฐ€๋Šฅํ•œ ์„œ๋น„์Šค๋ฅผ ์ด์šฉํ•  ์ˆ˜ ์žˆ์–ด์š”.

์ด ์ „์— ๊ณต๋ถ€ํ–ˆ๋˜ Apollo์˜ Playground๋ฅผ ์ด์šฉํ•˜๊ธฐ ์œ„ํ•œ ์„ค์ •์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ์ข‹์„ ๊ฑฐ ๊ฐ™์•„์š”.

๋˜ํ•œ, ์ด ๋ฐฉ๋ฒ• ๋ง๊ณ , ์ธํ…”๋ฆฌ์ œ์ด์˜ GraphQL Plugin(ํ”Œ๋Ÿฌ๊ทธ์ธ)์„ ์„ค์น˜ํ•ด์„œ ์ธํ…”๋ฆฌ์ œ์ด์—์„œ๋„ ์ง์ ‘ ํ…Œ์ŠคํŠธ๊ฐ€ ๊ฐ€๋Šฅํ•˜๊ณ , Postman์„ ์ด์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ์–ด์š”.

printer enable์„ ํ—ˆ์šฉํ•ด์ค€ ๊ฒƒ์€ jpa์˜ show-sql์ด ์ถœ๋ ฅ๋  ๋•Œ, GraphQL Query ๋‚ด์šฉ๋„ ์ถœ๋ ฅ๋˜๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•จ์ด์—์š”.

 

 

 

 

๐Ÿš€ ์ฝ”๋“œ ๊ตฌํ˜„

    ๐Ÿ”ฝ People

        ๐Ÿ“ฆ Entity

์‹ค์Šต์„ ์œ„ํ•œ Entity๋ฅผ ๋งŒ๋“ค์–ด ๋ณผ๊ฒŒ์š”.

์–„์ฝ”๋‹˜์˜ ๊ฐ•์˜๋ฅผ ๋“ค์œผ๋ฉด์„œ ๊ณต๋ถ€ํ–ˆ์„ ๋•Œ, Equipment, people, team, supply๋ฅผ ์ฃผ๋กœ ์‚ฌ์šฉํ–ˆ๋Š”๋ฐ,
์ฃผ๋‹ˆ๋„ ์ด๊ฒƒ์— ์ดˆ์ ์„ ๋งž์ถฐ ์‹ค์Šต์„ ํ•ด๋ณด๋ ค ํ•ด์š”.

์ฐธ๊ณ ๋กœ ์žํ”„๋ง ์‹ค์Šต ํŽธ์—์„œ๋Š” Equipment๋ฅผ ํ†ตํ•ด ์ •๋ฆฌ๋ฅผ ํ–ˆ๋Š”๋ฐ, People์ด ์—ฐ๊ด€ ๊ด€๊ณ„๋„ ์žˆ๊ณ , ์ข€ ๋” ๋กœ์ง์ด ๋“ค์–ด๊ฐ€์•ผ ํ•ด์„œ ์ด๋ฒˆ ์ฝ”ํ”„๋ง ํŽธ์—์„œ๋Š” People์„ ๊ฐ€์ง€๊ณ , ์ •๋ฆฌํ•ด ๋ณผ๊ฒŒ์š”.

๊ธ€์—์„œ๋Š” People๋งŒ ์ž‘์„ฑํ•˜๊ณ , ๋‚˜๋จธ์ง€๋Š” Git Hub์—์„œ ์†Œ์Šค์ฝ”๋“œ๋ฅผ ๋ด์ฃผ์‹œ๋ฉด ์ข‹์„ ๊ฑฐ ๊ฐ™์•„์š”.

https://github.com/junyharang-coding-study/GraphQL-Study/tree/master/graphql-test

 

People.java


์ž๋ฐ”์—์„œ ๋งŒ๋“ค์—ˆ๋˜ Entity๋Š” ์œ„์™€ ๊ฐ™์•„์š”.

 

 

People.kt

 

kotlin/com/junyharangstudy/kotlingraphqltest/api/people/model/entity/People.kt


์ฝ”ํ‹€๋ฆฐ์€ ์ž๋ฐ”์™€ ๋‹ค๋ฅด๊ฒŒ ํด๋ž˜์Šค ์ด๋ฆ„ ๋’ค์— () ์•ˆ์— Property(ํ”„๋กœํผํ‹ฐ) ์ฆ‰, ํด๋ž˜์Šค์˜ ์ฃผ์š” ์†์„ฑ์„ ์ •์˜ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์š”์†Œ๋“ค์„ ์ž…๋ ฅํ•ด ์ฃผ์–ด์•ผ ํ•ด์š”. ์ด๋ ‡๊ฒŒ ํ•ด ์ฃผ๋ฉด ์ฃผ ์ƒ์„ฑ์ž์™€ ์š”์†Œ๋ฅผ ๊ฐ™์ด ๋งŒ๋“ค์–ด ์ฃผ๋Š” ํšจ๊ณผ๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด์—์š”.

์ฃผ ์ƒ์„ฑ์ž๋Š” ํด๋ž˜์Šค์˜ ๊ฐ์ฒด ์ƒ์„ฑ ์‹œ ์‚ฌ์šฉ๋˜๋Š” ์ƒ์„ฑ์ž์ด๊ณ , ํด๋ž˜์Šค์˜ ์ฃผ์š” ์†์„ฑ ์ฆ‰, ํ”„๋กœํผํ‹ฐ๋ฅผ ์ •์˜ํ•˜๋Š” ์—ญํ• ์„ ํ•˜๊ณ  ์žˆ์–ด์š”.

์ฝ”ํ‹€๋ฆฐ์˜ ํ”„๋กœํผํ‹ฐ๋Š” ํด๋ž˜์Šค์˜ ํ•„๋“œ ๋˜๋Š” ๋ฉค๋ฒ„ ๋ณ€์ˆ˜๋ฅผ ์˜๋ฏธํ•ด์š”.
์ด๋Š” ํด๋ž˜์Šค ๋‚ด๋ถ€์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๋ณ€์ˆ˜๋กœ ํด๋ž˜์Šค์˜ State(์ƒํƒœ)๋ฅผ ์ €์žฅํ•ด์š”.
์ฃผ ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด ์ •์˜๋œ ํ”„๋กœํผํ‹ฐ๋“ค์€ ํด๋ž˜์Šค์˜ ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋  ๋•Œ, ์ดˆ๊ธฐํ™” ๋˜๊ณ , ์ด๋ฅผ ํ†ตํ•ด ๊ฐ์ฒด๊ฐ€ ์–ด๋–ค ์ƒํƒœ๋ฅผ ๊ฐ–๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ์–ด์š”.

์ฐธ๊ณ ๋กœ ์ž๋ฐ”์™€ ๋‹ค๋ฅด๊ฒŒ ๋ณ€์ˆ˜๋ช… ์•ž์— var๋ผ๋Š” ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™ํ˜”๋Š”๋ฐ, ์ด ๊ฒƒ์€ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ(Mutable) ํ”„๋กœํผํ‹ฐ๋ผ๋Š” ๋œป์ด์—์š”.
val๋กœ ์ •์˜ํ•ด ์ฃผ๋ฉด ์ฝ๊ธฐ ์ „์šฉ(read-only) ํ”„๋กœํผํ‹ฐ๋กœ ๋ณ€๊ฒฝ์ด ๋ถˆ ๊ฐ€๋Šฅํ•œ ์ƒ์ˆ˜ ๋ณ€์ˆ˜๋กœ ์„ ์–ธํ•œ๋‹ค๋Š” ์˜๋ฏธ๊ฐ€ ๋ผ์š”.

Entity ์†์„ฑ๋“ค์„ var๋กœ ํ•œ ์ด์œ ๋Š” RequestDTO ๋‚ด์šฉ์„ ์ถ”ํ›„ toEntity()๋ฅผ ์ด์šฉํ•˜์—ฌ Entity๋กœ ๋ฐ”๊ฟ”์ฃผ์•ผ ํ•˜๋Š” ๋“ฑ ๋ณ€๊ฒฝ์ด
์ผ์–ด๋‚˜์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด์—์š”.

๋˜ ํ•˜๋‚˜ ์ฐธ๊ณ ํ•ด์•ผ ํ•  ๊ฒƒ์€ peopleId ์ž๋ฃŒํ˜• ๋’ค์— ? ํ‘œ๊ฐ€ ๋ถ™์—ˆ๋‹ค๋Š” ์ ์ด์—์š”.
์ด ์˜๋ฏธ๋Š” ํ•ด๋‹น ๋ณ€์ˆ˜์— Null์ด ๋“ค์–ด์˜ฌ ์ˆ˜๋„ ์žˆ๋‹ค๋Š” ์ด์•ผ๊ธฐ์ธ๋ฐ, ์ด๋ ‡๊ฒŒ ํ•ด ์ค€ ์ด์œ ๋Š” ๋ฐ‘์— DTO์—์„œ ๋˜ ์–ธ๊ธ‰ํ•˜๊ฒ ์ง€๋งŒ, PeopleCreateRequestDto ๊ฐ์ฒด์—์„œ toEntity()๋ฅผ ๋งŒ๋“ค์–ด ์š”์ฒญ ๊ฐ์ฒด๋ฅผ Entity๋กœ ๋ณ€ํ™˜ํ•ด์ฃผ๋ ค๊ณ  ํ•  ๋•Œ, peopleId๋Š” Auth Increment๋ฅผ ์ ์šฉํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— Null ๊ฐ’์„ ์ „๋‹ฌํ•ด ์ค˜์•ผ ํ•ด์š”.

๊ทธ๋Ÿฐ๋ฐ, ?๋ฅผ ์ ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด Null์„ ๋„ฃ์–ด์ค„์ˆ˜๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ?๋ฅผ ๋ถ™ํ˜€์ค€๊ฑฐ์—์š”.

๊ทธ๋ฆฌ๊ณ , Sex, BooldType, Role์€ EnumType์œผ๋กœ ์ž๋ฃŒํ˜•์„ ๋งŒ๋“ค์–ด ์ฃผ์—ˆ์–ด์š”.

BloodType.java

 

kotlin/com/junyharangstudy/kotlingraphqltest/api/common/enumtype/BloodType.kt

 

 

kotlin/com/junyharangstudy/kotlingraphqltest/api/people/model/entity/People.kt
kotlin/com/junyharangstudy/kotlingraphqltest/api/people/model/entity/People.kt


์œ„ ๋ถ€๋ถ„์€ ์ถ”ํ›„ Update(์ˆ˜์ •) ๋กœ์ง ๊ตฌํ˜„ ์‹œ ๊ฐ๊ฐ์˜ ํ•„๋“œ์— ๋Œ€ํ•ด ์ˆ˜์ •ํ•  ๋ฉ”์„œ๋“œ๋ฅผ ๋งŒ๋“ค์–ด ์ตœ๋Œ€ํ•œ Entity์˜ Immutability
(๋ถˆ๋ณ€์„ฑ)์„ ํ™•๋ณดํ•˜๋ ค๊ณ  ๋งŒ๋“  ๋ฉ”์„œ๋“œ์—์š”.

 

 

 

 

 

 

        ๐Ÿ“ฆ Resolver

์ด๋ฒˆ์—๋Š” Resolver(๋ฆฌ์กธ๋ฒ„) Code๋ฅผ ๋งŒ๋“ค์–ด ๋ณผ๊ฒŒ์š”.
Resolver(๋ฆฌ์กธ๋ฒ„)๋Š” REST API๋กœ ๊ตฌํ˜„ํ–ˆ๋‹ค๋ฉด Controller๋ผ๊ณ  ๋ช…๋ช…ํ–ˆ์„๊ฑฐ์—์š”.



PeopleResolver.java


๋จผ์ € ์œ„ ์ž๋ฐ” ์ฝ”๋“œ์™€ ๊ฐ™์ด ์ €์žฅ Handle(ํ•ธ๋“ค) ๋ฉ”์„œ๋“œ๋ฅผ ๋งŒ๋“ค์–ด ๋ณผ๊ฒŒ์š”.

kotlin/com/junyharangstudy/kotlingraphqltest/api/people/resolver/PeopleResolver.kt


ํ˜„์žฌ DTO์™€ Service ์ž๋ฃŒํ˜•์ด ๋นจ๊ฐ„ ์ด์œ ๋Š” ์•„์ง ๋งŒ๋“ค์–ด ์ฃผ์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์ด์—์š”.

@MutaionMapping์— ๋…ธ๋ž€ ์ค„์ด ๊ฐ€ ์žˆ๋Š” ๊ฒƒ์€ ํ•ด๋‹น ํ•ธ๋“ค ๋ฉ”์„œ๋“œ์™€ Mapping(๋งคํ•‘) ๋˜๋Š” GraphQL Schma(์Šคํ‚ค๋งˆ)๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์ด์—์š”.

 

PeopleResolver.java


์ด๋ฒˆ์—๋Š” ๋ชฉ๋ก ์กฐํšŒ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋Š” ๋กœ์ง์„ ๋งŒ๋“ค์–ด ๋ณผ๊ฒŒ์š”.
์ฐธ๊ณ ๋กœ ์ž๋ฐ” ์ฝ”๋“œ์—์„œ๋Š” RequestDTO๋กœ ๋ฐ›์ง€ ์•Š๊ณ , ์š”์†Œ๋“ค์„ ๊ฐ๊ฐ ๋ฐ›์•„ ๋ณด์•˜๋Š”๋ฐ,
์ฝ”ํ‹€๋ฆฐ์—์„œ๋Š” RequestDTO๋กœ ๋ชจ๋‘ ๋ชจ์•„ ๋ฐ›์•„๋ณด๋ ค๊ณ  ํ•ด์š”.

kotlin/com/junyharangstudy/kotlingraphqltest/api/people/resolver/PeopleResolver.kt


์œ„์™€ ๊ฐ™์ด ๋งค๊ฐœ ๋ณ€์ˆ˜๋กœ ๋‘ ๊ฐ์ฒด๋ฅผ ๋ฐ›๋Š”๋ฐ, ํ•˜๋‚˜๋Š” ํŒ€์› ์ •๋ณด๋ฅผ ์ž…๋ ฅ ๋ฐ›์•„ ๊ฒ€์ƒ‰ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉ๋  DTO ๊ฐ์ฒด์ด๊ณ ,
ํ•˜๋‚˜๋Š” Paging ์š”์ฒญ์„ ๋ฐ›์„ DTO ๊ฐ์ฒด๋ฅผ ๋ฐ›์œผ๋ ค๊ณ  ํ•ด์š”. ์ž๋ฃŒํ˜• ๋’ค์— ?๋Š” Null์ด ๋“ค์–ด์˜ฌ ์ˆ˜๋„ ์žˆ๋‹ค๋Š” ์˜๋ฏธ์—์š”.



PeopleResolver.java

 

kotlin/com/junyharangstudy/kotlingraphqltest/api/people/resolver/PeopleResolver.kt


์ƒ์„ธ ์กฐํšŒ๋Š” ํ•ด๋‹น ์ธ์›์˜ ID๋ฅผ ๋ฐ›์•„ ํ•˜๋‚˜์˜ ์ •๋ณด๋ฅผ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“ค๊ฑฐ์—์š”.

 

 

PeopleResolver.java

 

kotlin/com/junyharangstudy/kotlingraphqltest/api/people/resolver/PeopleResolver.kt


ํ•œ ํŒ€์—๋Š” ์—ฌ๋Ÿฌ Member(๋ฉค๋ฒ„)๊ฐ€ ์†ํ•ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— team ID๋ฅผ ํ†ตํ•ด ์†Œ์† ํŒ€์› ์กฐํšŒ๋ฅผ ์œ„ํ•œ ๋กœ์ง๋„ ๋งŒ๋“ค์–ด ๋ณด๋ ค๊ณ  ํ•ด์š”.
์—ฌ๊ธฐ์„œ๋„ ์žํ”„๋ง๊ณผ ๋‹ค๋ฅธ ๊ฒƒ์€ Paging ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ์š”์ฒญ์„ ์ฝ”ํ”„๋ง์—์„œ๋Š” DTO๋กœ ๋ฌถ์–ด์„œ ๋ฐ›๋Š”๋‹ค๋Š” ๊ฒƒ์ด๊ณ ,
Client(ํด๋ผ์ด์–ธํŠธ)์—์„œ ํ•ด๋‹น ๋‚ด์šฉ์€ ์กฐํšŒ๋ฅผ ์•ˆํ•ด๋„ ๋  ์ˆ˜ ์žˆ๊ฒŒ ?๋กœ Null์ด ๋“ค์–ด์˜ฌ ์ˆ˜ ์žˆ์Œ์„ ์ •์˜ํ•ด ์ฃผ์—ˆ์–ด์š”.




PeopleResolver.java

 

kotlin/com/junyharangstudy/kotlingraphqltest/api/people/resolver/PeopleResolver.kt


์žํ”„๋ง์—์„œ๋Š” RequestDTO์— peopleId๋ฅผ ํ•จ๊ป˜ ๋‹ด์•„ ์ „๋‹ฌํ•˜๊ฒŒ ํ•ด ์ฃผ์—ˆ๋Š”๋ฐ,
์ฝ”ํ”„๋ง์—์„œ๋Š” ๋‘˜์ด ๋ถ„๋ฆฌ ์‹œ์ผœ ์ „๋‹ฌํ•˜๋„๋ก ํ•ด ์ฃผ์—ˆ์–ด์š”.

 

 

 

PeopleResolver.java

 

kotlin/com/junyharangstudy/kotlingraphqltest/api/people/resolver/PeopleResolver.kt


์‚ญ์ œ ๋กœ์ง์€ ์œ„์™€ ๊ฐ™์ด ๋งŒ๋“ค์–ด ์ฃผ์—ˆ์–ด์š”.
ํŒ€์›์˜ Id๋ฅผ ๋ฐ›์•„ Database(๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค)์— ํ•ด๋‹น ์ธ์›์ด ์กด์žฌํ•˜๋Š”์ง€ ์ฐพ๊ณ , ์žˆ์œผ๋ฉด ์‚ญ์ œํ•˜๊ณ , ์—†์œผ๋ฉด Error๋ฅผ ๋‚ด๋ณด๋‚ด ์ค„๊ฑฐ์—์š”.

์ด์ œ ๋ฆฌ์กธ๋ฒ„๋ฅผ ๋‹ค ๋งŒ๋“ค์—ˆ์œผ๋‹ˆ ๋นจ๊ฐ„ ์ƒ‰์œผ๋กœ Error๊ฐ€ ๋‚˜๋Š” ๋ถ€๋ถ„๋“ค์„ ํ•ด๊ฒฐํ•ด ๋ณผ๊ฒŒ์š”.

 

 

 

 

 

 

 

        ๐Ÿ“ฆ DTO

 

 

PeopleRequestDto.java
kotlin/com/junyharangstudy/kotlingraphqltest/api/people/model/dto/request/PeopleCreateRequestDto.kt


์žํ”„๋ง๊ณผ ๋‹ค๋ฅด๊ฒŒ ์ฝ”ํ”„๋ง์—์„œ๋Š” ์œ„์™€ ๊ฐ™์ด toEntity()๋ฅผ CreateRequestDto์— ๋งŒ๋“ค์–ด ์ฃผ์—ˆ์–ด์š”.
์œ„ Entity๋ฅผ ๋งŒ๋“ค ๋•Œ ์–ธ๊ธ‰ํ–ˆ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ toEntity()๋Š” DTO๋ฅผ Entity๋กœ ๋ณ€ํ™˜ํ•ด์ฃผ๋Š” ๋ฉ”์„œ๋“œ๋กœ ์œ„์™€ ๊ฐ™์ด People ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด ๋งŒ๋“ค ๋•Œ, peopleId๋ฅผ ๋ฌด์กฐ๊ฑด ์ „๋‹ฌํ•ด ์ฃผ์–ด์•ผ ํ•˜๋Š”๋ฐ, Auth Increment๋ฅผ ์ ์šฉํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— Null์„ ์ „๋‹ฌํ•ด ์ค€ ๊ฒƒ์ด์—์š”. ๊ทผ๋ฐ Entity ํ”„๋กœํผํ‹ฐ์— ?๊ฐ€ ์•ˆ ๋ถ™์–ด ์žˆ์Œ Null์„ ๋„ฃ์–ด์ค„ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์œ„์™€ ๊ฐ™์ด ํ•œ ๊ฒƒ์ด์—์š”.

๊ทธ๋ฆฌ๊ณ , RequestDto๋Š” var ๋Œ€์‹  val์„ ์ž…๋ ฅํ•˜์—ฌ ์ˆ˜์ •์„ ๋ถˆ๊ฐ€ํ•˜๊ฒŒ ๋งŒ๋“ค์—ˆ๋Š”๋ฐ, ํด๋ผ์ด์–ธํŠธ์—์„œ ์š”์ฒญ์ด ์˜ฌ ๋•Œ, ๋”ฑ ํ•œ๋ฒˆ ๊ฐ’์ด ์ž…๋ ฅ๋˜๊ณ , ์ด Dto ๋‚ด์— ์–ด๋–ค ๊ฒƒ๋“ค๋„ ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜์–ด์•ผ ํ•  ์ด์œ ๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์ด์—์š”.

 

 

PeopleSearchRequestDto.java

 

kotlin/com/junyharangstudy/kotlingraphqltest/api/people/model/dto/request/PeopleSearchRequestDto.kt


๊ฒ€์ƒ‰์„ ์œ„ํ•œ Dto๋Š” ์œ„์™€ ๊ฐ™์ด ๊ฒ€์ƒ‰์ด ๊ฐ€๋Šฅํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ ์–ธํ•ด ์ฃผ์—ˆ์–ด์š”.
์žํ”„๋ง์—์„œ๋Š” ๋ฉค๋ฒ„ Id์™€ ํŒ€ Id๋„ ๋ฐ›์•˜์—ˆ๋Š”๋ฐ, ๋ฆฌ์กธ๋ฒ„์—์„œ ํŒ€ ์กฐํšŒ๋Š” ๋”ฐ๋กœ ๋บ๊ณ , ๋ฉค๋ฒ„ Id๋Š” ์ƒ์„ธ ์กฐํšŒ๋ฅผ ํ†ตํ•ด ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์œ„์™€ ๊ฐ™์ด ํ•˜๊ธฐ๋กœ ํ•˜์˜€์–ด์š”.

๊ทธ๋ฆฌ๊ณ  ๋ชจ๋‘ ? ํ‘œ๊ฐ€ ๋ถ™์–ด ์žˆ๋Š”๊ฑธ ๋ณผ ์ˆ˜ ์žˆ์–ด์š”.
๊ฒ€์ƒ‰์„ ์œ„ํ•ด ๋ชจ๋“  ๊ฐ’์„ ๋‹ค ์ž…๋ ฅํ•  ํ•„์š”๊ฐ€ ์—†๊ณ , ์–ด๋–ค ๊ฑธ ๊ฒ€์ƒ‰ํ• ์ง€ ์•Œ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์ด์—์š”.

 

kotlin/com/junyharangstudy/kotlingraphqltest/api/common/constant/PageRequestDto.kt


์œ„ DTO๋Š” ํด๋ผ์ด์–ธํŠธ๊ฐ€ ํŽ˜์ด์ง• ์ฒ˜๋ฆฌ๋ฅผ ์›ํ•  ๋•Œ, ๋ณด๋‚ผ DTO ๊ฐ์ฒด์—์š”.

ํ”„๋กœํผํ‹ฐ๋ฅผ ๋จผ์ € ๋ณด๋ฉด currentPage๋Š” ํ˜„์žฌ ํŽ˜์ด์ง€๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ์ •์ˆ˜ ๊ฐ’ ๋˜๋Š” Null์„ ๋ฐ›์„ ๋ณ€์ˆ˜์—์š”.
perPagesize๋Š” ํŽ˜์ด์ง€ ๋‹น ์š”์†Œ์˜ ๊ฐœ์ˆ˜๋ฅผ ๋‚˜ํƒœ๋Š” ์ •์ˆ˜ ๊ฐ’ ๋˜๋Š” Null์„ ๋‹ด์„ ๋ณ€์ˆ˜์—์š”.
odrderBy๋Š” ID๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋‚ด๋ฆผ ์ฐจ์ˆœํ•  ๊ฒƒ์ธ์ง€์— ๋Œ€ํ•œ ์—ฌ๋ถ€๋ฅผ ๋‹ด์„ ๋ณ€์ˆ˜์ธ๋ฐ, ture๊ฐ€ ๋‹ด๊ธฐ๋ฉด ๋‚ด๋ฆผ ์ฐจ์ˆœ์œผ๋กœ ์ •๋ ฌํ•˜๊ณ , False๋‚˜, Null์ด ๋‹ด๊ธฐ๋ฉด ์ •๋ ฌ ํ•˜์ง€ ์•Š์•„์š”.

8 ~ 14๋ฒˆ์งธ ์ค„ getOffset()์€ ํ˜„์žฌ ํŽ˜์ด์ง€์™€ ํŽ˜์ด์ง€๋‹น ํ•ญ๋ชฉ ์ˆ˜๋ฅผ ์ด์šฉํ•˜์—ฌ ํŽ˜์ด์ง€์˜ ์‹œ์ž‘ ์œ„์น˜(offset)์„ ๊ณ„์‚ฐํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์„œ๋“œ์—์š”.
๋งŒ์•ฝ currentPage ๋˜๋Š” perPageSize๊ฐ€ Null์ด๋ฉด 0์„ ๋ฐ˜ํ™˜ํ•ด์š”. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ํ˜„์žฌ ํŽ˜์ด์ง€ ์œ„์น˜ ๊ฐ’์— 1์„ ๋นผ๊ณ , ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ํ•œ ํŽ˜์ด์ง€ ๋‹น ์ถœ๋ ฅํ•  ์š”์†Œ ๊ฐœ์ˆ˜์™€ ๊ณฑํ•œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•ด์š”.

์ด๋ ‡๊ฒŒ ํ•˜๋Š” ์ด์œ ๋Š” ํŽ˜์ด์ง• ์ฒ˜๋ฆฌ์—์„œ ํ˜„์žฌ ํŽ˜์ด์ง€์˜ ์‹œ์ž‘ ์œ„์น˜๋ฅผ ๊ณ„์‚ฐํ•˜๊ธฐ ์œ„ํ•œ ์—ฐ์‚ฐ์ธ๋ฐ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ํŽ˜์ด์ง• Query์—์„œ ํŠน์ • ํŽ˜์ด์ง€์˜ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•œ ๊ณ„์‚ฐ๋ฒ•์ด์—์š”.


ํŽ˜์ด์ง• ์ฒ˜๋ฆฌ์—์„œ ๊ฐ ํŽ˜์ด์ง€๋Š” ์ผ์ •ํ•œ ๊ฐœ์ˆ˜์˜ ํ•ญ๋ชฉ์„ ํฌํ•จํ•˜๊ณ  ์žˆ์–ด์š”.
ํ˜„์žฌ ํŽ˜์ด์ง€์˜ ์‹œ์ž‘ ์œ„์น˜๋Š” (ํ˜„์žฌ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ - 1) * ํŽ˜์ด์ง€๋‹น ํ•ญ๋ชฉ ์ˆ˜๋กœ ๊ณ„์‚ฐ ๋ผ์š”. ์ด ๊ณ„์‚ฐ์„ ํ†ตํ•ด ํ•ด๋‹น ํŽ˜์ด์ง€์˜ ์ฒซ ๋ฒˆ์งธ ํ•ญ๋ชฉ์˜ ์œ„์น˜๋ฅผ ์•Œ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด์—์š”.

์˜ˆ๋ฅผ ๋“ค์–ด ํŽ˜์ด์ง€๋‹น 10๊ฐœ์˜ ํ•ญ๋ชฉ์ด ์žˆ๋‹ค๊ณ  ํ–ˆ์„ ๋•Œ,

1ํŽ˜์ด์ง€์˜ ์‹œ์ž‘ ์œ„์น˜๋Š” (1 - 1) * 10 = 0 ์ด์—์š”.
2ํŽ˜์ด์ง€์˜ ์‹œ์ž‘ ์œ„์น˜๋Š” (2 - 1) * 10 = 10 ์ด์—์š”.
3ํŽ˜์ด์ง€์˜ ์‹œ์ž‘ ์œ„์น˜๋Š” (3 - 1) * 10 = 20 ์ด์—์š”.

์ด๋Ÿฐ ์‹์œผ๋กœ ๊ฐ ํŽ˜์ด์ง€์˜ ์‹œ์ž‘ ์œ„์น˜๋ฅผ ๊ณ„์‹ผํ•˜์—ฌ ํŠน์ • ํŽ˜์ด์ง€์˜ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•œ ๊ณต์‹์ด์—์š”.
ํŽ˜์ด์ง€ ๋‹น ํ•ญ๋ชฉ ์ˆ˜์™€ ํ˜„์žฌ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ๊ฐ€ ์ฃผ์–ด์กŒ์„ ๋•Œ, ์‹œ์ž‘ ์œ„์น˜๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” ์—ฐ์‚ฐ์€ ํŽ˜์ด์ง• ์ฒ˜๋ฆฌ์—์„œ ์ผ๋ฐ˜์ ์œผ๋กœ ๋งŽ์ด ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์–ด์š”.

16 ~ 22๋ฒˆ์งธ ์ค„ getLimist()์€ ํŽ˜์ด์ง€ ๋‹น ํ‘œ์‹œํ•  ์š”์†Œ์˜ ๊ฐœ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์„œ๋“œ์—์š”.
perPageSize๊ฐ€ Null์ด๋ฉด 0์„ ๋ฐ˜ํ™˜ํ•ด์š”. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด PerPageSize ๊ฐ’์„ ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜ํ•ด์š”.

24 ~ 35๋ฒˆ์งธ ์ค„ getOrderBy()๋Š” ์ •๋ ฌ ๋ฐฉ์‹์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋กœ Null์ด๊ฑฐ๋‚˜, False์ด๋ฉด False๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ , true์ผ ๋•Œ๋งŒ true๋ฅผ ๋ฐ˜ํ™˜ํ•ด์š”.


 

 

PeopleUpdateRequestDto.java

 

kotlin/com/junyharangstudy/kotlingraphqltest/api/people/model/dto/request/PeopleUpdateRequestDto.kt


UpdateRequestDto๋„ ์žํ”„๋ง๊ณผ ๋‹ค๋ฅด๊ฒŒ peopleId๋ฅผ ๋ฐ›์ง€ ์•Š๋Š”๊ฑธ๋กœ ์ˆ˜์ •ํ–ˆ๋Š”๋ฐ, ๊ทธ ์ด์œ ๋Š” ID ๊ฐ’์€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š” ๋กœ์ง์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‹ถ์—ˆ๊ธฐ ๋•Œ๋ฌธ์ด์—์š”.

๋ฌผ๋ก  ์„ฑ, ์ด๋ฆ„, ์„ฑ๋ณ„, ํ˜ˆ์•กํ˜•, ์ถœ์‹ ์ง€๋Š” ๋ณ€ํ•˜์ง€ ์•Š๋Š” ๋ถˆ๋ณ€ ์ •๋ณด๊ฒ ์ง€๋งŒ, ์—ฐ์Šต์„ ์œ„ํ•ด ์ˆ˜์ •์ด ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋กœ์ง์„ ์งœ๋ ค๊ณ  ํ•ด์š”.

์ˆ˜์ • ์—ญ์‹œ ์–ด๋–ค ๊ฐ’์„ ์ˆ˜์ •ํ•˜๊ณ ์ž ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๊ฐ’์„ ๋ณด๋‚ผ์ง€ ๋ชจ๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ๋ชจ๋“  ํ”„๋กœํผํ‹ฐ์— ?๋ฅผ ๋ถ™ํ˜€์ฃผ์—ˆ์–ด์š”.

 

PeopleResponseDto.java

 

kotlin/com/junyharangstudy/kotlingraphqltest/api/people/model/dto/response/PeopleResponseDto.kt


์žํ”„๋ง์—์„œ Entity๋ฅผ ResponseDTO๋ฅผ ๋ฐ”๊ฟ€ ๋•Œ, Builder Pattern์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ”๊พธ๊ธฐ ์œ„ํ•ด @Builder๋ฅผ ์‚ฌ์šฉํ–ˆ์ง€๋งŒ,
์ฝ”ํ‹€๋ฆฐ์—์„œ๋Š” Lombok์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— peopleToDto()๋ฅผ ๋งŒ๋“ค์–ด์„œ ์ฒ˜๋ฆฌํ•ด ์ฃผ๋ ค๊ณ  ํ•ด์š”.

ResponseDTO์—์„œ๋Š” ํ”„๋กœํผํ‹ฐ์— private์„ ๋ถ™ํ˜€๋†จ๋Š”๋ฐ, ์ด๋Š” ์™ธ๋ถ€์—์„œ ์ฝ์„ ์ˆ˜๋Š” ์žˆ์œผ๋‚˜, ์ˆ˜์ •ํ•  ์ˆ˜ ์—†๊ฒŒ ๋งŒ๋“ค๊ธฐ ์œ„ํ•จ์ด์—์š”.

ResponseDTO๋Š” Entity๋ฅผ ResponseDTO๋กœ ๊ฐ’์„ ๋„ฃ๋Š” ํ–‰์œ„ ์™ธ์—๋Š” ๋ณ€๊ฒฝ๋˜๋Š” ์ผ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์ด๊ณ , ๋‚ด๋ถ€ ๋ฉ”์„œ๋“œ peopleToDto๋ฅผ ํ†ตํ•ด์„œ๋Š” ๋ณ€๊ฒฝ์ด ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋งŒ๋“ค์–ด ์ค€ ๊ฒƒ์ด์—์š”.

๊ทธ๋ฆฌ๊ณ , companion object๋ผ๋Š” ํ‚ค์›Œ๋“œ๊ฐ€ ์žˆ๊ณ , ์ด ๋ถ€๋ถ„์— peopleToDto()๊ฐ€ ๋ฌถ์—ฌ ์žˆ๋Š” ๊ฑธ ๋ณผ ์ˆ˜ ์žˆ์–ด์š”.
companion object{}๋Š” ์ฝ”ํ‹€๋ฆฐ์—์„œ ํด๋ž˜์Šค ๋‚ด๋ถ€์— ์„ ์–ธ๋˜์–ด ํด๋ž˜์Šค์™€ ์—ฐ๊ฒฐ๋œ Static(์ •์ ) ๋ฉค๋ฒ„๋ฅผ ๋‚˜ํƒ€๋‚ด๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•ด์š”.
๋”ฐ๋ผ์„œ ์ด ๊ฐ์ฒด์— ์†ํ•œ ๋ฉค๋ฒ„๋Š” ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค ์—†์ด๋„ ํ˜ธ์ถœํ•˜๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ ๊ฒƒ์ด๊ณ , ์ž๋ฐ”๋กœ ์น˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ๋งŒ๋“ ๊ฑฐ์—์š”.

public static PeopleResponseDto peopleToDto(People people) {}


๊ทธ๋ฆฌ๊ณ  peopleToDto() ์•ˆ์— ํ”„๋กœํผํ‹ฐ ์ค‘ !!๊ฐ€ ๋ถ™์€ ํ”„๋กœํผํ‹ฐ๊ฐ€ ์žˆ๋Š” ๊ฑธ ์•Œ ์ˆ˜ ์žˆ์–ด์š”.
์ด๋Š” nullable Type์˜ ๋ณ€์ˆ˜๋ฅผ non-nullable๋กœ ๊ฐ•์ œ Casting(์บ์ŠคํŒ…)ํ•˜๋Š” ์—ฐ์‚ฐ์ž์—์š”.
์ด ์—ฐ์‚ฐ์ž๋Š” ๋ณ€์ˆ˜๊ฐ€ Null์ด ์•„๋‹˜์„ ๊ฐœ๋ฐœ์ž๊ฐ€ ํ™•์‹ ํ•  ๋•Œ๋งŒ ์‚ฌ์šฉํ•ด์•ผ ํ•ด์š”. ๋งŒ์•ฝ peopleId, teamId๊ฐ€ Null์ด ๋  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋‹ค๋ฉด ์•ˆ์ „ํ•œ Null Check๋‚˜, ๊ธฐํƒ€ ๋ฐฉ๋ฒ•์„ ๊ณ ๋ คํ•ด์•ผ ํ•ด์š”.

kotlin/com/junyharangstudy/kotlingraphqltest/api/people/model/entity/People.kt

 

kotlin/com/junyharangstudy/kotlingraphqltest/api/team/model/entity/Team.kt


Entity์˜ ๋‘ ํ”„๋กœํผํ‹ฐ๋Š” ?๊ฐ€ ๋ถ™์–ด์žˆ๋Š” ๊ฑธ ์•Œ ์ˆ˜ ์žˆ์–ด์š”.
์ด์œ ๋Š” Entity ๋ถ€๋ถ„์—์„œ ์ด์•ผ๊ธฐ ํ•œ ๊ฒƒ๊ณผ ๋™์ผํ•œ ์ด์œ ์—์š”.

์ด๋ ‡๊ฒŒ ๋‘ ํ”„๋กœํผํ‹ฐ์— ?๊ฐ€ ๋ถ™์–ด์žˆ๊ธฐ ๋•Œ๋ฌธ์— DTO์—์„œ ๊ทธ๋ƒฅ ์„ ์–ธํ•  ์ˆ˜๋Š” ์—†์–ด์š”.
๊ทธ๋Ÿฐ๋ฐ ResponseDTO๋Š” Service Layer์—์„œ ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค์—์„œ ๊ฐ’์„ ์ฐพ์€ ๋’ค Null Check๋ฅผ ํ•˜๊ณ , ์ •์ƒ์ด๋ฉด ๊ฐ’์„ ๋„ฃ์–ด ๋ฐ˜ํ™˜ํ•˜๋Š” ๋‹จ๊ณ„๋ฅผ ๊ฑฐ์น˜๊ธฐ ๋•Œ๋ฌธ์— Null์ด ์•„๋‹˜์„ ๊ฐœ๋ฐœ์ž์ธ ์ฃผ๋‹ˆ๋Š” ํ™•์‹ ํ•  ์ˆ˜ ์žˆ์–ด์š”.

๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ์œ„์™€ ๊ฐ™์ด !!๋ฅผ ๋ถ™ํ˜€์ค€ ๊ฒƒ์ด์—์š”.

์œ„ ResponseDTO๋Š” Entity ํŠน์ • ํ•„๋“œ๋“ค์„ ์„ ํƒ์ ์œผ๋กœ ๋…ธ์ถœํ•˜๊ณ , companion object์˜ Factory Method๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Entity๋ฅผ Dto๋กœ ๋ฐ”๊พธ๋Š” ์—ญํ•  ๋“ฑ์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•œ ํด๋ž˜์Šค์—์š”.

 

 

 

 

 

        ๐Ÿ“ฆ Repository (JPA)

PeopleRepository.java

 

kotlin/com/junyharangstudy/kotlingraphqltest/api/people/repository/PeopleRepository.kt


JPA Repository๋Š” ์œ„์™€ ๊ฐ™์ด ๋งŒ๋“ค์–ด ์ฃผ์—ˆ์–ด์š”.

 

 

 

 

 

        ๐Ÿ“ฆ Repository (QueryDSL)

kotlin/com/junyharangstudy/kotlingraphqltest/api/people/repository/PeopleQueryDslRepository.kt

 

 

PeopleQueryDslRepository.java


์žํ”„๋ง์—์„œ๋Š” ์œ„์™€ ๊ฐ™์ด ๊ฒ€์ƒ‰๊ณผ ํŽ˜์ด์ง• ์ฒ˜๋ฆฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋Š” Dynamic Query ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ QueryDSL์„ ์‚ฌ์šฉํ•˜์˜€๋Š”๋ฐ,
์ฝ”ํ”„๋ง์—์„œ๋Š” ๋ณด๋‹ค ์ •ํ™•ํ•œ ํŽ˜์ด์ง• ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด Custom ํ•˜๊ฒŒ ๋ณ€๊ฒฝํ•œ ๋ถ€๋ถ„์ด ์žˆ์–ด์š”.

kotlin/com/junyharangstudy/kotlingraphqltest/api/people/repository/PeopleQueryDslRepositoryImpl.kt


์ฐธ๊ณ ๋กœ QueryDSL ์‚ฌ์šฉ ์‹œ 15๋ฒˆ์งธ ์ค„์— people์ด ์ธ์‹์ด ์•ˆ ๋˜๋Š” ๊ฑธ ์•Œ ์ˆ˜ ์žˆ๋Š”๋ฐ,
์ด๋Š” ์ผ๋ฐ˜ Entity๊ฐ์ฒด๊ฐ€ ์•„๋‹Œ Q Entity ๊ฐ์ฒด๋ฅผ ์ธ์‹ ์‹œ์ผœ์ค˜์•ผ ํ•˜๋Š”๋ฐ, ์ธ์‹ํ•˜์ง€ ๋ชปํ•˜๊ธฐ ๋•Œ๋ฌธ์ด์—์š”.



์ด๋Ÿด ๋•Œ๋Š” ์œ„์™€ ๊ฐ™์ด Gradle๋ฅผ ์ด์šฉํ•ด Compiler๋ฅผ ๋Œ๋ ค Compile ํ•ด ์ฃผ๋ฉด Q Entity๊ฐ€ ์ƒ๊ธฐ๊ฒŒ ํ•  ์ˆ˜ ์žˆ์–ด์š”.

 

kotlin/com/junyharangstudy/kotlingraphqltest/api/people/repository/PeopleQueryDslRepositoryImpl.kt


์ด์ œ ์ •์‚ญ์ ์œผ๋กœ ์ธ์‹ ๋˜์—ˆ๊ณ , 6๋ฒˆ์งธ ์ค„์— QEntity๊ฐ€ import ๋œ๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด์š”.

kotlin/com/junyharangstudy/kotlingraphqltest/api/people/repository/PeopleQueryDslRepositoryImpl.kt


19 ~ 25๋ฒˆ์งธ ์ค„ ๋‚ด์šฉ์€ ์•„๋ž˜์—์„œ ์ด์•ผ๊ธฐ ํ•ด ๋ณด๋„๋ก ํ•˜๊ณ , ์ผ๋‹จ ์œ„ ๋‚ด์šฉ์„ ๋ถ„์„ํ•ด ๋ณผ๊ฒŒ์š”.


์ตœ์ดˆ @Repository๋กœ Spring์—์„œ ํ•ด๋‹น ํด๋ž˜์Šค๋ฅผ ๋ฐ์ดํ„ฐ ์ ‘๊ทผ ๊ณ„์ธต์˜ ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•ด ์ฃผ๋ฉฐ, ์ด๊ฒƒ์€ Repository ๊ฐ์ฒด์•ผ ๋ผ๊ณ  ์•Œ๋ ค์ค€ ๊ฒƒ์ด์—์š”.

jpaQueryFactory๋Š” QueryDSL์„ ์‚ฌ์šฉํ•˜์—ฌ JPA Query๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ ์œ„ํ•œ Factory์—์š”.
์ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Query๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์–ด์š”.

27 ~ 29๋ฒˆ์งธ ์ค„์— pageRequestDTO์— orderBy ํ”„๋กœํผํ‹ฐ ๊ฐ’์ด False์ด ์•„๋‹Œ์ง€ ํ™•์ธํ•˜๊ณ , True๋ผ๋ฉด peopleID๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋‚ด๋ฆผ์ฐจ์ˆœ์œผ๋กœ ์ •๋ ฌ๋  ์ˆ˜ ์žˆ๊ฒŒ ์ฒ˜๋ฆฌํ•œ ๋ถ€๋ถ„์ด์—์š”.

 

kotlin/com/junyharangstudy/kotlingraphqltest/api/common/QueryDslSupportUtil.kt


QueryDslRepository์—์„œ ์‚ฌ์šฉํ•œ queryDslPagingProcessing()์€ ์œ„์™€ ๊ฐ™์ด ์ •์˜ ๋˜์–ด ์žˆ์–ด์š”.

@Component๋Š” Spring์—์„œ ํ•ด๋‹น ํด๋ž˜์Šค๋ฅผ Component Scan์„ ํ†ตํ•ด Bean์œผ๋กœ ๋“ฑ๋กํ•˜๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด ์„ ์–ธํ•ด ์ฃผ์—ˆ์–ด์š”.

queryDslPagingProcessing()๋Š” JPAQuery์™€ PageRequestDto๋ฅผ ๋งค๊ฐœ ๋ณ€์ˆ˜๋กœ ๋ฐ›์•„ ํŽ˜์ด์ง• ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๊ณ , ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์„œ๋“œ์—์š”.

13๋ฒˆ์งธ ์ค„์—์„œ jpaQuery.stream().count()์˜ ๊ฐ’์ด 2๋ณด๋‹ค ํฌ๊ฑฐ๋‚˜, ๊ฐ™์€์ง€๋ฅผ ํ™•์ธํ•˜๋Š”๋ฐ, 2๋ณด๋‹ค ์ž‘๋‹ค๋ฉด ํŽ˜์ด์ง• ์ฒ˜๋ฆฌํ•  ์ด์œ ๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์ด์—์š”.

ํฌ๊ฑฐ๋‚˜ ๊ฐ™๋‹ค๋ฉด offset๊ณผ limit์„ ์ ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ํŽ˜์ด์ง•๋œ ๊ฒฐ๊ณผ๋ฅผ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋„๋ก ์ฒ˜๋ฆฌํ•ด ์ฃผ์—ˆ์–ด์š”.

๋งŒ์•ฝ ์ž‘๋‹ค๋ฉด ์ฒซ๋ฒˆ์งธ ๋‹จ์ผ ํ•ญ๋ชฉ๋งŒ ๋ฆฌ์ŠคํŠธ์— ๋‹ด์•„ ๋ฐ˜ํ™˜๋˜๋„๋ก ์ฒ˜๋ฆฌํ•ด์ค€ ๋ถ€๋ถ„์ด์—์š”.


 

kotlin/com/junyharangstudy/kotlingraphqltest/api/people/repository/PeopleQueryDslRepositoryImpl.kt

 

kotlin/com/junyharangstudy/kotlingraphqltest/api/people/repository/PeopleQueryDslRepositoryImpl.kt


24 ~ 30๋ฒˆ์งธ ๋‚ด์šฉ์€ ๊ณตํ†ต ๋˜๋Š” ๋ถ€๋ถ„์ด ๋งŽ์•„ ๋Œ€ํ‘œ์ ์œผ๋กœ ๋‹ค๋ฅธ 25, 26๋ฒˆ์งธ ๋‚ด์šฉ์— ๋Œ€ํ•ด ๋ถ„์„ํ•ด ๋ณผ๊ฒŒ์š”.

์ตœ์ดˆ eqFirstName()์€ QueryDSL์—์„œ ์‚ฌ์šฉ๋˜๋Š” BooleanExpression ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š”๋ฐ, ๋งค๊ฐœ ๋ณ€์ˆ˜๋กœ ๋ฐ›์€ firstName ๋ฌธ์ž์—ด์ด ๋น„์–ด์žˆ๊ฑฐ๋‚˜, Null์ด๋ฉด Null์„ ๋ฐ˜ํ™˜ํ•˜๊ณ , ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด people.firstName.eq(firstName) ์˜ ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ๋ผ์š”.

์ข€ ๋” ์ž์„ธํžˆ ์ด์•ผ๊ธฐ ํ•ด ๋ณด์ž๋ฉด 51๋ฒˆ์งธ ์ค„์—์„œ firstName ๋ฌธ์ž์—ด์ด ๋น„์–ด์žˆ๊ฑฐ๋‚˜, Null์ด ์•„๋‹Œ์ง€๋ฅผ ํ™•์ธํ•˜๋Š” StringUtils.hasText(Spring Framework Utility Method)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ™•์ธํ•˜๊ณ , Null์ด ์•„๋‹ˆ๋ผ๋ฉด people.firstName.eq(firstName)์„ ํ†ตํ•ด ์ธ์ž๋กœ ์ „๋‹ฌ๋œ ๋ฌธ์ž์—ด firstName๊ณผ ์„œ๋กœ ๊ฐ™์€์ง€๋ฅผ ํ™•์ธํ•œ ๊ฒฐ๊ณผ BooleanExpresstion ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์ด์—์š”.

6๋ฒˆ์งธ ์ค„์—๋Š” StringUtils.hasText๋ฅผ ํ†ตํ•ด ํ™•์ธํ•˜์ง€ ์•Š์•˜๋Š”๋ฐ, ์ด๋Š” Enum Type์ด๋ผ ๋ฌธ์ž์—ด ์ฒ˜๋Ÿผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์—†์—ˆ๊ธฐ ๋•Œ๋ฌธ์ด์—์š”.

 

 

 

 

 

        ๐Ÿ“ฆ Service

PeopleService.java

 

kotlin/com/junyharangstudy/kotlingraphqltest/api/people/service/PeopleService.kt

 

 

 

PeopleServiceImpl.java
kotlin/com/junyharangstudy/kotlingraphqltest/api/people/service/PeopleServiceImpl.kt


์ฝ”ํ”„๋ง์—์„  ์žํ”„๋ง๋ณด๋‹ค ์ฝ”๋“œ ์ˆ˜๋ฅผ ์—„์ฒญ ์ค„์ธ๊ฑธ ์•Œ ์ˆ˜ ์žˆ์–ด์š”.
์ตœ์ดˆ 22๋ฒˆ์งธ ์ค„์—์„œ ์ž…๋ ฅ๋œ Team์ด ์กด์žฌํ•˜๋Š”์ง€ ์•Œ๊ธฐ ์œ„ํ•ด DTO์— ๋‹ด๊ธด teamID๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์กฐํšŒํ•˜๊ณ , ๊ทธ ๊ฒฐ๊ณผ ๊ฐ’์ด ์—†์œผ๋ฉด ์กด์žฌ ํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ์‘๋‹ตํ•˜๊ฒŒ ํ•ด ๋‘์—ˆ์–ด์š”.

ํ•ด๋‹น ํŒ€์ด ์กด์žฌํ•œ๋‹ค๋ฉด ์†Œ์†ํ•  ํŒ€์ด ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ˆ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ €์žฅํ•ด์ฃผ๊ณ , ์ €์žฅํ•œ ๋’ค ๋ฐ˜ํ™˜๋œ ID ๊ฐ’์„ saveAsPeopleId ๋ณ€์ˆ˜์— ๋‹ด์•„ ์ฃผ์—ˆ์–ด์š”.

๊ทธ ๊ฐ’์ด Null์ด๋ฉด ์ €์žฅ์ด ์ œ๋Œ€๋กœ ์•ˆ๋œ ๊ฒƒ์ด๋‹ˆ ์ €์žฅ์ด ์•ˆ ๋˜์—ˆ๋‹ค๊ณ  ์‘๋‹ต์„ ๋ณด๋‚ด๊ณ , Null์ด ์•„๋‹ˆ๋ฉด ์ œ๋Œ€๋กœ ์ €์žฅ์ด ๋œ ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ €์žฅ์ด ์™„๋ฃŒ๋œ ๊ฒฐ๊ณผ๋ฅผ ์‘๋‹ต์œผ๋กœ ๋ณด๋‚ด๊ฒŒ ์ฒ˜๋ฆฌํ•ด ์ฃผ์—ˆ์–ด์š”.


PeopleServiceImpl.java

 

PeopleServiceImpl.java

 

kotlin/com/junyharangstudy/kotlingraphqltest/api/people/service/PeopleServiceImpl.kt


์—ญ์‹œ ์žํ”„๋ง๋ณด๋‹ค ์ฝ”๋“œ๋ฅผ ๋งŽ์ด ์ค„์ธ๊ฑธ ์•Œ ์ˆ˜ ์žˆ๋Š”๋ฐ, ๊ทธ ๋น„๋ฒ•์€ ๋ฐ”๋กœ ๋”ฐ๋กœ ๋ฉ”์„œ๋“œ๋ฅผ ๋นผ์ฃผ๋ ค๊ณ  ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด์—์š”.

์—ฌ๊ธฐ์„  ์ฝ”ํ”„๋ง๋งŒ์˜ when ์ ˆ์„ ์‚ฌ์šฉํ•ด ๋ณด์•˜์–ด์š”.
39๋ฒˆ์งธ ์ค„์— pageRequestDto์˜ currentPage์™€ perPageSize๊ฐ€ Null์ธ์ง€๋ฅผ ํ™•์ธํ•˜๊ณ , Null์ด ์•„๋‹ˆ๋ฉด 40๋ฒˆ์งธ when ์ค„์„ ๋‹ค์‹œ ํƒ€๊ฒŒ ๋ผ์š”.

์ด ๋•Œ๋Š” peopleSearchRequestDto๊ฐ€ Null์ธ์ง€ ํ™•์ธํ•˜๋Š”๋ฐ, ์•„๋‹ˆ๋ผ๋ฉด processingParameterNotNull()๋กœ ๋‘ ๊ฐ์ฒด๋ฅผ ๋ชจ๋‘ ๋งค๊ฐœ ๋ณ€์ˆ˜๋กœ ๋ณด๋‚ด๊ฒŒ ์ฒ˜๋ฆฌํ•ด ์ฃผ์—ˆ๊ณ , Null์ด๋ผ๋ฉด processingParameterPagingNotNull()๋กœ PageRequestDto ๊ฐ์ฒด๋งŒ ๋ณด๋‚ด๋„๋ก ์ฒ˜๋ฆฌํ–ˆ์–ด์š”.

์ด๋ ‡๊ฒŒ ํ•œ ๊ฒƒ์€ SeacrchRequestDto๊ฐ€ Null์ด ์•„๋‹ˆ๋ฉด ๊ฒ€์ƒ‰ ๋กœ์ง์„ ํƒ€๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•จ์ด๊ณ , ํ•ด๋‹น ๊ฐ์ฒด๊ฐ€ Null์ธ๋ฐ, PageRequestDto๊ฐ€ Null์ด ์•„๋‹Œ ๊ฒฝ์šฐ๋Š” ์ „์ฒด ์กฐํšŒ๋ฅผ ํ•˜๊ณ , ํŽ˜์ด์ง• ์ฒ˜๋ฆฌ๋งŒ ํ•˜๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•จ์ด์—์š”.

๋งŒ์•ฝ ์ด ๋‘ ๊ฐ์ฒด ๋ชจ๋‘ Null์ด๋ผ๋ฉด 46๋ฒˆ์งธ ์ค„์„ ํƒ€๊ฒŒ ๋˜๊ณ , processingParameterNull()์„ ํ˜ธ์ถœํ•˜์—ฌ ์—ฐ์‚ฐ๋œ ๊ฒฐ๊ณผ๋ฅผ ํ†ตํ•ด ํ•ด๋‹น ๊ฒฐ๊ณผ๊ฐ€ ๋น„์–ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ , ๋น„์–ด ์žˆ๋‹ค๋ฉด ๊ฐ’์„ ์ฐพ์ง€ ๋ชปํ–ˆ๋‹ค๋Š” ์‘๋‹ต์„ ๋ณด๋‚ด๊ฒŒ ๋ผ๊ณ , ์•„๋‹ˆ๋ผ๋ฉด ์ •์ƒ ์ฒ˜๋ฆฌ ๋˜์—ˆ๋‹ค๋Š” ๋‚ด์šฉ์„ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ํ•ด ์ฃผ์—ˆ์–ด์š”.


kotlin/com/junyharangstudy/kotlingraphqltest/api/people/service/PeopleServiceImpl.kt


processingParameterNotNull()์€ ์ด๋ ‡๊ฒŒ ๋‘ ๊ฐœ์˜ ๋งค๊ฐœ ๋ณ€์ˆ˜๋ฅผ QueryDsl Repository์˜ findBySearchAndPaging()์œผ๋กœ ๋ณด๋‚ด ์—ฐ์‚ฐ์„ ์ฒ˜๋ฆฌํ•˜๊ณ , ์ฐพ์•„์˜จ ์š”์†Œ๋ฅผ ๋‹ด์€ List ๋ณ€์ˆ˜๋ฅผ ๊ฐ€์ง€๊ณ , ๋น„์–ด ์žˆ๋‹ค๋ฉด ๊ฐ’์„ ๋ชป ์ฐพ์€ ๊ฒƒ์ด๋‹ˆ ๊ฐ’์„ ๋ชป ์ฐพ์•˜๋‹ค๋Š” ๋‚ด์šฉ์„ ์‘๋‹ตํ•ด ์ฃผ๊ฒŒ ํ•ด ์ฃผ๊ณ , ๋น„์–ด ์žˆ์ง€ ์•Š๋‹ค๋ฉด ์ •์ƒ ์ฒ˜๋ฆฌ ๋œ ๊ฒƒ์ด๋‹ˆ ํ•ด๋‹น ๋‚ด์šฉ์„ ResponseDTO๋กœ ๋ฐ”๊ฟ” ์‘๋‹ตํ•˜๊ฒŒ ํ•ด ์ฃผ์—ˆ์–ด์š”.

๊ทธ๋ฆฌ๊ณ , Pagination ์ƒ์„ฑ์ž์˜ ์š”์†Œ์˜ ๊ฐœ์ˆ˜์™€ ํ•ด๋‹น ํ…Œ์ด๋ธ”์˜ ๋ชจ๋“  ์š”์†Œ ๊ฐœ์ˆ˜ ๊ทธ๋ฆฌ๊ณ , ์ •๋ ฌ ์—ฌ๋ถ€๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋‚ด์šฉ์„ ๋‹ด์€ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ํ•ด ์ฃผ์—ˆ์–ด์š”.

kotlin/com/junyharangstudy/kotlingraphqltest/api/people/service/PeopleServiceImpl.kt


processingParameterPagingNotNull()์€ ๊ฒ€์ƒ‰์€ ํ•˜์ง€ ์•Š๊ณ , ํŽ˜์ด์ง• ์ฒ˜๋ฆฌ๋งŒ ํ•˜๊ณ ์ž ํ•  ๋•Œ, ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ๋ฉ”์„œ๋“œ์—์š”.
์œ„์™€ ์ฒ˜๋ฆฌ ๋กœ์ง์€ ๋™์ผํ•˜์ง€๋งŒ, QueryDsl Repository findBySearchAndPaging()์— ๊ฒ€์ƒ‰ ๊ด€๋ จ Dto๋Š” Null์„ ๋ณด๋‚ด๋Š” ๊ฑธ ์•Œ ์ˆ˜ ์žˆ์–ด์š”.

kotlin/com/junyharangstudy/kotlingraphqltest/api/people/service/PeopleServiceImpl.kt


processingParameterNull()์€ People์— ๋Œ€ํ•ด ์ „์ฒด ์กฐํšŒ๋ฅผ ํ•˜๊ณ ๋Š” ์‹ถ์€๋ฐ ๊ทธ ์–ด๋–ค ๊ฐ’๋„ ์ „๋‹ฌํ•˜์ง€ ์•Š์•˜์„ ๋•Œ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ๋ฉ”์„œ๋“œ์—์š”.

JPA Repository์˜ findAll()์„ ํ˜ธ์ถœํ•˜์—ฌ ์ „์ฒด ์š”์†Œ๋ฅผ ๋‹ค ์กฐํšŒํ•œ ๋’ค mapNotNull๋กœ ๋ฐ˜๋ณตํ•˜๋ฉด์„œ Null์ด ์—†๋Š”์ง€๋ฅผ ํ™•์ธํ•˜๊ณ , Null์ด ์•„๋‹Œ ์š”์†Œ๋ฅผ ResponseDTO๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ List์— ๋‹ค์‹œ ์ €์žฅํ•˜๋Š” ๊ณผ์ •์„ ์ˆ˜ํ–‰ํ•˜๊ณ , ๊ทธ List๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ํ•ด ์ฃผ์—ˆ์–ด์š”.


kotlin/com/junyharangstudy/kotlingraphqltest/api/people/service/PeopleServiceImpl.kt


์œ„์˜ ๋กœ์ง์€ teamId๋กœ ๋ฉค๋ฒ„๋ฅผ ๊ฒ€์ƒ‰ํ•˜๊ธฐ ์œ„ํ•œ ๋กœ์ง์ด์—์š”.
์œ„์™€ ๋™์ผํ•œ ๋กœ์ง์ธ๋ฐ, ์œ„์˜ ๋‚ด์šฉ์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ProcessingParameterNotNull()์„ ์ˆ˜์ •ํ•ด ์ฃผ์—ˆ์–ด์š”.

ํ•ด๋‹น ๋‚ด์šฉ์€ GitHub์—์„œ ์ฃผ๋‹ˆ๊ฐ€ ์ž‘์„ฑํ•œ ์ฝ”๋“œ๋ฅผ ํ™•์ธํ•ด ์ฃผ์‹œ๋ฉด ์ข‹์„ ๊ฑฐ ๊ฐ™์•„์š”.

 

GitHub - junyharang-coding-study/GraphQL-Study: GraphQL์„ ๊ณต๋ถ€ํ•˜๊ณ , ์‹ค์Šตํ•œ ์ฝ”๋“œ์—์š” ๐Ÿ˜€

GraphQL์„ ๊ณต๋ถ€ํ•˜๊ณ , ์‹ค์Šตํ•œ ์ฝ”๋“œ์—์š” ๐Ÿ˜€. Contribute to junyharang-coding-study/GraphQL-Study development by creating an account on GitHub.

github.com

 

PeopleServiceImpl.java
kotlin/com/junyharangstudy/kotlingraphqltest/api/people/service/PeopleServiceImpl.kt


์œ„ ์ฝ”๋“œ๋Š” ์ƒ์„ธ ์กฐํšŒ ๋กœ์ง์œผ๋กœ peopleId๋ฅผ ๋ฐ›๊ฒŒ ๋˜๋ฉด JPA๋ฅผ ์ด์šฉํ•˜์—ฌ ํ•ด๋‹น ID๋ฅผ ์ด์šฉํ•ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๊ฒ€์ƒ‰์„ ํ•˜๊ณ ,
๊ฐ’์ด ์žˆ์œผ๋ฉด ์ •์ƒ ์ฒ˜๋ฆฌํ–ˆ๋‹ค๊ณ  ์‘๋‹ตํ•˜๊ณ , ์•„๋‹ˆ๋ฉด ๊ฐ’์„ ๋ชป ์ฐพ์•˜๋‹ค๊ณ  ์—๋Ÿฌ๋ฅผ ์‘๋‹ตํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•ด ์ค€ ๋ถ€๋ถ„์ด์—์š”.





kotlin/com/junyharangstudy/kotlingraphqltest/api/people/service/PeopleServiceImpl.kt


์œ„ ์ฝ”๋“œ๋Š” ์ˆ˜์ •์„ ์œ„ํ•œ ๋กœ์ง์ด์—์š”.
์ตœ์ดˆ ๋ฉค๋ฒ„ ID๋ฅผ ์ด์šฉํ•ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๊ฐ’์„ ์กฐํšŒํ•˜๊ณ , ํ•ด๋‹น ID๋ฅผ ๊ฐ€์ง„ ๊ฐœ์ฒด์˜ ์š”์†Œ๋ฅผ ๊ฐ€์ ธ์˜ค๊ฒŒ ๋ผ์š”.

๊ทธ ๊ฐœ์ฒด๊ฐ€ ๋น„์–ด ์žˆ๋‹ค๋ฉด ์ˆ˜์ •ํ•  ๋Œ€์ƒ์„ ์ฐพ์ง€ ๋ชปํ–ˆ๋‹ค๋Š” ์—๋Ÿฌ ์‘๋‹ต์„ ๋ณด๋‚ด์ฃผ๊ณ , ๋น„์–ด ์žˆ์ง€ ์•Š๋‹ค๋ฉด chekUpdateRequest()์— DTO์™€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์ฐพ์€ ๊ฐœ์ฒด๊ฐ€ Optional๋กœ ๊ฐ์‹ธ์ ธ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— get()์„ ํ†ตํ•ด Entity ๊ฐ์ฒด๋กœ ๋ณ€๊ฒฝํ•ด์„œ ๋งค๊ฐœ ๋ณ€์ˆ˜๋กœ ์ „๋‹ฌํ•ด ์ฃผ์—ˆ์–ด์š”.

๊ทธ๋Ÿฐ ๋’ค ์ •์ƒ ์ฒ˜๋ฆฌ๊ฐ€ ๋˜์—ˆ๋‹ค๋Š” ์‘๋‹ต์„ ์ฃผ๋ฉด์„œ ํ•ด๋‹น ์ธ์›์˜ ID๊ฐ’์„ ํ•จ๊ป˜ ๋ฐ˜ํ™˜ํ•ด ์ฃผ์—ˆ์–ด์š”.

 

kotlin/com/junyharangstudy/kotlingraphqltest/api/people/service/PeopleServiceImpl.kt


checkUpdateRequest()๋Š” ์š”์ฒญ DTO์— ๋‹ด๊ฒจ ์žˆ๋Š” ๊ฐ’๋“ค๋งŒ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•ด Null ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๊ณ , Null์ด ์•„๋‹Œ ๊ฐ’๋งŒ ๊ฐ๊ฐ์˜ update()๋ฅผ ์ด์šฉํ•ด์„œ Entity ํ”„๋กœํผํ‹ฐ์— ๊ฐ’์„ ๋‹ด์•„ ์ฃผ๋„๋ก ํ–ˆ์–ด์š”.

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด JPA ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์˜ 1์ฐจ ์บ์‹œ๊ฐ’๊ณผ ๊ฐ’์ด ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์— Update Query๊ฐ€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋กœ ๋‚ ์•„๊ฐ€๊ฒŒ ๋  ๊ฑฐ์—์š”.

์ฐธ๊ณ ๋กœ people.apply{}๋Š” ์ฝ”ํ‹€๋ฆฐ์—์„œ ์ œ๊ณตํ•˜๋Š” ํ™•์žฅ ํ•จ์ˆ˜ apply๋ฅผ ์‚ฌ์šฉํ•œ ์ฝ”๋“œ ๋ธ”๋ก์ด์—์š”.
apply()๋Š” ์ˆ˜์‹  ๊ฐ์ฒด๋ฅผ ๋ณ€๊ฒฝํ•˜๊ฑฐ๋‚˜, ์ดˆ๊ธฐํ™” ํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋˜๊ณ , ์ˆ˜์‹  ๊ฐ์ฒด ์ž์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํŠน์ง•์„ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์š”. ์ฆ‰, ์ฝ”๋“œ ๋ธ”๋ก ๋‚ด์—์„œ ์ˆ˜์‹  ๊ฐ์ฒด์— ๋Œ€ํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ์ด์šฉํ•ด์š”.

์ข€ ๋” ์ž์„ธํžˆ ์ด์•ผ๊ธฐ ํ•ด๋ณด์ž๋ฉด people.apply{}๋Š” people ๊ฐ์ฒด์— ๋Œ€ํ•œ ์ผ๋ จ์˜ ๋ณ€๊ฒฝ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ์„ ์–ธํ•œ ๊ฒƒ์ด์—์š”.
people ๊ฐ์ฒด์˜ ์ƒํƒœ๋ฅผ peopleUpdateRequestDto์—์„œ ๊ฐ€์ ธ์˜จ ๊ฐ’์œผ๋กœ ์ˆ˜์ •ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ ๊ฒƒ์ด์—์š”.

apply()๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ถˆ ํ•„์š”ํ•œ ๋ณ€์ˆ˜ ํ• ๋‹น์„ ํ”ผํ•˜๋ฉด์„œ ์ฝ”๋“œ๋ฅผ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ์–ด์š”.

๐Ÿ’ก ์ฐธ๊ณ  ์‚ฌํ•ญ
apply๋ž€?

1. ์ˆ˜์‹  ๊ฐ์ฒด ์„ค์ •: apply()์˜ ์ˆ˜์‹  ๊ฐ์ฒด๋Š” this ์—ฐ์‚ฐ์ž๋กœ ์ฐธ์กฐ.
2. ๊ฐ์ฒด ๋ณ€๊ฒฝ ๋˜๋Š” ์ดˆ๊ธฐํ™”: apply() ๋‚ด๋ถ€์—์„œ๋Š” ์ˆ˜์‹  ๊ฐ์ฒด์— ๋Œ€ํ•œ ๋ณ€๊ฒฝ ์ž‘์—… ์ˆ˜ํ–‰. when ์ ˆ์—์„œ๋Š” peopleUpdateRequestDto์—์„œ ํ•ด๋‹นํ•˜๋Š” ํ•„๋“œ๊ฐ€ Null์ด ์•„๋‹Œ ๊ฒฝ์šฐ์—๋งŒ ํ•ด๋‹น ํ•„๋“œ ์—…๋ฐ์ดํŠธ ์ง„ํ–‰.
3. ์ˆ˜์‹  ๊ฐ์ฒด ๋ฐ˜ํ™˜: apply()๋Š” ๋งˆ์ง€๋ง‰์— ์ˆ˜์‹  ๊ฐ์ฒด ๋ฐ˜ํ™˜. ๋”ฐ๋ผ์„œ return people.apply{}๋Š” ๋ณ€๊ฒฝ๋œ people ๊ฐ์ฒด ๋ฐ˜ํ™˜.

 

 

 

PeopleServiceImpl.java
kotlin/com/junyharangstudy/kotlingraphqltest/api/people/service/PeopleServiceImpl.kt


์œ„ ์ฝ”๋“œ๋Š” ์‚ญ์ œ ๋กœ์ง ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ์ฝ”๋“œ์—์š”.
peopleId๋ฅผ ์ธ์ž๋กœ ๋ฐ›์•„ JPA findById()๋ฅผ ํ†ตํ•ด ํ•ด๋‹น ID์— ํ•ด๋‹นํ•˜๋Š” ๋ฉค๋ฒ„์˜ ์š”์†Œ๋ฅผ ์ฐพ๊ฒŒ ๋˜๊ณ , ๊ทธ ์š”์†Œ๊ฐ€ ๋น„์–ด ์žˆ๋‹ค๋ฉด ์‚ญ์ œ ๋Œ€์ƒ์„ ๋ชป ์ฐพ์•˜๋‹ค๋Š” ์—๋Ÿฌ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ๋˜๊ณ , ๋น„์–ด ์žˆ์ง€ ์•Š๋‹ค๋ฉด 127๋ฒˆ์งธ ์ค„์„ ํ†ตํ•ด ํ•ด๋‹น ์š”์†Œ์˜ ID๋ฅผ ์ด์šฉํ•˜์—ฌ ์‚ญ์ œ๋ฅผ ํ•ด ์ฃผ๊ณ , ์ •์ƒ์ ์œผ๋กœ ์‚ญ์ œ ๋˜์—ˆ๋‹ค๋Š” ๊ฒƒ์„ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•ด ์ฃผ์—ˆ์–ด์š”.

 

 

 

 

    ๐Ÿ”ฝ graphqls(Schema)

        ๐Ÿ“ฆ query.graphqls

kotlin/com/junyharangstudy/kotlingraphqltest/api/people/resolver/PeopleResolver.kt

 

resources/graphql/graphql/query.graphqls




        ๐Ÿ“ฆ mutaion.graphqls

kotlin/com/junyharangstudy/kotlingraphqltest/api/people/resolver/PeopleResolver.kt

 

kotlin/com/junyharangstudy/kotlingraphqltest/api/people/resolver/PeopleResolver.kt

 

resources/graphql/graphql/mutaion.graphqls





 

        ๐Ÿ“ฆ people.graphqls

resources/graphql/graphql/people/people.graphqls

 

resources/graphql/graphql/people/people.graphqls

 

resources/graphql/graphql/people/people.graphqls



์œ„์™€ ๊ฐ™์ด 
GraphQL ์Šคํ‚ค๋งˆ๋ฅผ ๊ตฌ์„ฑํ•ด ์ฃผ์—ˆ์–ด์š”.

 

 

 

    ๐Ÿ”ฝ ์ž˜ ๋งŒ๋“ค์—ˆ๋‚˜? ๐Ÿค”

        ๐Ÿ“ฆ People CRUD Test

๋งŒ๋“ค์–ด์ง„ ๋กœ์ง์„ ์ด์šฉํ•˜์—ฌ CRUD Test๋ฅผ ์ง„ํ–‰ํ•ด ๋ณผ๊ฒŒ์š”.

http://localhost:8080/graphiql


์œ„์™€ ๊ฐ™์ด Apollo Playgroud์™€ ๊ฐ™์€ ์„œ๋น„์Šค๋ฅผ Spring For GraphQL๋„ ์ œ๊ณตํ•˜๋Š”๋ฐ ์ด๋ฆ„์ด Graphiql ๊ฐ™์•„์š”.
์ฐธ๊ณ ๋กœ ์ด ์นœ๊ตฌ๋Š” ๋กœ์ง์ด ๊ตฌํ˜„๋˜์–ด์•ผ ์˜ฌ๋ผ์™€์š”.

๋กœ์ง์ด ๊ตฌํ˜„๋˜์ง€ ์•Š์€ ์ƒํƒœ์—์„œ application.yml์— ์„ค์ •๋งŒ ํ•ด ์ฃผ์—ˆ๋‹ค๊ณ  ํ•ด์„œ URL์„ ์ž…๋ ฅํ•˜๋ฉด White Error๋งŒ ๋‚˜์˜ฌ๊ฑฐ์—์š”.
์ฃผ๋‹ˆ๋Š” ๊ทธ๋ž˜์„œ ๊ต‰์žฅํžˆ ๋‹นํ™ฉํ–ˆ๊ฑฐ๋“ ์š”.

 

http://localhost:8080/graphiql?path=/graphql

 

query findBygetPeopleListSeachAndPaging {
  getPeopleList(
    peopleSearchRequestDto: {
      # lastName: "",
      # firstName: "",
      # sex: "",
      # bloodType: "",
      # serveYears: "",
      # role: "",
      hometown: "California",
    },
    pageRequestDto: {
      currentPage: 1,
      perPageSize: 10,
      orderBy: true
    }) {
    statusCode,
    message,
    data {
      peopleId,
      teamId,
      lastName,
      firstName,
      sex,
      bloodType,
      serveYears,
      role,
      hometown
    },
    pagination {
      perPageSize,
      totalElementCount,
      totalPage,
      orderBy
    }
  }
}

 

์œ„์™€ ๊ฐ™์ด ํŽ˜์ด์ง• ์ฒ˜๋ฆฌ์™€ ๊ฒ€์ƒ‰ ๋ชจ๋‘ ์ž˜ ๋˜๋Š” ๊ฑธ ์•Œ ์ˆ˜ ์žˆ์–ด์š”.

http://localhost:8080/graphiql?path=/graphql


์•„๋ฌด ์กฐ๊ฑด์„ ์ฃผ์ง€ ์•Š์•„๋„ ์ž˜ ๋™์ž‘ํ•˜๋Š” ๊ฑธ ์•Œ ์ˆ˜ ์žˆ์–ด์š”.

 

http://localhost:8080/graphiql?path=/graphql

 

query getPeopleByPeopleId {
  getPeopleByPeopleId(peopleId: 1) {
    statusCode,
    message,
    data {
      peopleId,
      teamId,
      lastName,
      firstName,
      sex,
      bloodType,
      serveYears,
      role,
      hometown
    }
  }
}


peopleId๋ฅผ ์ด์šฉํ•œ ์ƒ์„ธ ์กฐํšŒ๋„ ์ •์ƒ์ ์œผ๋กœ ๋™์ž‘ํ•˜๋Š” ๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด์š”.




http://localhost:8080/graphiql?path=/graphql

query getPeopleListByTeamId {
  getPeopleListByTeamId(
    teamId: 1,
    pageRequestDto: {
      currentPage: 1,
      perPageSize: 10,
      orderBy: true
  }) {
    statusCode,
    message,
    data {
      peopleId,
      teamId,
      lastName,
      firstName,
      sex,
      bloodType,
      serveYears,
      role,
      hometown
    },
    pagination {
      perPageSize,
      totalElementCount,
      totalPage,
      orderBy
    }
  }
}


teamId๋ฅผ ์ด์šฉํ•œ ๋ชฉ๋ก ์กฐํšŒ๋„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•ด ๋†“์•˜์–ด์š”.


http://localhost:8080/graphiql?path=/graphql

mutation savePeople {
  savePeople(input: {
    teamId: 1,
    lastName: "H",
    firstName: "Juny",
    sex: "male",
    bloodType: "B",
    serveYears: 10,
    role: "developer",
    hometown: "Seoul"
  }) {
    statusCode,
    message,
    data
  }
}


์‚ฝ์ž…๋„ ์ž˜ ๋˜๋Š” ๊ฑธ ์•Œ ์ˆ˜ ์žˆ์–ด์š”.



http://localhost:8080/graphiql?path=/graphql

mutation updatePeople {
  updatePeople(
    peopleId: 50,
    input: {
    teamId: 5,
    lastName: "H"
    firstName: "Junyss",
    serveYears: 20,
  }) {
    statusCode,
    message,
    data
  }
}


์ˆ˜์ • ์ฒ˜๋ฆฌ๋„ ์ž˜ ์ง„ํ–‰ ๋˜๋Š” ๊ฑธ ์•Œ ์ˆ˜ ์žˆ์–ด์š”.



http://localhost:8080/graphiql?path=/graphql

 

mutation deletePeople {
  deletePeople(peopleId: 50) {
    statusCode,
    message,
    data
  }
}


์‚ญ์ œ ๊นŒ์ง€ ๊น”๋”ํ•˜๊ฒŒ ์ง„ํ–‰ ๋˜์—ˆ์–ด์š”.


์ด๋ ‡๊ฒŒ ๋ชจ๋‘ ์ •์ƒ ์ฒ˜๋ฆฌ ๋˜๋Š” ๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด์š”.


People ์™ธ์— ๋‹ค๋ฅธ ๊ฒƒ๋“ค์€ Git Hub ์†Œ์Šค ์ฝ”๋“œ๋ฅผ ์ฐธ๊ณ ํ•ด ์ฃผ์„ธ์š”.
์ฐธ๊ณ ๋กœ ๊ฐ ๋„๋ฉ”์ธ ๋ณ„๋กœ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด ๋กœ์ง์ด ์กฐ๊ธˆ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์œผ๋‹ˆ ์ด ์  ์ฐธ๊ณ ํ•ด ์ฃผ์„ธ์š”!

https://github.com/junyharang-coding-study/GraphQL-Study/tree/master/graphql-test


์ด์ œ ๊ฐ•์˜์—์„œ ๋ฐฐ์› ๋˜ ์‹ค์Šต์„ ์ง„ํ–‰ํ•ด ๋ณผ๊ฒŒ์š”.



 

 

 

 

ํ† ๋น„์˜ ์Šคํ”„๋ง 3.1 Vol 1: ์Šคํ”„๋ง์˜ ์ดํ•ด์™€ ์›๋ฆฌ

COUPANG

www.coupang.com

"์ด ํฌ์ŠคํŒ…์€ ์ฟ ํŒก ํŒŒํŠธ๋„ˆ์Šค ํ™œ๋™์˜ ์ผํ™˜์œผ๋กœ, ์ด์— ๋”ฐ๋ฅธ ์ผ์ •์•ก์˜ ์ˆ˜์ˆ˜๋ฃŒ๋ฅผ ์ œ๊ณต๋ฐ›์Šต๋‹ˆ๋‹ค."

 

 

 

 

๐Ÿง ์ฐธ๊ณ  ์ž๋ฃŒ

 

[์ฝ”ํ”„๋ง] Java ์„œ๋ฒ„๋ฅผ Kotlin์œผ๋กœ

๐Ÿ‘ Java๋ฅผ Kotlin์œผ๋กœ! ์ง€๋‚œ ์‹œ๊ฐ„์—๋Š” ์ฝ”ํ‹€๋ฆฐ์— ์ต์ˆ™ํ•ด์ง€๊ธฐ ์œ„ํ•œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑ๋ฒ•์„ ๋”ฐ๋ผ ์ ์–ด๋ดค๋‹ค. ์ด์ œ Java ํ”„๋กœ์ ํŠธ๋ฅผ Kotlin์œผ๋กœ ๋ณ€๊ฒฝํ•ด๋ณด๋Š” ์‹œ๊ฐ„์„ ๊ฐ€์ ธ๋ณด์ž! ๐Ÿ“— Domain ๋ฆฌํŒฉํ† ๋ง ๐Ÿ“„ Book ๋จผ์ €

velog.io

 

 

 

GitHub - junyharang-coding-study/GraphQL-Study: GraphQL์„ ๊ณต๋ถ€ํ•˜๊ณ , ์‹ค์Šตํ•œ ์ฝ”๋“œ์—์š” ๐Ÿ˜€

GraphQL์„ ๊ณต๋ถ€ํ•˜๊ณ , ์‹ค์Šตํ•œ ์ฝ”๋“œ์—์š” ๐Ÿ˜€. Contribute to junyharang-coding-study/GraphQL-Study development by creating an account on GitHub.

github.com

 

 

 

 

์นด์นด์˜คํŽ˜์ด | ๋งˆ์Œ ๋†“๊ณ  ๊ธˆ์œตํ•˜๋‹ค

์—ฌ๊ธฐ๋ฅผ ๋ˆŒ๋Ÿฌ ๋งํฌ๋ฅผ ํ™•์ธํ•˜์„ธ์š”.

qr.kakaopay.com

 

 

 

728x90
๋ฐ˜์‘ํ˜•