Back-End ์ž‘์—…์‹ค/Nest.js

GraphQL๊ณผ Apollo ์—ด ์„ธ๋ฒˆ์งธ ์ด์•ผ๊ธฐ - TypeScript + Nest์—์„œ GraphQL ์‚ฌ์šฉํ•ด ๋ณด๊ธฐ - ์‹ค์Šต ํ•ด๋ณด๊ธฐ

์ฃผ๋‹ˆ์“ฐ๐Ÿง‘‍๐Ÿ’ป 2023. 12. 7. 22:46
728x90
๋ฐ˜์‘ํ˜•

 

 

 

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

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

qr.kakaopay.com

 

 

 

 

 

NestJS๋กœ ๋ฐฐ์šฐ๋Š” ๋ฐฑ์—”๋“œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ:ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ํ™˜๊ฒฝ์˜ ์ฐจ์„ธ๋Œ€ ์„œ๋ฒ„ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ๋งŒ๋‚˜๋‹ค

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)

 

 

 

 

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

    ๐Ÿ”ฝ TypeScript + Nest์—์„œ GraphQL ์‚ฌ์šฉํ•ด ๋ณด๊ธฐ - ์‹ค์Šต ํ•ด๋ณด๊ธฐ

        ๐Ÿ“ฆ ๊ฐœ์š”

์žํ”„๋ง(Java + Spring Boot)์—์„œ๋„ ๊ทธ๋žฌ๋“ฏ ์ง€๋‚œ ๊ธ€๊นŒ์ง€ Nest.ts๋ฅผ ์ด์šฉํ•˜์—ฌ GraphQL ํ™˜๊ฒฝ ๊ตฌ์„ฑ์„ ์œ„ํ•œ ์ž‘์—…์„ ์ง„ํ–‰ํ•ด ๋ณด์•˜์–ด์š”.

์žํ”„๋ง ๊ธ€๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์‹ค์Šต์„ ์ง„ํ–‰ํ•ด ๋ณด๋„๋ก ํ• ๊ฒŒ์š”.

 

 

 

 

 

 

    ๐Ÿ”ฝ  ์„ธ๋ฒˆ์งธ ์ด์•ผ๊ธฐ ์‹ค์Šต

        ๐Ÿ“ฆ Overfetching

Overfetching ๋ฌธ์ œ์— ๋Œ€ํ•œ ์ด์•ผ๊ธฐ๋Š” ์žํ”„๋ง ์‹ค์Šต ๋•Œ ๋ณด๋‹ค ์ž์„ธํžˆ ์ด์•ผ๊ธฐ ํ•ด ๋ณด์•˜์–ด์š”.

Nest.ts์˜ ๊ฒฝ์šฐ ์ด๋ฅผ ๋ชจ๋‘ ํ•ด๊ฒฐํ•ด์„œ ๊ตฌ์„ฑ์„ ํ•˜์˜€๊ธฐ ๋•Œ๋ฌธ์— ์žํ”„๋ง ๋‚ด์šฉ์„ ์ฐธ๊ณ ํ•ด ์ฃผ์‹œ๋ฉด ์ข‹์„ ๊ฑฐ ๊ฐ™์•„์š”.

 

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

์ž๋ฐ” ORM ํ‘œ์ค€ JPA ํ”„๋กœ๊ทธ๋ž˜๋ฐ:์Šคํ”„๋ง ๋ฐ์ดํ„ฐ ์˜ˆ์ œ ํ”„๋กœ์ ํŠธ๋กœ ๋ฐฐ์šฐ๋Š” ์ „์ž์ •๋ถ€ ํ‘œ์ค€ ๋ฐ์ดํ„ฐ๋ฒ ์ด COUPANG www.coupang.com "์ด ํฌ์ŠคํŒ…์€ ์ฟ ํŒก ํŒŒํŠธ๋„ˆ์Šค ํ™œ๋™์˜ ์ผํ™˜์œผ๋กœ, ์ด์— ๋”ฐ๋ฅธ ์ผ์ •์•ก์˜ ์ˆ˜์ˆ˜๋ฃŒ๋ฅผ ์ œ

junyharang.tistory.com

 

 

 

 

        ๐Ÿ“ฆ Underfetching

์ด๋ฒˆ์—” Underfetching์— ๋Œ€ํ•ด ์‹ค์Šตํ•˜๋ฉด์„œ ๋ถ„์„ํ•ด ๋ณด๋ ค๊ณ  ํ•ด์š”.

http://localhost:8081/graphql

728x90
query getEquipmentsAndSupplies {
  getEquipmentList(
    pageNumber: 1,
    perPageSize: 10
  ) {
    statusCode,
    message,
    pagination {
      perPageSize,
      totalCount,
      totalPage
      data {
     		equipmentId,
        usedBy,
        newOrUsed
      }
    }
  }
  
  getSupplyList(
    pageNumber: 1,
    perPageSize: 10
  ) {
    statusCode,
    message,
    pagination {
      perPageSize,
      totalCount,
      totalPage
      data {
        supplyId,
     		teamId,
      }
    }
  }
}



{
  "data": {
    "getEquipmentList": {
      "statusCode": 200,
      "message": "Success",
      "pagination": {
        "perPageSize": 6,
        "totalCount": 6,
        "totalPage": 1,
        "data": [
          {
            "equipmentId": "machanical keyboard",
            "usedBy": "developer",
            "newOrUsed": "used"
          },
          {
            "equipmentId": "pen tablet",
            "usedBy": "developer",
            "newOrUsed": "used"
          },
          {
            "equipmentId": "ergonomic mouse",
            "usedBy": "designer",
            "newOrUsed": "used"
          },
          {
            "equipmentId": "dual monitor",
            "usedBy": "developer",
            "newOrUsed": "used"
          },
          {
            "equipmentId": "whiteboard",
            "usedBy": "planner",
            "newOrUsed": "used"
          },
          {
            "equipmentId": "sketchb",
            "usedBy": "designer",
            "newOrUsed": "new"
          }
        ]
      }
    },
    "getSupplyList": {
      "statusCode": 200,
      "message": "Success",
      "pagination": {
        "perPageSize": 10,
        "totalCount": 10,
        "totalPage": 1,
        "data": [
          {
            "supplyId": "calculator",
            "teamId": 5
          },
          {
            "supplyId": "chair",
            "teamId": 3
          },
          {
            "supplyId": "ergonomic mouse",
            "teamId": 1
          },
          {
            "supplyId": "headphone",
            "teamId": 4
          },
          {
            "supplyId": "hoodie",
            "teamId": 2
          },
          {
            "supplyId": "mug",
            "teamId": 1
          },
          {
            "supplyId": "stempler",
            "teamId": 4
          },
          {
            "supplyId": "t shirt",
            "teamId": 5
          },
          {
            "supplyId": "usb hub",
            "teamId": 3
          },
          {
            "supplyId": "webcam",
            "teamId": 2
          }
        ]
      }
    }
  }
}


์œ„ ๋‚ด์šฉ์„ ๋ณด๋ฉด ํ•˜๋‚˜์˜ ์ฟผ๋ฆฌ๋ฅผ ๋ณด๋‚ด ๋‘ ๊ฐœ์˜ ๊ฐ๊ฐ ์›ํ•˜๋Š” ์‘๋‹ต๊ฐ’์„ ๋ฐ›์€ ๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด์š”.

src/graphql/schema/schema.graphqls

 

src/graphql/schema/schema.graphqls


์ด๋ ‡๊ฒŒ ๋‘ ๊ฐœ์˜ ์Šคํ‚ค๋งˆ์— ๋Œ€ํ•ด ์กฐํšŒ๋ฅผ ๋‚ ๊ฒŒ๋ฉด ํ•˜๋‚˜์˜ ์š”์ฒญ์œผ๋กœ ๋‘ ๊ฐœ์˜ ๊ฐ’์„ ์–ป์„ ์ˆ˜ ์žˆ๋Š” ๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด์š”.
Join ์ด๋‚˜, ๋‹ค๋ฅธ ๊ฑธ ํ•˜์ง€ ์•Š๊ณ ๋„ ์ด๋ ‡๊ฒŒ ์–ป์„ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด์—์š”.

๊ทผ๋ฐ ์œ„์—์„œ Supply๋Š” Http Status Code์™€ Message๋ฅผ ๋ฐ›๊ณ  ์‹ถ์ง€ ์•Š๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ์š”?

http://localhost:8081/graphql


์œ„์™€ ๊ฐ™์ด ๋ฐ›๊ณ  ์‹ถ์ง€ ์•Š๋Š” Field๋ฅผ ์š”์ฒญ์— ๋ณด๋‚ด์ง€ ์•Š์œผ๋ฉด ํ•ด๋‹น ๋‚ด์šฉ์€ ์‘๋‹ตํ•˜์ง€ ์•Š๋Š”๊ฑธ ๋ณผ ์ˆ˜ ์žˆ์–ด์š”.
์ด๋ ‡๊ฒŒ Overfetching ๋ฌธ์ œ์— ๋Œ€ํ•ด ์ž์œ ๋กญ๊ฒŒ ์›ํ•˜๋Š” ๊ฐ’๋งŒ ๋ฐ›์„ ์ˆ˜ ์žˆ์–ด์š”.

{
  "data": {
    "getEquipmentList": {
      "statusCode": 200,
      "message": "Success",
      "pagination": {
        "perPageSize": 6,
        "totalCount": 6,
        "totalPage": 1,
        "data": [
          {
            "equipmentId": "machanical keyboard",
            "usedBy": "developer",
            "newOrUsed": "used"
          },
          {
            "equipmentId": "pen tablet",
            "usedBy": "developer",
            "newOrUsed": "used"
          },
          {
            "equipmentId": "ergonomic mouse",
            "usedBy": "designer",
            "newOrUsed": "used"
          },
          {
            "equipmentId": "dual monitor",
            "usedBy": "developer",
            "newOrUsed": "used"
          },
          {
            "equipmentId": "whiteboard",
            "usedBy": "planner",
            "newOrUsed": "used"
          },
          {
            "equipmentId": "sketchb",
            "usedBy": "designer",
            "newOrUsed": "new"
          }
        ]
      }
    },
    "getSupplyList": {
      "pagination": {
        "perPageSize": 10,
        "totalCount": 10,
        "totalPage": 1,
        "data": [
          {
            "supplyId": "calculator",
            "teamId": 5
          },
          {
            "supplyId": "chair",
            "teamId": 3
          },
          {
            "supplyId": "ergonomic mouse",
            "teamId": 1
          },
          {
            "supplyId": "headphone",
            "teamId": 4
          },
          {
            "supplyId": "hoodie",
            "teamId": 2
          },
          {
            "supplyId": "mug",
            "teamId": 1
          },
          {
            "supplyId": "stempler",
            "teamId": 4
          },
          {
            "supplyId": "t shirt",
            "teamId": 5
          },
          {
            "supplyId": "usb hub",
            "teamId": 3
          },
          {
            "supplyId": "webcam",
            "teamId": 2
          }
        ]
      }
    }
  }
}


์œ„์˜ ์‹ค์Šต์„ ํ†ตํ•ด Underfetching ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ ๋˜๋Š” ๊ฑธ ์•Œ ์ˆ˜ ์žˆ์–ด์š”.






 

        ๐Ÿ“ฆ ๋‘ ๋ฒˆ์˜ ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค ์กฐํšŒ - REST API๋„ ๊ตฌ์„ฑํ•ด ๋ณด๊ธฐ

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

์ฃผ๋‹ˆ๋Š” teamId๋ฅผ ์ด์šฉํ•ด์„œ Team๊ณผ People ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๊ฒŒ ๊ตฌ์„ฑํ•ด ๋ณด๋ ค๊ณ  ํ•ด์š”.

team.resolver.ts


์œ„ Resolver(๋ฆฌ์กธ๋ฒ„)๋Š” teamId๋ฅผ ๋ฐ›์•„ ์ •๋ณด๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋Š” Router์—์š”.


src/app/team/service/team-impl.service.ts


๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์€ ์œ„์™€ ๊ฐ™์ด ๋˜์–ด ์žˆ๋Š”๋ฐ, 88๋ฒˆ์งธ ์ค„์—์„œ TypeORM์„ ์ด์šฉํ•ด์„œ TeamId๋ฅผ ์ด์šฉํ•˜์—ฌ Team ์ •๋ณด๋ฅผ ์กฐํšŒํ•˜๋„๋ก ํ•˜์˜€์–ด์š”.

๊ทธ๋Ÿฐ ๋’ค 90๋ฒˆ์งธ ์ค„์—์„œ teamId๋ฅผ ํ†ตํ•ด QueryBuilder์— Custom Method๋ฅผ ๋งŒ๋“ค์–ด People ์ •๋ณด๋ฅผ ์กฐํšŒํ•˜๋Š”๋ฐ, Team์— ์†Œ์†๋œ ์‚ฌ๋žŒ์€ ์—ฌ๋Ÿฌ๋ช…์ด๊ธฐ ๋•Œ๋ฌธ์— Array(๋ฐฐ์—ด)๋กœ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ํ•˜์˜€๊ณ , ์ด๋ฅผ map()์„ ์ด์šฉํ•˜์—ฌ ๋ฐ˜๋ณต๋ฌธ์„ ๋Œ๋ฆฌ๋ฉด์„œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์กฐํšŒ๋œ People Entity๋ฅผ PeopleResponseDto๋กœ ๋ณ€ํ™˜ํ•œ ๋’ค ์ด๋ฅผ ๋‹ค์‹œ ๋ฐฐ์—ด ๋ณ€์ˆ˜ peopleResponseDto๋กœ ๋ฐ›๊ฒŒ ํ•ด ์ฃผ์—ˆ์–ด์š”.

๊ทธ๋Ÿฐ ๋’ค ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์กฐํšŒ๋œ ๊ฒฐ๊ณผ๊ฐ€ Null์ธ์ง€ ํ™•์ธํ•˜๊ณ , Null์ด ์•„๋‹ˆ๋ผ๋ฉด TeamAndMemberResponseDto ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค๊ณ , ์ƒ์„ฑ์ž๋ฅผ ์ด์šฉํ•ด์„œ ๊ฐ์ฒด๊ฐ€ ๋งŒ๋“ค์–ด ์ง€๊ฒŒ ํ•œ ๋’ค ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ํ•ด ์ฃผ์—ˆ์–ด์š”.


src/app/team/model/dto/response/team-and-member-response.dto.ts


DTO๋Š” ์œ„์™€ ๊ฐ™์ด ๊ตฌ์„ฑ ๋˜์–ด ์žˆ๋Š”๋ฐ, 12๋ฒˆ์งธ ์ค„๊ณผ ๊ฐ™์ด ํ•œ ๊ฐœ์˜ ํŒ€์— ์†Œ์†๋œ ์—ฌ๋Ÿฌ ์‚ฌ๋žŒ์„ ๋ฐ›๊ธฐ ์œ„ํ•ด ๋ฉค๋ฒ„ ๋ณ€์ˆ˜๋ฅผ ๋ฐฐ์—ด๋กœ ํ•˜์—ฌ PeopleResponseDto๊ฐ€ ๋‹ด๊ธธ ์ˆ˜ ์žˆ๊ฒŒ ์„ ์–ธํ•ด ์ฃผ์—ˆ๊ณ , ์ƒ์„ฑ์ž๋ฅผ ์ด์šฉํ•ด์„œ ๊ฐ’์ด ๋‹ด๊ธธ ๋•Œ, 22๋ฒˆ์งธ ์ค„์„ ๋ณด๋ฉด peopleResponseDto์— ๊ฐ’์ด ์žˆ์„ ๊ฒฝ์šฐ ๊ทธ ๊ฐ’์„ ๊ทธ๋Œ€๋กœ members๋ผ๋Š” ๋ฉค๋ฒ„ ๋ณ€์ˆ˜์— ๋„ฃ์–ด์ฃผ๊ณ ,
์—†๋‹ค๋ฉด ๋นˆ ๋ฐฐ์—ด์„ ๋„ฃ๊ฒŒ ํ•˜์—ฌ Null์ด ๋‹ด๊ธฐ์ง€ ์•Š๊ฒŒ ์กฐ์น˜ํ•ด ์ฃผ์—ˆ์–ด์š”.



src/app/people/repository/people-query-builder.repository.ts


TypeORM QueryBuilder๋ฅผ ์ด์šฉํ•˜์—ฌ findAllByTeamId()๋ฅผ ๋งŒ๋“ค์—ˆ๋Š”๋ฐ, teamId๋ฅผ ์กฐํšŒํ•œ ๋’ค ๋‚˜์˜ค๋Š” ๋ชจ๋“  ๊ฐ’์„ PeopleEntity[]์— ๋‹ด์•„ ๋ฐ˜ํ™˜ํ•ด ์ฃผ์—ˆ์–ด์š”.

์—ฌ๊ธฐ์„œ Team Table๊ณผ Join์„ ๋งบ๊ธฐ์œ„ํ•ด 69๋ฒˆ์งธ ์ค„๊ณผ ๊ฐ™์ด Left Join์ด ๋งบ์–ด์ง€๊ฒŒ ํ•ด์„œ ๊ฐ’์„ ๊ฐ€์ ธ์˜ค๋„๋ก ์ฒ˜๋ฆฌํ•ด ์ฃผ์—ˆ์–ด์š”.

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด TeamId๋ฅผ ์ด์šฉํ•˜์—ฌ ํ•ด๋‹น Router๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ, Team ์ •๋ณด์™€ People ์ •๋ณด๊ฐ€ ํ•จ๊ป˜ ๋‹ด๊ธด DTO๋ฅผ ๋ฐ˜ํ™˜ํ•  ๊ฑฐ์—์š”.


src/graphql/schema/schema.graphqls


๊ทธ๋ฆฌ๊ณ  ์œ„ 38๋ฒˆ์งธ ์ค„๊ณผ ๊ฐ™์ด Query Schema(์ฟผ๋ฆฌ ์Šคํ‚ค๋งˆ)๋ฅผ ๊ตฌ์„ฑํ•ด ์ฃผ์—ˆ์–ด์š”.


src/graphql/schema/team/team.graphqls


๋ฐ˜ํ™˜๋˜๋Š” Type์€ ์œ„์™€ ๊ฐ™์ด ๊ตฌ์„ฑํ•ด ์ฃผ์—ˆ์–ด์š”.

src/graphql/schema/team/team.graphqls


data ํ•„๋“œ๋Š” ์œ„ DTO๋กœ ์ •์˜๋œ Type ํ˜•์‹์œผ๋กœ ๋ฐ˜ํ™˜๋˜๊ฒŒ ํ•ด ์ฃผ์—ˆ์–ด์š”.
์—ฌ๊ธฐ์„œ ์ฃผ๋ชฉํ•ด์•ผ ํ•  ์ ์€ 50๋ฒˆ์งธ ์ค„์ด์—์š”. 50๋ฒˆ์งธ ์ค„์— ํ•„๋“œ ์ด๋ฆ„(members)์™€

src/app/team/model/dto/response/team-and-member-response.dto.ts


๋ฐ˜ํ™˜๋˜๋Š” DTO์˜ ๋ณ€์ˆ˜๋ช…์ด ์ผ์น˜ํ•ด์•ผ ๋˜๊ธฐ ๋•Œ๋ฌธ์ด์—์š”.
๋งŒ์•ฝ ๋‹ค๋ฅด๋ฉด Null์ด ๋‹ด๊ฒจ ๋‚˜์˜ฌ๊ฑฐ์—์š”.

 

 

http://localhost:8081/graphql

query getTeamAndPeopleByTeamId {
  getTeamByTeamId(teamId: 1) {
    statusCode,
    message,
    data {
      teamId,
      manager,
      office,
      extensionNumber,
      mascot,
      cleaningDuty,
      project,

      members {
        peopleId,
        teamId,
        firstName,
        lastName,
        sex,
        bloodType,
        serveYears,
        role,
        hometown
      }
    }
  }
}


์ด๋ ‡๊ฒŒ ์ฟผ๋ฆฌ๋ฅผ ๋‚ ๋ฆฌ๋ฉด teamId๋ฅผ ์ „๋‹ฌํ•˜์—ฌ Team ์ •๋ณด์™€ ํ•ด๋‹น Team์— ์†Œ์†๋œ ์‚ฌ๋žŒ๋“ค ์ •๋ณด๋ฅผ ๋ฐ›์•„์˜ค๋Š” ๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด์š”.

๊ทธ๋ฆฌ๊ณ  ์œ„ ๋‚ด์šฉ์„ REST API๋กœ๋„ ๊ตฌ์„ฑํ•ด ๋ณด๋ ค๊ณ  ํ•ด์š”.

๊ทธ ์ „์— ๋ณด๋‹ค ํŽธ๋ฆฌํ•˜๊ฒŒ API Docs๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” Swagger๋ฅผ ๋จผ์ € ๊ตฌ์„ฑํ•ด ๋ณผ๊ฒŒ์š”.

Nest.js์—์„œ Swagger ์„ค์น˜ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์ƒ์„ธ ๋‚ด์šฉ์€ ์ด ๊ณณ์— ์ž‘์„ฑํ•ด ๋‘์—ˆ์–ด์š”.
๋งŽ์€ ๊ด€์‹ฌ ๋ถ€ํƒ๋“œ๋ ค์š”.

 

[BackEnd][Node.js][nest.js-PJ] ์‚ฌ๋‚ด ๊ฐœ๋ฐœ์ž ์ปค๋ฎค๋‹ˆํ‹ฐ ์„œ๋น„์Šค - ์ดˆ๊ธฐ ๊ตฌ์„ฑ(Pipe, TypeORM, Configuration, Swagger, Lo

Project Git Hub ๐Ÿ—‚ ๋ชฉ์ฐจ โ— [BackEnd][Node.js][nest.js-PJ] ์‚ฌ๋‚ด ๊ฐœ๋ฐœ์ž ์ปค๋ฎค๋‹ˆํ‹ฐ ์„œ๋น„์Šค - ์ดˆ๊ธฐ ๊ตฌ์„ฑ(Pipe, TypeORM, Configuration, Swagger, Logger) โ— [BackEnd][Node.js][Nest.js] ์‚ฌ๋‚ด ๊ฐœ๋ฐœ์ž ์ปค๋ฎค๋‹ˆํ‹ฐ ์„œ๋น„์Šค - ํšŒ์› ๊ฐ€์ž…

junyharang.tistory.com

 

npm install @nestjs/swagger swagger-ui-express --save

 

swagger.config.ts



src/main.ts


Swagger Config๋ฅผ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•ด 13๋ฒˆ์งธ ์ค„๊ณผ ๊ฐ™์ด ์„ค์ •ํ•ด ์ค๋‹ˆ๋‹ค.



http://localhost:8081/swagger-ui/index.html


๋งŒ์•ฝ ์œ„์™€ ๊ฐ™์ด No operations ... ๋ผ๊ณ  ๋‚˜์˜ค๋ฉด Module์— ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์ œ๋Œ€๋กœ ๋“ฑ๋ก๋˜์ง€ ์•Š์•˜์„ ์ˆ˜ ์žˆ์–ด์š”.




src/app/team/controller/team-rest-api.controller.ts

 

src/app/team/module/team.module.ts


์—ฌ๊ธฐ์„œ ํ•œ๊ฐ€์ง€ ์ฃผ๋ชฉํ•ด์•ผ๋  ์ ์€ GraphQL์˜ ๋ฆฌ์กธ๋ฒ„๋Š” Providers์— ๋„ฃ์–ด์ฃผ์ง€๋งŒ,
REST API์˜ Controller(์ปจํŠธ๋กค๋Ÿฌ)๋Š” controllers์— ๊ผญ ๋„ฃ์–ด์ฃผ์–ด์•ผ ํ•ด์š”.


src/app.module.ts



์œ„์™€ ๊ฐ™์ด ์ปจํŠธ๋กค๋Ÿฌ Code๋ฅผ ์ƒ์„ฑํ•ด ์ฃผ์—ˆ์–ด์š”.


http://localhost:8080/swagger-ui/index.html


์ด๋ ‡๊ฒŒ Swagger๊ฐ€ ๋‚˜์˜จ๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด์š”.



http://localhost:8081/swagger-ui/index.html#/TEAM%20%EA%B4%80%EB%A0%A8%20API/TeamRestApiController_getTeamByTeamId



http://localhost:8081/swagger-ui/index.html#/TEAM%20%EA%B4%80%EB%A0%A8%20API/TeamRestApiController_getTeamByTeamId

 

{
  "statusCode": 200,
  "message": "Success",
  "data": {
    "teamId": 1,
    "manager": "Mandy Warren",
    "office": "101A",
    "extensionNumber": "#5709",
    "mascot": "Panda",
    "cleaningDuty": "Monday",
    "project": "Hyperion",
    "members": [
      {
        "peopleId": 3,
        "teamId": 1,
        "lastName": "Nathan",
        "firstName": "Jenkins",
        "sex": "male",
        "bloodType": "B",
        "serveYears": 1,
        "role": "planner",
        "hometown": "Texas"
      },
      {
        "peopleId": 8,
        "teamId": 1,
        "lastName": "Isabella",
        "firstName": "Martin",
        "sex": "female",
        "bloodType": "A",
        "serveYears": 3,
        "role": "developer",
        "hometown": "Georgia"
      },
      {
        "peopleId": 12,
        "teamId": 1,
        "lastName": "Kate",
        "firstName": "Owen",
        "sex": "female",
        "bloodType": "B",
        "serveYears": 2,
        "role": "developer",
        "hometown": "Maine"
      },
      {
        "peopleId": 16,
        "teamId": 1,
        "lastName": "Byron",
        "firstName": "Barnes",
        "sex": "male",
        "bloodType": "A",
        "serveYears": 3,
        "role": "designer",
        "hometown": "Idaho"
      },
      {
        "peopleId": 27,
        "teamId": 1,
        "lastName": "Brian",
        "firstName": "Hunt",
        "sex": "male",
        "bloodType": "B",
        "serveYears": 2,
        "role": "planner",
        "hometown": "Indiana"
      },
      {
        "peopleId": 29,
        "teamId": 1,
        "lastName": "Violet",
        "firstName": "Pearson",
        "sex": "female",
        "bloodType": "AB",
        "serveYears": 5,
        "role": "designer",
        "hometown": "Pennsylvania"
      },
      {
        "peopleId": 35,
        "teamId": 1,
        "lastName": "Sally",
        "firstName": "Fox",
        "sex": "female",
        "bloodType": "AB",
        "serveYears": 5,
        "role": "planner",
        "hometown": "Messachusetts"
      },
      {
        "peopleId": 42,
        "teamId": 1,
        "lastName": "Russ",
        "firstName": "Lawrence",
        "sex": "male",
        "bloodType": "O",
        "serveYears": 5,
        "role": "designer",
        "hometown": "New York"
      },
      {
        "peopleId": 47,
        "teamId": 1,
        "lastName": "Leroy",
        "firstName": "Elliott",
        "sex": "male",
        "bloodType": "AB",
        "serveYears": 2,
        "role": "developer",
        "hometown": "Indiana"
      },
      {
        "peopleId": 50,
        "teamId": 1,
        "lastName": "Ned",
        "firstName": "Butler",
        "sex": "male",
        "bloodType": "O",
        "serveYears": 2,
        "role": "planner",
        "hometown": "Messachusetts"
      }
    ]
  }
}


์œ„์™€ ๊ฐ™์ด REST API๋ฅผ ์ด์šฉํ•ด์„œ ์กฐํšŒ๋ฅผ ํ•ด๋„ ๋ฐ˜ํ™˜ ๋ฐ›๋Š” ๊ฐ’์€ GraphQL๊ณผ ๋™์ผํ•œ ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์–ด์š”.


 

 

 

        ๐Ÿ“ฆ Float, Boolean Type ๊ฐ€์ง€๊ณ  ๋†€๊ธฐ

์ด๋ฒˆ์—๋Š” ์ผ๊ณฑ๋ฒˆ์งธ ์ด์•ผ๊ธฐ์—์„œ EquipmentsAdv๋ฅผ ๋งŒ๋“ค์–ด Float์™€ Boolean ์ž๋ฃŒํ˜•์„ ๊ตฌ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์‹ค์Šตํ•ด ๋ณด๋ ค๊ณ  ํ•ด์š”.

 

GraphQL๊ณผ Apollo ์ผ๊ณฑ๋ฒˆ์งธ ์ด์•ผ๊ธฐ - GraphQL Data Type์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์•„์š” ๐Ÿ˜€

GraphQL๊ณผ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋กœ ๊ฐœ๋ฐœํ•˜๋Š” ์›น ์„œ๋น„์Šค:์„ค๊ณ„๋ถ€ํ„ฐ ๊ฐœ๋ฐœ·๋ฐฐํฌ๊นŒ์ง€ ๋”ฐ๋ผ ํ•˜๋ฉฐ ์™„์„ฑํ•˜๋Š” ์›น ํ’€ COUPANG www.coupang.com "์ด ํฌ์ŠคํŒ…์€ ์ฟ ํŒก ํŒŒํŠธ๋„ˆ์Šค ํ™œ๋™์˜ ์ผํ™˜์œผ๋กœ, ์ด์— ๋”ฐ๋ฅธ ์ผ์ •์•ก์˜ ์ˆ˜์ˆ˜๋ฃŒ๋ฅผ

junyharang.tistory.com

 

src/graphql/schema/equipment/equipment.graphqls




src/graphql/schema/equipment/equipment.graphqls




src/graphql/schema/schema.graphqls


์œ„์™€ ๊ฐ™์ด 9 ~ 14๋ฒˆ์งธ ์ค„์— ์ฟผ๋ฆฌ ํ•จ์ˆ˜๋ฅผ ์„ ์–ธํ•ด ์ฃผ์—ˆ์–ด์š”.


src/app/equipment/resolver/equipment.resolver.ts


๋ฆฌ์กธ๋ฒ„ ์ฝ”๋“œ๋Š” ์œ„์™€ ๊ฐ™์ด ๋งŒ๋“ค์–ด ์ฃผ์—ˆ์–ด์š”.


src/app/equipment/service/equipment-Impl.service.ts

๋ฐ˜์‘ํ˜•


์œ„์™€ ๊ฐ™์ด ์ด๋ฏธ ๋งŒ๋“ค์–ด์ ธ ์žˆ๋˜ QueryBuilder์˜ ๊ฒ€์‚ฌ์™€ ํŽ˜์ด์ง• ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•œ Method๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ฒ˜๋ฆฌํ•ด ์ฃผ์—ˆ์–ด์š”.

์ด์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ ์ด ์ „ ๊ธ€์„ ์ฐธ๊ณ ํ•ด ์ฃผ์„ธ์š”.

 

GraphQL๊ณผ Apollo ์—ด๋‘๋ฒˆ์งธ ์ด์•ผ๊ธฐ - TypeScript + Nest.js์—์„œ GraphQL ์‚ฌ์šฉํ•ด ๋ณด๊ธฐ - ์‹ค์Šต ํ™˜๊ฒฝ ๊ตฌ์„ฑ

NestJS๋กœ ๋ฐฐ์šฐ๋Š” ๋ฐฑ์—”๋“œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ:ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ํ™˜๊ฒฝ์˜ ์ฐจ์„ธ๋Œ€ ์„œ๋ฒ„ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ๋งŒ๋‚˜๋‹ค COUPANG www.coupang.com "์ด ํฌ์ŠคํŒ…์€ ์ฟ ํŒก ํŒŒํŠธ๋„ˆ์Šค ํ™œ๋™์˜ ์ผํ™˜์œผ๋กœ, ์ด์— ๋”ฐ๋ฅธ ์ผ์ •์•ก์˜ ์ˆ˜์ˆ˜๋ฃŒ๋ฅผ ์ œ๊ณต๋ฐ›

junyharang.tistory.com

 

 

equipments.js

 

ํ•ด๋‹น ์‹ค์Šต์„ ์œ„ํ•ด ์ผ๊ณฑ๋ฒˆ์งธ ์ด์•ผ๊ธฐ์—์„œ๋Š” ์œ„์™€ ๊ฐ™์ด resolver๋ฅผ ์ž‘์„ฑํ•ด ์ฃผ์—ˆ์—ˆ์–ด์š”.
์ด๋ฅผ Type Script์™€ Nest.js์— ๋งž๊ฒŒ ๋ณ€ํ™˜ํ•ด ๋ณผ๊ฒŒ์š”.


src/app/equipment/model/dto/response/equipment-adv.response.dto.ts


์ด ๋‚ด์šฉ์€ ์œ„์™€ ๊ฐ™์ด DTO ์ƒ์„ฑ์ž์—์„œ ์ฒ˜๋ฆฌํ•ด ์ฃผ์—ˆ์–ด์š”.

17๋ฒˆ์งธ ์ค„์— Equipment ๋ณ€์ˆ˜์— ๋‹ด๊ธด usedBy ๊ฐ’์ด developer๋ผ๋Š” ๋ฌธ์ž์—ด์ธ์ง€๋ฅผ ํ™•์ธํ•˜๊ณ , ๋งž๋‹ค๋ฉด ๋žœ๋ค ์ˆซ์ž(์†Œ์ˆ˜์  2๋ฒˆ์งธ ์ž๋ฆฌ๊นŒ์ง€)๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๋‹ด๊ธธ ์ˆ˜ ์žˆ๋„๋ก ์ฒ˜๋ฆฌํ•ด ์ฃผ์—ˆ์–ด์š”.

๊ทธ๋ฆฌ๊ณ , 21๋ฒˆ์งธ ์ค„์€ Equipment ๋ณ€์ˆ˜์— ๋‹ด๊ธด newOrUsed new๋ผ๋Š” ๋ฌธ์ž์—ด์ธ์ง€ ํ™•์ธํ•˜๊ณ , ๋งž๋‹ค๋ฉด True๋ฅผ ์•„๋‹ˆ๋ผ๋ฉด False๊ฐ€ ๋“ค์–ด๊ฐ€๊ฒŒ ํ•ด ์ฃผ์—ˆ์–ด์š”.

http://localhost:8081/graphql


์ด๋ ‡๊ฒŒํ•ด์„œ ์ฟผ๋ฆฌ๋ฅผ ๋‚ ๋ ค๋ณด๋ฉด ์ •์ƒ์ ์œผ๋กœ Float์™€ Blooen์ด ์ƒ๊ธด ๊ฐ์ฒด๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ์–ด์š”.


 

 

        ๐Ÿ“ฆ Enum Type

์ด๋ฒˆ์—๋Š” ์ผ๊ณฑ๋ฒˆ์งธ ์ด์•ผ๊ธฐ์—์„œ ๊ณต๋ถ€ํ•ด๋ดค๋˜ Enum Type์— ๋Œ€ํ•ด ์‹ค์Šตํ•ด ๋ณผ๊ฒŒ์š”.

src/graphql/schema/common/enums.graphqls


์œ„์™€ ๊ฐ™์ด Enum Type๋งŒ ๋‹ด์„ ์ˆ˜ ์žˆ๋Š” enums.graphqls๋ฅผ ๋งŒ๋“ค์–ด ์ฃผ๊ณ , ๊ทธ ์•ˆ์— Enum Type๋“ค์„ ์ •์˜ํ•ด ์ฃผ์—ˆ์–ด์š”.



src/graphql/schema/people/people.graphqls


๊ทธ๋ฆฌ๊ณ  ์œ„์™€ ๊ฐ™์ด ResponseDto Type์— ์ž๋ฃŒํ˜• ํƒ€์ž…์„ ๊ฐ๊ฐ Enum Type์œผ๋กœ ์ง€์ •ํ•ด ์ฃผ์—ˆ์–ด์š”.

์ผ๊ณฑ๋ฒˆ์งธ ์ด์•ผ๊ธฐ์—์„œ๋Š” ๋ฐฐ์—ด Type๊ณผ Objet Type์— ๋Œ€ํ•ด์„œ ๊ณต๋ถ€ํ•˜๊ณ , ์‹ค์Šตํ•ด ๋ณด์•˜๋Š”๋ฐ,
์ด๋ฏธ Dto ๊ฐ์ฒด๋กœ ๋ฐ˜ํ™˜๋ฐ›๋Š” ๋ฐฉ๋ฒ•๊ณผ ๋ฐฐ์—ด Type์œผ๋กœ ๋ฐ›๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐ ํ•ด ๋ณด์•˜๊ธฐ ๋•Œ๋ฌธ์— ๋”ฐ๋กœ ์‹ค์Šตํ•˜์ง„ ์•Š์„๊ฒŒ์š”.

 

 

 

    ๐Ÿ“ฆ Interface

์ด๋ฒˆ์—๋Š” ์—ฌ๋Ÿ๋ฒˆ์งธ ์ด์•ผ๊ธฐ์—์„œ ๊ณต๋ถ€ํ•ด ๋ณด์•˜๋˜ Interface(์ธํ„ฐํŽ˜์ด์Šค)์— ๋Œ€ํ•ด ์‹ค์Šตํ•ด ๋ณด๋„๋ก ํ• ๊ฒŒ์š”.

 

GraphQL๊ณผ Apollo ์—ฌ๋Ÿ๋ฒˆ์งธ ์ด์•ผ๊ธฐ - GraphQL Union๊ณผ Interface ๊ทธ๋ฆฌ๊ณ  ์ธ์ž์™€ ์ธํ’‹ ํƒ€์ž…์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์•„

GraphQL๊ณผ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋กœ ๊ฐœ๋ฐœํ•˜๋Š” ์›น ์„œ๋น„์Šค:์„ค๊ณ„๋ถ€ํ„ฐ ๊ฐœ๋ฐœ·๋ฐฐํฌ๊นŒ์ง€ ๋”ฐ๋ผ ํ•˜๋ฉฐ ์™„์„ฑํ•˜๋Š” ์›น ํ’€ COUPANG www.coupang.com "์ด ํฌ์ŠคํŒ…์€ ์ฟ ํŒก ํŒŒํŠธ๋„ˆ์Šค ํ™œ๋™์˜ ์ผํ™˜์œผ๋กœ, ์ด์— ๋”ฐ๋ฅธ ์ผ์ •์•ก์˜ ์ˆ˜์ˆ˜๋ฃŒ๋ฅผ

junyharang.tistory.com

 

์‹ค์Šตํ•˜๊ธฐ ์ „์— ์—ฌ๋Ÿ๋ฒˆ์งธ ์ด์•ผ๊ธฐ์—์„  Union์— ๋Œ€ํ•ด์„œ๋„ ์ด์•ผ๊ธฐ๋ฅผ ํ•ด ๋ณด์•˜์–ด์š”.
ํ•˜์ง€๋งŒ, ์ฃผ๋‹ˆ๊ฐ€ ๋Š๊ผˆ์„ ๋•Œ, Union์ด๋ผ๋Š” ๊ฑธ ์‹ค์ œ ์„œ๋น„์Šค์—์„œ ์–ผ๋งˆ๋‚˜ ๋งŽ์ด ์“ธ๊นŒ?๊ฐ€ ์˜๋ฌธ์ด ๋“ค์—ˆ์–ด์š”.

ํ•˜๋‚˜์˜ List์— ๊ฐ๊ธฐ ๋‹ค๋ฅธ N๊ฐœ์˜ ๊ฐ์ฒด๋ฅผ ๋‹ด์•„์„œ ๋ณด๋‚ด๋Š” ๊ฒƒ์€ ์ด๋ฏธ ์œ„์—์„œ ํ•ด ๋ณด์•˜๊ณ , ์–ด๋–ค ์กฐ๊ฑด์ด ์ฃผ์–ด์กŒ์„ ๋•Œ, ๊ทธ ์กฐ๊ฑด์ด ๋งž์œผ๋ฉด A ๊ฐ์ฒด๋ฅผ ์•„๋‹ˆ๋ฉด B ๊ฐ์ฒด๋ฅผ ์ฃผ๋Š” ๋“ฑ์˜ ์‚ฌ์šฉ์„ ํ•˜๋Š”๋ฐ, ์•„์ง๊นŒ์ง€๋Š” ์‹ค์ œ ํ•„์š”ํ•˜๋‹ค๊ณ  ๋Š๋ผ์ง€ ๋ชปํ•ด์„œ ์ผ๋‹จ! ์‹ค์Šต์€ ํ•˜์ง€ ์•Š๋„๋ก ํ• ๊ฑฐ์—์š”.

 

src/graphql/schema/equipment/equipment.graphqls



src/graphql/schema/software/software.graphqls

 

์—ฌ๋Ÿ๋ฒˆ์งธ ์ด์•ผ๊ธฐ์—์„œ ์ด์•ผ๊ธฐํ–ˆ๋˜ ๋Œ€๋กœ ์œ„ ๋‘ Type์€ ๊ฐ์ฒด ์ด๋ฆ„ ์ค‘ usedBy๊ฐ€ ๊ฒน์น˜๋Š” ๊ฑธ ์•Œ ์ˆ˜ ์žˆ์–ด์š”.
์ฐธ๊ณ ๋กœ ์—ฌ๋Ÿ๋ฒˆ์งธ ์ด์•ผ๊ธฐ์—์„œ๋Š” ID ๊ฐ์ฒด ์ด๋ฆ„์ด ๋ชจ๋‘ id ์˜€๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ๋„ ๊ฒน์ณค์ง€๋งŒ, ์ฃผ๋‹ˆ๋Š” ์œ ๋‹ˆํฌํ•œ ID ์ด๋ฆ„์„ ๋ถ€์—ฌํ•˜๊ธฐ ์œ„ํ•ด ์œ„์™€ ๊ฐ™์ด ์ด๋ฆ„์„ ์ •ํ•ด์ฃผ์–ด์„œ ๊ฒน์น˜์ง€ ์•Š๋Š”๊ฑธ ์•Œ ์ˆ˜ ์žˆ์–ด์š”.


์ด ๋ถ€๋ถ„๋งŒ Interface๋กœ ๋”ฐ๋กœ ๋นผ ๋ณผ๊ฒŒ์š”.


src/graphql/schema/common/interface/interface.graphqls



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

 

src/graphql/schema/equipment/equipment.graphqls

 

 

src/graphql/schema/software/software.graphqls


๊ทธ๋ฆฌ๊ณ  ์œ„์™€ ๊ฐ™์ด ๊ฐ๊ฐ์˜ Type ๋“ค์ด Tool Interface(์ธํ„ฐํŽ˜์ด์Šค)๋ฅผ ๊ตฌํ˜„๋  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ์—ˆ์–ด์š”.


http://localhost:8081/graphql

 

query findeBygetEquipmentAndSoftwareListPagingUseByInterface {
  getEquipmentList(
    pageNumber: 1,
    perPageSize: 10
  ) {
    statusCode,
    message,
    pagination {
      perPageSize,
      totalCount,
      totalPage
      data {
        equipmentId,
        usedBy,
        count,
        newOrUsed
      }
    }
  }

  getSoftwareList(
    usedBy: "developer",
    developedBy: "Eclipse Foundation",
    description: "integrated development environment",
    pageNumber: 1,
    perPageSize: 5,
    orderBy: true
  ) {
    statusCode,
    message,
    pagination {
      perPageSize,
      totalCount,
      totalPage,
      data {
        softwareId,
        usedBy,
        developedBy,
        description
      }
    }
  }
}



์œ„์™€ ๊ฐ™์ด ๊ฒฐ๊ณผ๊ฐ’์„ ๋ฐ›๋Š”๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ๊ณ , Equipmensts์™€ Softwares ๋ฐฐ์—ด ๊ฐ์ฒด๊ฐ€ ๋ฐ˜ํ™˜๋œ๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด์š”.

์ด๋ ‡๊ฒŒ ํ•ด์„œ ์ฃผ์š” ์‹ค์Šต์„ ๋ชจ๋‘ ๋งˆ์ณค์–ด์š”.

 

 

 

 

 

    ๐Ÿ”ฝ  ์‹ค์Šต ๋งˆ๋ฌด๋ฆฌ

        ๐Ÿ“ฆ ์งง์€ ํšŒ๊ณ 

Nest.ts ๋งŒ์˜ ํŠน์ง•์„ ์ตํžˆ๊ณ , TypeORM Version Up์œผ๋กœ ์ธํ•œ ๋ณ€๋™ ์‚ฌํ•ญ์œผ๋กœ ๊ฝค ๋งŽ์ด ๊ณ ์ƒ์„ ํ–ˆ์–ด์š”.
์ด๋ ‡๊ฒŒ ์‹ค์Šต์„ ๋งˆ๋ฌด๋ฆฌํ•˜๋‹ˆ Nest.ts ์‚ฌ์šฉ๋ฒ•๋„ ๋‹ค์‹œ ํ•œ๋ฒˆ ์ตํž ์ˆ˜ ์žˆ์—ˆ๊ณ , ๋ณด๋‹ค GraphQL์— ๋Œ€ํ•ด ์ดํ•ดํ•˜๊ฒŒ ๋œ ๊ฑฐ ๊ฐ™์•„ ๋„ˆ๋ฌด ๊ธฐ๋ถ„ ์ข‹์•„์š”.

์ด์ œ REST API๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ณ , GraphQL๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์žํ”„๋ง๊ณผ Nest.ts๋ฅผ ๊ฐ€์ง€๊ณ ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ์–ด์š”.

์žํ”„๋ง ํšŒ๊ณ ๋ก์—๋„ ์ผ์ง€๋งŒ, ์•„์ง๊นŒ์ง€ ํŽธ๋ฆฌํ•˜๊ณ , ์ข‹๋‹ค๋ผ๋Š” ๋Š๋‚Œ์€ ํฌ๊ฒŒ ๋ชป ๋ฐ›์•˜์–ด์š”.
ํ† ์ด ํ”„๋กœ์ ํŠธ ๋“ฑ์—์„œ ๊ณ„์† ์จ ๊ฐ€๋ฉด์„œ REST API์™€ ๊ณ„์† ๋น„๊ตํ•˜๋ฉด์„œ ์ฝ”๋”ฉํ•ด ๋ณด๋ฉด ์ข‹๊ฒ ๋‹ค๋ผ๋Š” ์ƒ๊ฐ์ด์—์š”.

ํ•˜์ง€๋งŒ, ํ•œ๊ฐ€์ง€ ๋ถ„๋ช…ํ•œ ๊ฑด GraphQL์„ ์ผ์„ ๋•Œ, URI ์ด๋ฆ„ ์ง“๋Š” ๊ฒƒ์— ๋Œ€ํ•œ ์–ด๋ ค์›€์€ ์‚ฌ๋ผ์ง„๋‹ค๋Š” ๊ฒƒ์ด์—์š”.

GitHub์— ์‹ค์Šต์—์„œ ์‚ฌ์šฉํ•œ ์ฝ”๋“œ๋ฅผ ๊ทธ๋Œ€๋กœ ์˜ฌ๋ ค ๋‘์—ˆ์–ด์š”!

Lisense.md์™€ README.md๋ฅผ ๊ผญ ์ฝ์–ด๋ด ์ฃผ์‹œ๊ณ , ํ•„์š”ํ•˜์‹œ๋ฉด ์‚ฌ์šฉํ•ด ์ฃผ์‹œ๋ฉด ์ข‹๊ฒ ์–ด์š”!

์•„์ฐธ! GitHub์— โญ๏ธ ์ด๊ฑฐ ๋ˆŒ๋Ÿฌ์ฃผ์‹œ๋ฉด ์ •๋ง ๊ณ ๋ง™๊ฒ ์Šต๋‹ˆ๋‹ค ๐Ÿ˜€



 

 

 

GraphQL๊ณผ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋กœ ๊ฐœ๋ฐœํ•˜๋Š” ์›น ์„œ๋น„์Šค:์„ค๊ณ„๋ถ€ํ„ฐ ๊ฐœ๋ฐœ·๋ฐฐํฌ๊นŒ์ง€ ๋”ฐ๋ผ ํ•˜๋ฉฐ ์™„์„ฑํ•˜๋Š” ์›น ํ’€

COUPANG

www.coupang.com

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

 

 

 

 

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
๋ฐ˜์‘ํ˜•