[실습] GraphQL API 만들기 - 타입간 연결

기운찬곰·2020년 9월 13일
0

GraphQL

목록 보기
6/6
post-thumbnail

🚀 타입간 연결 - 일대일, 일대다

타입생성 및 변경

저번시간에 Photo까지만 만들고 끝이 났는데 이번에는 User를 만들어서 User가 다수의 Photo를 가질 수 있도록 1대다 관계를 만들어보도록 하겠습니다.

type User {
   githubLogin: ID!
   name: String
   avatar: String
   postedPhotos: [Photo!]!
}

하는 방법은 간단합니다. User 타입을 만들고 potedPhotos 필드로 Photo목록에 접근하도록 설정만 하면 됩니다.

Photo또한 User와 1대1 관계를 만들어줘서 무방향 그래프 형식이 되도록 해주겠습니다.

type Photo {
    id: ID!
    url: String!
    name: String!
    description: String
    category: PhotoCategory!
    postedBy: User!
}

샘플데이터

테스트를 위해 샘플 데이터도 만들어줬습니다.

const users = [
  {
    githubLogin: 'ckstn0777',
    name: 'ckstn'
  },
  {
    githubLogin: 'gildong0878',
    name: 'gildong hong'
  },
  {
    githubLogin: 'incheon0897',
    name: 'incheon univ'
  }
];

const photos = [
  {
    id: "1",
    name: "Test 1",
    description: "Test Photo 1",
    category: "GRAPHIC",
    githubLogin: "ckstn0777",
  },
  {
    id: "2",
    name: "Test 2",
    description: "Test Photo 2",
    category: "SELFIE",
    githubLogin: "gildong0878",
  },
  {
    id: "3",
    name: "Test 3",
    description: "Test Photo 3",
    category: "PORTRAIT",
    githubLogin: "gildong0878",
  },
];

리졸버 함수

User: {
  postedPhotos: (parent) => {
    // filter : 조건에 만족하는 모든 요소를 모아 새로운 배열로 반환
    return photos.fillter((p) => p.githubLogin === parent.githubLogin);
  },
},
Photo: {
  url: (parent) => `http://yoursite.com/img/${parent.id}.jpg`,
  postedBy: (parent) => {
    // find : 조건에 만족하는 첫번째 요소의 값을 반환
    return users.find((u) => u.githubLogin === parent.githubLogin);
  },
},

parent가 뭔지 아직도 헷갈린다면 저번시간글을 읽어보는 것을 추천합니다. filter와 find는 자바스크립트 배열 내장함수 중에서 기초에 해당하기 때문에 알거라고 생각합니다. (이것도 나중에 정리해야지)


쿼리 실행

query photos {
  allPhotos {
    name
    url
    postedBy {
      name
    }
  }
}

성공적으로 postedBy에서 name이 반환된 것을 볼 수 있습니다.


🪁 타입간 연결 - 다대다

타입 업데이트

이번에는 타입연결이 다대다인경우를 해보도록 하겠습니다. 예를 들어, 사진에 사용자를 태그하는 기능을 넣어보려고 합니다. User 한명이 여러 장의 사진에 태그될 수도 있고, Photo 한장에는 여러명의 사용자가 태그될 수도 있습니다.

type Photo {
  (생략)
  taggedUsers: [User!]!
}

type User {
  (생략)
  inPhotos: [Photo!]!
}

만드는 방법은 간단하죠?


샘플 데이터

const tags = [
  { photoID: '1', userID: 'ckstn0777'},
  { photoID: '2', userID: 'gildong0878'},
  { photoID: '2', userID: 'incheon0897'},
  { photoID: '2', userID: 'ckstn0777'},
]

테스트를 위해 샘플 데이터도 생성해줍니다.


리졸버

User: {
  (...생략...)
  inPhotos: (parent) => {
    return tags
      .filter(tag.userID === parent.id)
      .map((tag) => tag.photoID)
      .map((photoID) => photos.find((p) => p.id === photoID));
  },
},
Photo: {
  (...생략...)
  taggedUsers: (parent) => {
    return tags
      .filter((tag) => tag.photoID === parent.id)
      .map((tag) => tag.userID)
      .map((userID) => users.find((u) => u.githubLogin === userID));
  },
},

쿼리 실행

query listPhotos {
  allPhotos {
    url
    taggedUsers {
      name
    }
  }
}

각 사진마다 url과 태그되어있는 사용자 목록이 taggedUsers에 나오는 것을 볼 수 있습니다. 근데 마지막 taggedUsers는 빈배열입니다. [User!]! 를 썼기 때문에 안되는거 아닌가 의아했지만 알고보니 빈배열은 GraphQL에서는 null로 취급하지 않습니다. (저번시간 참고)

여기서 알 수 있는 점은 Tag라는 타입은 만들지 않았다는 것입니다. 다시말해 DB의 데이터 모델과 스키마 타입이 반드시 매칭할 필요는 없다는 소리가 됩니다. User과 Photo타입만을 이용해 충분히 찾을 수 있다면 그렇게 하는게 더 좋은 방법입니다.


마침

참고자료 및 사이트

profile
배움을 좋아합니다. 새로운 것을 좋아합니다.

0개의 댓글