GraphQL api

Inhye Jeong·2022년 10월 3일
0

GraphQL

목록 보기
1/1

아래 공식문서로 문법 및 전체적인 그림을 익히고,
노마드 코더 강의로 graph ql api 생성, 문서화 그리고 rest api를 graph ql로 마이그레이션하는 방법을 파악.

0. 설정

  • dependencies: apollo-server, graphql, node-fetch
  • devDependencies: nodemon

1. typeDefs

Query, Mutation resolver에 사용될 type을 정의한다.

  • Query, Mutataion은 지정된 Type이다.

2. resolvers

typeDefs를 활용해서 api response를 handling하는 resolver를 요구사항에 맞게 정의한다.

2-1. 정의

  • type 정의와 마찬가지로Query Resolver, Mutataion Resolver는 지정된 Resolver이다.
  • Dynamic Resolver 또한 type 정의를 참고하여 작성할 수 있다.
  • 각 resolver는 각 type과 동일한 네이밍이어야한다.
const typeDefs = gql`
    type Query {
      allMovies: [Movie!]!
      allUsers: [User!]!
      allTweets: [Tweet!]!
    }
    type Mutation {
      postTweet(text: String!, userId: ID!): Tweet
      deleteTweet(id: ID!): Boolean!
    }
`
const resolvers = {
  Query: {
    // typeDefs와 이름이 반드시 같아야한다.
    allTweets() {
      return tweets;
    },
    ...
  },
  Mutation: { ... }
}

2-2. arguments

  1. Query
    첫번째 arg는 Query 타입의 정보를 줌
func (root, { userId }) { ... }
  1. Mutation
    첫번째 arg는 호출되는 type의 root object.
    이걸 활용해서 dynamic 필드를 정의할 수 있음.
  User: {
    // Dynamic Resolver
    fullName({ firstName, lastName }) {
      return `${firstName} ${lastName}`;
    },
  },

3. Relationship

각 tweet과 User를 연결

  • 각 tweet에 userId를 각각 정의해줌
  • Tweet 타입은 author를 가지고 있음. 이걸 찾아줘야함
  • Tweet Resolver를 추가하고 author필드가 호출될시, 첫번째 argument의 userId로 tweets에서 tweet을 찾아서 리턴
let tweets = [
  {
    id: '1',
    text: 'first one',
    userId: '2',
  },
  {
    id: '2',
    text: 'second one',
    userId: '1',
  },
];
const typeDefs = gql`
  type User {
    id: ID!
    username: String!
    firstName: String!
    lastName: String!
    fullName: String!
  }
  type Tweet {
    id: ID!
    text: String!
    author: User // NOTE: relationship definition
  }
  type Query {
    allTweets: [Tweet!]!
  }
`;
const resolvers = {
  Query: {
    allTweets() {
      return tweets;
    },
    tweet(root, { id }) {
      return tweets.find((tweet) => tweet.id === id);
    },
  },
  Mutation: {
    Tweet: {
      author({ userId }) { // 첫번째 arg는 Tweet이 된다.
        return users.find((user) => user.id === userId);
      },
    },
};
  • 쿼리 요청
{
  allTweets {
    id
    text
    author {
      fullName
    }
  }
}
  • 처리 순서
  1. allTweets이 요청됨
  2. tweets이 리턴됨
  3. 각 tweet에서 author가 요청됨
  4. tweets에서 author가 없음을 알고, author resolver를 탐색함
  5. author resolver에서 첫번째 argument로 tweet 데이터를 넘겨줌
  6. author resolver는 User 타입을 리턴함.
  7. users에서 fullName이 없음을 알고, fullName resolver를 탐색함
  8. fullName resolver에서 첫번째 argument로 user 데이터를 넘겨줌
  9. fullName resolver는 user 데이터를 가지고 fullName을 만들어서 리턴함.
  • 결과
{
  "data": {
    "allTweets": [
      {
        "id": "1",
        "text": "first one",
        "author": {
          "fullName": "Elon Musk"
        }
      },
      {
        "id": "2",
        "text": "second one",
        "author": {
          "fullName": "inhye jeong"
        }
      }
    ]
  }
}

4. REST to Graph QL

  • rest 요청 응답을 type 정의한후
  • Query 요청시 resolver에서 rest api를 호출
const resolvers = {
  Query: {
    allMovies() {
      return fetch('https://yts.mx/api/v2/list_movies.json')
        .then((r) => r.json())
        .then((json) => json.data.movies);
    },
    movie(_, { id }) {
      return fetch(`https://yts.mx/api/v2/movie_details.json?movie_id=${id}`)
        .then((r) => r.json())
        .then((json) => json.data.movie);
    },
  },
}
  • 그 응답을 리턴해주기만 하면 됨

이렇게 처리하면, FE에서는 원하는 필드를 graph ql로 호출해서 사용할 수 있음.

profile
Frontend Engineer in @KakaoStyle

0개의 댓글