도움말 - 글감 수집하기 (인용)

도움말 - 부분 리뷰 작성하기

5편 - React + GraphQL + Flowtype으로 트렐로 클론 웹앱 만들기 - 리스트(List), 카드(Card)

이전 편에서 우리는 graphql mutation 후에 스토어를 업데이트 할 수 있는 방법에 대해 다루고, 이 중 refetchQueries 옵션을 사용하여 스토어를 업데이트 하는 방법을 적용 했다. 또한, Flowtype의 기본적인 이론을 커버하고, 실제 소스에 적용 해봤다.

이번 편에서 우리는 List, Card graphql type을 만들고, graphql의 가장 큰 장점 중 하나인 relational data를 graphcool에서 다루는 방법에 대해서 다루도록 하겠다. 

참고: 이번 튜토리얼을 진행 하기 위해 진행 되는 코드를 깃헙에 업로드 해놨으니, 이 튜토리얼을 진행하고 싶다면 아래에서 소스를 클론 받은 후 아래의 내용을 따라가기를 추천 드립니다.

튜토리얼 소스:

https://github.com/simsim0709/react-apollo-flow-trello-clone/tree/ch-5

이전 편:

0편: React + GraphQL + Flowtype으로 트렐로 클론 웹앱 만들기 - 소개

1편: React + GraphQL + Flowtype으로 트렐로 클론 웹앱 만들기 - 프로토타입

2편: React + GraphQL + Flowtype으로 트렐로 클론 웹앱 만들기 - graphcool (GraphQL 서버 만들기)

3편: React + GraphQL + Flowtype으로 트렐로 클론 웹앱 만들기 - Trello Board 생성

4편: React + GraphQL + Flowtype으로 트렐로 클론 웹앱 만들기 - Apollo 스토어 업데이트, Flow


먼저 List와 Card graphql 타입을 추가 한다.

// 소스에 graphcool-server/types.graphql을 열어보자.

type Board @model {
id: ID! @isUnique
createdAt: DateTime!
updatedAt: DateTime!
name: String!
description: String
lists: [List!]! @relation(name: "ListOnBoard") // (1)
# owner: User! @relation(name: "UserBoards")
}
type List @model {
id: ID! @isUnique
createdAt: DateTime!
updatedAt: DateTime!
name: String
board: Board! @relation(name: "ListOnBoard") // (2)
cards: [Card!]! @relation(name: "CardOnList")
// (3)
}
type Card @model {
id: ID! @isUnique
createdAt: DateTime!
updatedAt: DateTime!
name: String
list: List! @relation(name: "CardOnList") // (4)
}

한개의 Board에는 여러개의 List를 가질 수 있다. 또한, 한개의 List는 여러개의 Card를 가질 수 있다. 그러므로, Board와 List는 one to many 관계이고, List와  Card역시 one to many의 관계가 된다. 이러한 데이터 간의 관계를 graphql에서는 type을 선언해주는 것으로 간단히 해결 할 수 있다.

위의 소스 주석 (1), (2), (3), (4) 을 보면, field의 타입을 scalar 타입을 선언하는 대신, model 타입을 선언 한 걸 알 수있다. 이렇게 scalar 타입 대신 model 타입을 선언 해주면 선언한 model 타입의 데이터가 리턴 된다. 하지만, 여기서 오해하지 않아야 할 것이 이렇게 선언만 한다고, graphql이 알아서 데이터를 찾아 와주는 것은 아니다. 우리가 만약 graphql 백엔드를 직접 만들었다면 이 부분을 resolver를 통해 로직을 구현 해야 하지만, 우리는 graphcool 서비스를 사용하고 있기 때문에 graphcool에서 제공하는 커스텀 디렉티브인 @relation 을 사용해서 이를 처리 해줘야 한다. 

위의 소스에서 relation 디렉티브 부분을 보면 알 수 있듯이, name 값을 사용 하여 두 타입간의 관계를 선언 했다.

더 자세한 내용은 공식 문서를 확인하자. 

자, 이제 수정된 types.graphql을 graphcool 서비스에 deploy 한다. (터미널에서 프로젝트 폴더로 이동 후에 아래 명령어를 실행 한다.)

cd graphcool-server && graphcool deploy

디플로이가 완료 됐다면 플레이그라운드를 실행해서, 데이터가 정상적으로 query, muation이 되는지 확인 해보자. 

graphcool palyground

플레이그라운드에서 임의로 보드를 만들어 보자:

mutation {
createBoard(name: "sample", description:"sample") {
id
}
}


여기에서 생성된 id 값을 복사 해놓고, 왼쪽 하단에 QUERY VARIABLES 부분에 방금 생성된 id를 값을 넣어 준다:

{
"boardId": "cjb5xk0t7np320199avw13vi7"
}

 그리고 아래처럼 List 데이터를 쿼리 해본다 (소스: pages/BoardPage.js):

query AllListsByBoardIdQuery($boardId: ID) {
allLists(filter: { board: { id: $boardId } }) {
id
name
cards {
id
createdAt
name
}
}
}

그럼 당연히 빈 데이터가 나올 것이다.

List를 mutation을 사용하여 생성 해보자(components/ListCreateButton.js).

mutation CreateListMutation($boardId: ID!, $name: String) {
createList(boardId: $boardId, name: $name) {
id
}
}

여기에 boardId는 위에서 사용한 id 값을, name은 임의의 string 값을 넣고 생성 해본후 위에 List query를 다시 해보면 방금 생성한 데이터가 배열로 나올 것이다.

자, 이 과정이 에러없이 진행 됐다면 성공 한 것이다. 그럼 각각의 리스트에 들어가는 Card도 playground에서 테스트 해보자. 과정은 List를 만들었던 것과 동일 하다.

먼저, List mutation을 하고 나온 id를 복사 한 후, listId를 복사한 id로 갖는 Card mutation을 진행한다(components/List.js):

mutation CreateCardMutation($listId: ID!, $name: String!) {
createCard(listId: $listId, name: $name) {
id
}
}

이렇게 샘플로 몇개의 카드를 만들어 보자.

이게 완료 됐다면, 다시 한번 위의 List query를 다시 해보자. 그러면  cards 필드에 배열로 데이터가 들어온 것을 알 수 있다. relational database에서 join으로 해결해야 하는 것을 type을 선언 해주는 것으로 간단하게 해결 했다. 

이 과정이 에러 없이 진행 됐다면, 나머지 소스 부분은 앞에서 한 과정과 같으니 직접 소스를 확인 해보며 진행 하면 무리가 없을 것으로 보인다.

이번 편은 여기서 마무리 짖고, 다음편에서는 카드 상세 뷰를 만들어 보자.


리뷰

5편 - React + GraphQL + Flowtype으로 트렐로 클론 웹앱 만들기 - 리스트(List), 카드(Card)

카드 상세 뷰는 언제 올라올지 알 수 있을까요?

저 같은 초보자들에게는 따라하기와 같은 튜토리얼이 무척 감을 잡기에 좋은데요 올려주신 내용은 정말 잘 보고 있었습니다. github 엔 chap-6 의 코드가 있는 것 같은데...