GraphQL과 Apollo 열 일곱번째 이야기 - Kotlin + Spring Boot에서 GraphQL 사용해 보기 - 실습 해보기

2023. 12. 21. 15:53개념 정리 작업실/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), Nest.ts에서도 그랬듯 지난 글까지 코프링(Kotlin + Spring Boot)를 이용하여 GraphQL 환경 구성을 위한 작업을 진행해 보았어요.

Nest.ts 글과 마찬가지로 실습을 진행해 보도록 할게요.

 

 

 

 

 

        📦 Overfetching

Overfetching 문제에 대한 이야기는 자프링 실습 때 보다 자세히 이야기 해 보았어요.

코프링의 경우 이를 모두 해결해서 구성을 하였기 때문에 자프링 내용을 참고해 주시면 좋을 거 같아요.

 

GraphQL과 Apollo 열번째 이야기 - Java + Spring Boot에서 GraphQL 사용해 보기 - 실습 해보기

자바 ORM 표준 JPA 프로그래밍:스프링 데이터 예제 프로젝트로 배우는 전자정부 표준 데이터베이 COUPANG www.coupang.com "이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제

junyharang.tistory.com

 

 

 

 

 

 

        📦 Underfetching

이번엔 Underfetching에 대해 실습하면서 분석해 보려고 해요.

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

728x90
query getEquipmentsAndSupplies {
  getEquipmentList(
    pageRequestDto: {
      currentPage: 1,
      perPageSize: 10
      orderBy: true
    },
  ){
    statusCode,
    message,
    data {
      equipmentId,
      usedBy,
      count,
      newOrUsed
    },
    pagination {
      perPageSize,
      totalElementCount,
      totalPage
    }
  }

  getSupplyList(
  # teamId: 2,
  pageRequestDto: {
    currentPage: 1,
    perPageSize: 10,
    orderBy: true
  }) {
    statusCode,
    message,
    data {
      supplyId,
      teamId
    },
    pagination {
      perPageSize,
      totalElementCount,
      totalPage,
      orderBy
    }
  }
}
{
  "data": {
    "getEquipmentList": {
      "statusCode": 200,
      "message": "OK",
      "data": [
        {
          "equipmentId": "whiteboard",
          "usedBy": "planner",
          "count": 12,
          "newOrUsed": "used"
        },
        {
          "equipmentId": "sketchb",
          "usedBy": "designer",
          "count": 48,
          "newOrUsed": "new"
        },
        {
          "equipmentId": "pen tablet",
          "usedBy": "developer",
          "count": 15,
          "newOrUsed": "used"
        },
        {
          "equipmentId": "notebook",
          "usedBy": "planner",
          "count": 37,
          "newOrUsed": "new"
        },
        {
          "equipmentId": "machanical keyboard",
          "usedBy": "developer",
          "count": 24,
          "newOrUsed": "used"
        },
        {
          "equipmentId": "ergonomic mouse",
          "usedBy": "designer",
          "count": 31,
          "newOrUsed": "used"
        },
        {
          "equipmentId": "dual monitor",
          "usedBy": "developer",
          "count": 20,
          "newOrUsed": "used"
        }
      ],
      "pagination": {
        "perPageSize": 7,
        "totalElementCount": 7,
        "totalPage": 1
      }
    },
    "getSupplyList": {
      "statusCode": 200,
      "message": "OK",
      "data": [
        {
          "supplyId": "webcam",
          "teamId": "2"
        },
        {
          "supplyId": "usb hub",
          "teamId": "3"
        },
        {
          "supplyId": "t shirt",
          "teamId": "5"
        },
        {
          "supplyId": "stempler",
          "teamId": "4"
        },
        {
          "supplyId": "mug",
          "teamId": "1"
        },
        {
          "supplyId": "hoodie",
          "teamId": "2"
        },
        {
          "supplyId": "headphone",
          "teamId": "4"
        },
        {
          "supplyId": "ergonomic mouse",
          "teamId": "1"
        },
        {
          "supplyId": "chair",
          "teamId": "3"
        },
        {
          "supplyId": "calculator",
          "teamId": "5"
        }
      ],
      "pagination": {
        "perPageSize": 10,
        "totalElementCount": 10,
        "totalPage": 1,
        "orderBy": true
      }
    }
  }
}

 

위 내용을 보면 하나의 쿼리를 보내 두 개의 각각 원하는 응답값을 받은 걸 확인할 수 있어요.


resources/graphql/graphql/query.graphqls

 

resources/graphql/graphql/query.graphqls

 

이렇게 두 개의 스키마에 대해 조회를 날리면 하나의 요청으로 두 개의 값을 얻을 수 있는 걸 확인할 수 있어요.
Join 이나, 다른 걸 하지 않고도 이렇게 얻을 수 있는 것이에요.

근데 위에서 Supply는 Http Status Code와 Message를 받고 싶지 않다면 어떻게 해야 할까요?

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

 

위와 같이 받고 싶지 않는 Field를 요청에 보내지 않으면 해당 내용은 응답하지 않는걸 볼 수 있어요.
이렇게 Overfetching 문제에 대해 자유롭게 원하는 값만 받을 수 있어요.

 

{
  "data": {
    "getEquipmentList": {
      "statusCode": 200,
      "message": "OK",
      "data": [
        {
          "equipmentId": "whiteboard",
          "usedBy": "planner",
          "count": 12,
          "newOrUsed": "used"
        },
        {
          "equipmentId": "sketchb",
          "usedBy": "designer",
          "count": 48,
          "newOrUsed": "new"
        },
        {
          "equipmentId": "pen tablet",
          "usedBy": "developer",
          "count": 15,
          "newOrUsed": "used"
        },
        {
          "equipmentId": "notebook",
          "usedBy": "planner",
          "count": 37,
          "newOrUsed": "new"
        },
        {
          "equipmentId": "machanical keyboard",
          "usedBy": "developer",
          "count": 24,
          "newOrUsed": "used"
        },
        {
          "equipmentId": "ergonomic mouse",
          "usedBy": "designer",
          "count": 31,
          "newOrUsed": "used"
        },
        {
          "equipmentId": "dual monitor",
          "usedBy": "developer",
          "count": 20,
          "newOrUsed": "used"
        }
      ],
      "pagination": {
        "perPageSize": 7,
        "totalElementCount": 7,
        "totalPage": 1
      }
    },
    "getSupplyList": {
      "data": [
        {
          "supplyId": "webcam",
          "teamId": "2"
        },
        {
          "supplyId": "usb hub",
          "teamId": "3"
        },
        {
          "supplyId": "t shirt",
          "teamId": "5"
        },
        {
          "supplyId": "stempler",
          "teamId": "4"
        },
        {
          "supplyId": "mug",
          "teamId": "1"
        },
        {
          "supplyId": "hoodie",
          "teamId": "2"
        },
        {
          "supplyId": "headphone",
          "teamId": "4"
        },
        {
          "supplyId": "ergonomic mouse",
          "teamId": "1"
        },
        {
          "supplyId": "chair",
          "teamId": "3"
        },
        {
          "supplyId": "calculator",
          "teamId": "5"
        }
      ],
      "pagination": {
        "perPageSize": 10,
        "totalElementCount": 10,
        "totalPage": 1,
        "orderBy": true
      }
    }
  }
}

 

위의 실습을 통해 Underfetching 문제가 해결 되는 걸 알 수 있어요.

 

 

 

 

 

 

        📦 두 번의 데이터 베이스 조회 - REST API도 구성해 보기

비즈니스 로직에서 두 번의 데이터베이스 조회를 통해 한번에 값을 반환 받는 방법에 대해 이야기 해보려 해요.

주니는 teamId를 이용해서 Team과 People 정보를 가져올 수 있게 구성해 보려고 해요.

kotlin/com/junyharangstudy/kotlingraphqltest/api/team/resolver/TeamResolver.kt


위 Resolver(리졸버)는 
teamId를 받아 정보를 반환할 수 있는 Router에요.


kotlin/com/junyharangstudy/kotlingraphqltest/api/team/service/TeamService.kt


비즈니스 로직은 위와 같이 되어 있는데, 72번째 줄에서 JPA의 findById()를 통해 team 정보를 조회하도록하였어요.



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


그런 뒤 78번째 줄에 JPA findAllByTeamId()를 만든 메서드를 호출하여 teamId를 전달하고, 소속 사람들 정보를 모두 조회하여 List에 담아 반환하도록 하였어요.

이 때, map을 이용하여 반복문을 돌리면서 데이터베이스에서 조회된 People EntityPeopleResponseDto로 변환한 뒤 이를 다시 List 상수 변수 findAllMemberByTeamId로 받게 해 주었어요.

그런 뒤 정상 조회된 내용을 응답하기 위해 82번째 줄과 같이 해주고, 응답할 때, Team 정보는 아직 Entity이기 때문에 TeamAndMemberResponseDto에 만든 entityToDto()를 호출하여 TeamAndMemberResponseDto 형식으로 변환한 뒤 반환하게 해 주었어요.

kotlin/com/junyharangstudy/kotlingraphqltest/api/team/model/dto/response/TeamAndMemerResponseDto.kt


DTO는 위와 같이 구성 되어 있는데, 14번째 members Property(프로퍼티)는 한 개의 팀에 소속된 여러 사람을 받기 위해 members 변수를 List로 하여 PeopleResponseDto가 담길 수 있게 선언해 주었고, entityToDto()를 통해 값이 담길 때, 26번째 줄과 같이 프로퍼티에 담길 수 있도록 처리해 주었어요.

19번째 줄 !!가 왜 붙었는지 모르겠다면? 이 곳에 관심을 주시면 좋을 거 같아요.

 

GraphQL과 Apollo 열 여섯번째 이야기 - Kotlin + Spring Boot에서 GraphQL 사용해 보기 - 실습 환경 구성

카카오페이 | 마음 놓고 금융하다 여기를 눌러 링크를 확인하세요. qr.kakaopay.com 코틀린 완벽 가이드 COUPANG www.coupang.com "이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료

junyharang.tistory.com

 

resources/graphql/graphql/query.graphqls


그리고 위 48번째 줄과 같이 Query Schema(쿼리 스키마)를 구성해 주었어요.

resources/graphql/graphql/other/teamAndMember.graphqls


반환되는 Type은 위와 같이 구성해 주었어요.

data 필드는 위 DTO로 정의된 Type 형식으로 반환되게 해 주었어요.
여기서 주목해야 할 점은 16번째 줄이에요. 16번째 줄에 필드 이름(members)와 4번째 줄 반환되는 DTO의 변수명이 일치해야 되기 때문이에요. 만약 다르면 Null이 담겨 나올거에요.


query getTeamAndMemberByTeamId {
  getTeamAndMemberByTeamId(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를 먼저 구성해 볼게요.

build.gradle.kts

    //SpringDoc 의존성 추가
    // https://mvnrepository.com/artifact/org.springdoc/springdoc-openapi-ui
    implementation 'org.springdoc:springdoc-openapi-ui:1.6.14'


위와 같이 
Springdoc-openapi를 추가해 주었어요.


kotlin/com/junyharangstudy/kotlingraphqltest/common/config/SwaggerConfig.kt

 

resources/application.yml



위와 같이 Swagger Config 코드도 만들어 주었어요.


kotlin/com/junyharangstudy/kotlingraphqltest/api/team/resolver/TeamRestApiController.kt


위와 같이 Controller Code를 생성해 주었어요.

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


위와 같이 접속하려고 하면 Whitelabel Error를 만나게 될거에요.

그 이유는 Spring Boot 3부터 SpringDoc 구성 방법이 바뀌었기 때문이에요.



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


이렇게 Swagger가 나온걸 확인할 수 있어요.



http://localhost:8080/swagger-ui/index.html#/Team%20%EA%B4%80%EB%A0%A8%20API/getTeamAndMemberByTeamId




http://localhost:8080/swagger-ui/index.html#/Team%20%EA%B4%80%EB%A0%A8%20API/getTeamAndMemberByTeamId

 

{
  "statusCode": 200,
  "message": "OK",
  "pagination": null,
  "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": 9,
        "teamId": 1,
        "lastName": "Isabella",
        "firstName": "Martin",
        "sex": "female",
        "bloodType": "A",
        "serveYears": 3,
        "role": "developer",
        "hometown": "Georgia"
      },
      {
        "peopleId": 13,
        "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



resources/graphql/graphql/query.graphqls


7 ~ 12번째 줄과 같이 쿼리 함수를 선언해 주었어요.

resources/graphql/graphql/equipment/equipment.graphqls



위와 같이 EquipmentsAdvDto와 DefaultEquipmentsAdvResponse라는 Type을 명시해 주었어요.


kotlin/com/junyharangstudy/kotlingraphqltest/api/equipment/resolver/EquipmentResolver.kt


리졸버 코드는 위와 같이 만들어 주었어요.


kotlin/com/junyharangstudy/kotlingraphqltest/api/equipment/service/EquipmentService.kt



kotlin/com/junyharangstudy/kotlingraphqltest/api/equipment/service/EquipmentService.kt


비즈니스 로직은 위와 같이 만들어 주었는데, 검색을 할 것인지 Paging 처리를 할 것인지를 분기하여 상황에 맞는 메서드를 호출하여 처리될 수 있도록 해 주었어요.

해당 처리에 대한 상세 내용은 이 곳을 참고해 주시면 좋을 거 같아요.

 

GraphQL과 Apollo 열 여섯번째 이야기 - Kotlin + Spring Boot에서 GraphQL 사용해 보기 - 실습 환경 구성

카카오페이 | 마음 놓고 금융하다 여기를 눌러 링크를 확인하세요. qr.kakaopay.com 코틀린 완벽 가이드 COUPANG www.coupang.com "이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료

junyharang.tistory.com

반응형

kotlin/com/junyharangstudy/kotlingraphqltest/api/equipment/service/EquipmentService.kt


위 코드는 Client에서 검색 조건과 Paging 처리 조건을 보냈을 때, 호출되는 메서드에요.
QueryDSL을 통해 Paging 처리와 데이터베이스에서 검색이 처리되게 코드를 짜 보았어요.

QueryDSL을 이용하여 검색 키워드에 대한 검사와 페이징 처리 내용은 이 곳을 참고해 주세요.

 

GraphQL과 Apollo 열 여섯번째 이야기 - Kotlin + Spring Boot에서 GraphQL 사용해 보기 - 실습 환경 구성

카카오페이 | 마음 놓고 금융하다 여기를 눌러 링크를 확인하세요. qr.kakaopay.com 코틀린 완벽 가이드 COUPANG www.coupang.com "이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료

junyharang.tistory.com


185번째 줄에서 데이터베이스에서 조회된 결과가 비어있는지 확인하고, 비어있지 않다면 반복문을 돌리면서 Entity 하나의 객체를 map을 통해 EquipmentAdvResponsDto로 변환해 주는 작업을 해요.

그런 뒤 194번째 줄에 조회된 Entity 객체에 usedBy 값이 developer라면 랜덤 숫자(소수점 2번째 자리까지)를 생성하여 DTO 객체 useRate 프로퍼티에 값이 담길 수 있게 해 주었어요.


그런 뒤 198번째 줄에서 Entity 객체에 newOrUsed 값이 new 라면 DTO 객체 isNew 프로퍼티에 ture가 담길 수 있게 해주었어요.

아니라면? false가 담길 거에요.

그리고, 200번째 줄에서 이렇게 반복하여 처리된 내용을 새로운 List에 담길 수 있도록 처리해 준 거에요.

새롭게 만들어진 List가 비어있는지 확인하고, 비어 있지 않으면 List를 그대로 반환하고, 비어있다면 비어있는 List를 반환하도록 해 주었어요.

kotlin/com/junyharangstudy/kotlingraphqltest/api/equipment/service/EquipmentService.kt

 

kotlin/com/junyharangstudy/kotlingraphqltest/api/equipment/service/EquipmentService.kt


두 메서드도 동작하는 로직은 같아요.

 

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


이렇게해서 쿼리를 날려보면 정상적으로 Float와 Blooen이 생긴 객체를 받을 수 있답니다.

 

 

 

 

 

 

        📦 Enum Type

이번에는 일곱번째 이야기에서 공부해봤던 Enum Type에 대해 실습해 볼게요.

resources/graphql/graphql/other/enums.graphqls


위와 같이 Enum Type만 담을 수 있는 enums.graphqls를 만들어 주고, 그 안에 Enum Type들을 정의해 주었어요.


resources/graphql/graphql/people/people.graphqls


그리고 위와 같이 ResponseDto Type에 자료형 타입을 각각 Enum Type으로 지정해 주었어요.





위와 같이 실습해 본 결과 아무 문제 없이 동작하는 걸 확인하였어요.



일곱번째 이야기에서는 List Type과 Objet Type에 대해서 공부하고, 실습해 보았는데,
이미 Dto 객체로 반환받는 방법과 List Type으로 받는 방법에 대해 이야기 해 보았기 때문에 따로 실습하진 않을게요.

 

 

 

 

 

 

 

        📦 Interface

이번에는 여덟번째 이야기에서 공부해 보았던 Interface(인터페이스)에 대해 실습해 보도록 할게요.

 

GraphQL과 Apollo 여덟번째 이야기 - GraphQL Union과 Interface 그리고 인자와 인풋 타입에 대해 알아보아

GraphQL과 타입스크립트로 개발하는 웹 서비스:설계부터 개발·배포까지 따라 하며 완성하는 웹 풀 COUPANG www.coupang.com "이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를

junyharang.tistory.com

 

실습하기 전에 여덟번째 이야기에선 Union에 대해서도 이야기를 해 보았어요.
하지만, 주니가 느꼈을 때, Union이라는 걸 실제 서비스에서 얼마나 많이 쓸까?가 의문이 들었어요.

하나의 List에 각기 다른 N개의 객체를 담아서 보내는 것은 이미 위에서 해 보았고, 어떤 조건이 주어졌을 때, 그 조건이 맞으면 A 객체를 아니면 B 객체를 주는 등의 사용을 하는데, 아직까지는 실제 필요하다고 느끼지 못해서 일단! 실습은 하지 않도록 할거에요.

 

 

resources/graphql/graphql/equipment/equipment.graphqls

 

resources/graphql/graphql/software/software.graphqls

 

여덟번째 이야기에서 이야기했던 대로 위 두 Type은 객체 이름 중 usedBy가 겹치는 걸 알 수 있어요.
참고로 여덟번째 이야기에서는 ID 객체 이름이 모두 id 였기 때문에 이것도 겹쳤지만, 주니는 유니크한 ID 이름을 부여하기 위해 위와 같이 이름을 정해주어서 겹치지 않는걸 알 수 있어요.


이 부분만 Interface로 따로 빼 볼게요.

resources/graphql/graphql/Interface/interface.graphqls

 

 

 

resources/graphql/graphql/equipment/equipment.graphqls



resources/graphql/graphql/software/software.graphqls

 

그리고 위와 같이 각각의 Type 들이 Tool Interface(인터페이스)를 구현될 수 있도록 해주었어요.


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

query findeBygetEquipmentAndSoftwareListPagingUseByInterface {
  getEquipmentList (
    pageRequestDto: {
      currentPage: 1,
      perPageSize: 10
      orderBy: true
    },
    equipmentSearchRequestDto: {
      usedBy: "developer"
    }
  ) {
    statusCode,
    message,
    data {
      equipmentId,
      usedBy,
      count,
      newOrUsed
    },
    pagination {
      perPageSize,
      totalElementCount,
      totalPage
    }
  }

  getSoftwareList(
    softwareSearchRequestDto: {
      # usedBy: "developed",
      # developedBy: "",
      # description: ""
    },

    pageRequestDto: {
      currentPage: 1,
      perPageSize: 10,
      orderBy: true
    }
  ) {
    statusCode,
    message,
    data {
      usedBy,
      developedBy,
      description
    },
    pagination {
      perPageSize,
      totalElementCount,
      totalPage,
      orderBy
    }
  }
}


위와 같이 결과값을 받는걸 확인할 수 있고, Equipmensts List와 Softwares List 객체가 반환된걸 확인할 수 있어요.

이렇게 해서 주요 실습을 모두 마쳤어요.

 

 

 

    🔽  실습 마무리

        📦 짧은 회고

자프링, Nest.ts 그리고, 코프링까지! 주니가 활용할 수 있는 언어와 Framework가 늘어나서 너무 기분 좋아요.
그리고, GraphQL도 사용할 수 있다는 건 분명 도움이 많이 될 거에요.

Spring Boot 3로 변경이 되면서 Swagger, QueryDSL 설정 등이 변경 되었지만, 이렇게 GraphQL 이라는 주제 하나로 여러가지를 공부하고, 경험해 볼 수 있어서 소중한 시간이였어요.

 

 

 

스프링 부트 3 백엔드 개발자 되기 : 자바 편

COUPANG

www.coupang.com

"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."

 

 

 

 

 

카카오페이 | 마음 놓고 금융하다

여기를 눌러 링크를 확인하세요.

qr.kakaopay.com

 

 

 

728x90
반응형