GraphQL과 Apollo 열 두번째 이야기 - TypeScript + Nest.js에서 GraphQL 사용해 보기 - 실습 환경 테스트

2023. 12. 5. 02:42Back-End 작업실/Nest.js

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)

 

 

 

 

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 열 두번째 이야기

    🔽 TypeScript + Nest.js에서 GraphQL 사용해 보기

        📦 실습 환경 테스트

이번 글에서는 지난 글에서 만들었던 GraphQL 형식의 Equipment CRUD에 대해 Schema(스키마)를 작성하고, PlayGround를 통해 QueryMutation문을 만들어 Query를 던져 정상적으로 Response(응답)가 오는지 확인해 보도록 할게요.

 

 

 

    🔽 Schema

        📦 Query - getEquipmentList()

src/graphql/schema/schema.graphqls


최초 type Root Query를 보면 getEquipmentList()와 getEquipment()가 선언 되어 있는걸 볼 수 있어요.
이 함수 이름은 Resolver(리졸버)의 Method(메서드) 이름과 똑같아야 해요.

getEquipmentList()는 usedBy, newOrUsed, page, perPageSize, orderBy를 인자값으로 받아요.
이 부분에 대한 상세 내용은 이 전 글에서 Resolver를 이야기 할 때, 자세히 이야기 해 보았어요.

즉, 리졸버의 메서드의 이름과 매개 변수, 반환 Type(타입)이 일치해야 해요.


src/graphql/schema/equipment/equipment.graphqls


getEquipmentList()의 반환 타입은 위와 같이 선언 되어 있어요.
HTTP Status Code를 정수로 받고,
처리 결과를 문자열로 받는데, ! 느낌표는 Null이면 안된다는 의미.
즉, 무조건 값이 있어야 한다는 의미에요.

src/graphql/schema/equipment/equipment.graphqls


pagination 속성은 위 type을 자료형으로 정의해 두었는데,
Paging 처리 결과를 담은 정수 타입의 변수들과 데이터베이스에서 조회된 결과를 담은
EquipmentResponseDto 객체를 배열로 받겠다고 선언해 주었어요.


src/graphql/schema/equipment/equipment.graphqls


data 속성의 값은 위 자료형 타입인데, equipmentId, usedBy, count, newOrused라는
실제 데이터 값을 갖은 DTO를 반환받게 해 두었어요.








        📦 Query - getEquipment()

src/graphql/schema/schema.graphqls


getEquipment()는 인자값으로 ID값을 문자열을 반드시 받도록하고,
반환 타입을 FindByEquipmentResponse로 돌려주는데, 필수로 나와야 하도록 정의해 주었어요.

src/graphql/schema/equipment/equipment.graphqls


FindByEquipmentResponse는 위와 같이 HTTP Status Code와 Message를 주고,
data로는 ResponseDto를 주도록 해 주었어요.


src/graphql/schema/equipment/equipment.graphqls






        📦 Mutaion - saveForEquipment()

src/graphql/schema/schema.graphqls


saveForEquipment()는 EquipmentRequestDto를 input 타입으로 받도록 해 주었어요.



src/graphql/schema/equipment/equipment.graphqls


장비에 대한 저장 처리 로직이기 때문에 모든 값을 필수로 받도록 처리해 주었어요.


src/graphql/schema/equipment/equipment.graphqls


반환 타입은 위와 같은데, HTTP Status Code와 Message를 받고, data로는 해당 작업이 처리되고,
반환된 ID 값을 받겠다고 정의해 주었어요.

참고로 작업이 실패하면 data는 아무것도 담기지 않을 거고, 문제에 대한 내용을 출력하기 위해
statusCode와 message만 값이 담겨올 것이라서 data에는 느낌표를 붙히지 않았어요.






        📦 Mutaion - updateEquipment()

src/graphql/schema/schema.graphqls

 

src/graphql/schema/equipment/equipment.graphqls


update Logic의 경우 수정할 대상을 잡아야 하기 때문에 ID값은 필수로 받아야 하지만,
나머지는 뭘 수정할지 알 수 없기 때문에 느낌표를 붙히지 않았어요.
반환 값은 saveForEquipment()와 동일하게 처리해 주었어요.


 

 

 

 

        📦 Mutaion - deleteEquipment()

src/graphql/schema/schema.graphqls


Delete Logic의 경우에도 삭제 대상을 잡아줘야 하기 때문에 ID값을 필수 인자값으로 받아주고 있어요.

그리고 반환 타입은 getEquipment()와 동일하게 처리해 주었어요.

 

 

 

 

    🤔 잘 동작하나?

        📦 PlayGround

이제 정상 동작 여부를 하나하나 테스트 해볼게요.

1. saveForEquipment

mutation saveForEquipment {
  saveForEquipment(input: {
    equipmentId: "MacBook",
    usedBy: "developer",
    count: 100,
    newOrUsed: "new"
  }) {
    statusCode,
    message,
    data
  }
}

 


해당 문법에 대해서는 이 글의 이 전 시리즈를 통해 공부해 보았어요.
GraphQL에 대해 잘 모르시는 분은 해당 시리즈 처음부터 글을 보시면 좋을 거 같아요.

반응형



mutation saveForEquipment

 

mutation saveForEquipment



 

2. getEquipmentList - findBygetEquipmentListSeachAllFieldAndPaging

이 테스트는 전체 조회를 할 때, 모든 요소에 대한 검색 값이 있고, Paging 관련 값도 있으며, 정렬에 대해 내림차순으로 조회 해달라는 Request(요청)에 대한 테스트에요.

query findBygetEquipmentListSeachAllFieldAndPaging {
  getEquipmentList(
    usedBy: "developer",
    newOrUsed: "used",
  	page: 1,
  	perPageSize: 10,
    orderBy: true
  ) {
    statusCode,
    message,
    pagination{
      perPageSize,
      totalCount,
      totalPage,
      data {
        equipmentId,
        usedBy,
        count,
        newOrUsed
    	}
    }
  }
}

query findBygetEquipmentListSeachAllFieldAndPaging

 

 

 

2-1. getEquipmentList - findeBygetEquipmentListPaging

이번에는 검색 조건은 없이 Paging 처리 요청만 들어왔을 때에요.

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

 

query findeBygetEquipmentListPaging

 

{
  "data": {
    "getEquipmentList": {
      "statusCode": 200,
      "message": "Success",
      "pagination": {
        "perPageSize": 6,
        "totalCount": 7,
        "totalPage": 2,
        "data": [
          {
            "equipmentId": "pen tablet",
            "usedBy": "developer",
            "count": 15,
            "newOrUsed": "used"
          },
          {
            "equipmentId": "ergonomic mouse",
            "usedBy": "designer",
            "count": 31,
            "newOrUsed": "used"
          },
          {
            "equipmentId": "dual monitor",
            "usedBy": "developer",
            "count": 20,
            "newOrUsed": "used"
          },
          {
            "equipmentId": "whiteboard",
            "usedBy": "planner",
            "count": 12,
            "newOrUsed": "used"
          },
          {
            "equipmentId": "sketchb",
            "usedBy": "designer",
            "count": 48,
            "newOrUsed": "new"
          },
          {
            "equipmentId": "MacBook",
            "usedBy": "developer",
            "count": 100,
            "newOrUsed": "new"
          }
        ]
      }
    }
  }
}

 





2-2. getEquipmentList - findBygetEquipmentListSeachUsedByAndPaging

이번에는 검색 조건으로 usedBy가 들어오고, Paging 요청이 들어왔을 때에요.

query findBygetEquipmentListSeachUsedByAndPaging {
  getEquipmentList(
    usedBy: "developer",
    page: 1,
    perPageSize: 1
  ) {
    statusCode,
    message,
    pagination {
      perPageSize,
      totalCount,
      totalPage
      data {
        equipmentId,
        usedBy,
        count,
        newOrUsed
    	}
    }
  }
}
728x90

query findBygetEquipmentListSeachUsedByAndPaging





 

2-3. getEquipmentList - findBygetEquipmentListSeachNewOrUsedAndPaging

이번에는 검색 조건으로 newOrUsed만 들어오고, Paging 요청이 들어왔을 때에요.

query findBygetEquipmentListSeachNewOrUsedAndPaging {
  getEquipmentList(
    newOrUsed: "used",
    page: 1,
    perPageSize: 10
  ) {
    statusCode,
    message,
    pagination {
      perPageSize,
      totalCount,
      totalPage
      data {
        equipmentId,
        usedBy,
        count,
        newOrUsed
      }
    }
    ,
  }
}

 

query findBygetEquipmentListSeachNewOrUsedAndPaging

 

{
  "data": {
    "getEquipmentList": {
      "statusCode": 200,
      "message": "Success",
      "pagination": {
        "perPageSize": 4,
        "totalCount": 5,
        "totalPage": 2,
        "data": [
          {
            "equipmentId": "pen tablet",
            "usedBy": "developer",
            "count": 15,
            "newOrUsed": "used"
          },
          {
            "equipmentId": "ergonomic mouse",
            "usedBy": "designer",
            "count": 31,
            "newOrUsed": "used"
          },
          {
            "equipmentId": "dual monitor",
            "usedBy": "developer",
            "count": 20,
            "newOrUsed": "used"
          },
          {
            "equipmentId": "whiteboard",
            "usedBy": "planner",
            "count": 12,
            "newOrUsed": "used"
          }
        ]
      }
    }
  }
}






3. getEquipment

이번에는 상세 조회 테스트 해볼게요.

query getEquipment {
  getEquipment(
  equipmentId: "machanical keyboard"
  ) {
    statusCode,
    message,
    data {
      equipmentId,
      usedBy,
      count,
      newOrUsed
    }
  }
}

query getEquipment








4. updateEquipment

이번에는 위에서 저장했던 equipmentId 값이 MackBook인 것을 수정해 볼게요.

mutation updateEquipment {
  updateEquipment(input: {
    equipmentId: "MacBook",
    usedBy: "developer",
    count: 150
    newOrUsed: "new"
  }) {
    statusCode,
    message,
    data
  }
}

mutation updateEquipment

 

mutation updateEquipment


위와 같이 필수값을 넣어주지 않으면 해당 Field 값이 정의되지 않았다고 Error가 발생하는 걸 볼 수 있어요.


mutation updateEquipment




4. deleteEquipment

이번엔 만들어줬던 MacBook에 대한 개체를 삭제해 볼게요.

mutation deleteEquipment {
  deleteEquipment(
    equipmentId: "MacBook") {
    statusCode,
    message,
    data
  }
}

mutation deleteEquipment





Console


위와 같이 정상 처리되는 것을 확인할 수 있어요.

Equipment 외에 다른 것들도 이와 비슷하게 구성될 것이기 때문에 Equipment에 대한 내용만 남기고,
나머지는 추가 실습을 하면서 정리해 보도록 할게요.

해당 내용은 실습 코드에 src/graphql/query에 남겨 두었어요.


실습해보고 싶으시다면 Git Hub에 방문해 주세요.


 

 

 

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
반응형