ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • GraphQL 개념 정리 (Apollo Client)
    PROGRAMMING/Web Programming 2021. 4. 6. 11:07
    반응형

    현재 진행 중인 프로젝트에서 React.js 프레임워크와 함께 GraphQL을 사용 중인데, 처음 써봐서 정리하려고 한다.


    GraphQL이란?

    API를 위한 query language로, Facebook에서 개발하였다. GraphQL은 기존의 RESTful API와는 달리 주로 하나의 Endpoint를 사용하며, query문에 따라 응답의 구조가 달라진다.

    이로써 내가 생각하는 장점은 크게 2가지인데,

    1. 쿼리 형식으로 server - client 간 통신이 용이하며, (schema가 오픈되므로) 유지보수와 확장성에 용이하다. 

    2. HTTP 요청의 횟수를 줄일 수 있으며 (하나의 query에 원하는 정보를 담아 요청할 수 있으므로), 더불어 응답 size를 줄일 수 있다.

    Query language란?
    query 언어란 정보를 얻기 위해 보내는 질의문(query)을 만들기 위해 사용되는 컴퓨터 언어의 한 종류


    GraphQL Exercise

    GraphQL 예제를 실행하기 위해서는, 기본적으로 Apollo client & server를 구축해놓은 환경이 필요하다.

    GraphQL Basic

    graphql.org/learn/queries/

     

    Queries and Mutations | GraphQL

    Queries and Mutations On this page, you'll learn in detail about how to query a GraphQL server. Fields# At its simplest, GraphQL is about asking for specific fields on objects. Let's start by looking at a very simple query and the result we get when we run

    graphql.org

    Query

    Apollo Client는 기본적으로 cache object를 제공함으로써, query를 실행할 때마다 새로운 요청을 발생시키는 것을 방지해 더 빠른 data fetch를 제공한다. 그 중에서도 cache update는 유용하게 쓰이는데..... 잘 모르겠어서 정리!

    Updating cache query results는 크게 2가지 feature로 쓰일 수 있다.

    1. Polling
    주기적으로 업데이트되는 data에서 유용하게 쓰일 수 있다. (near-real-time synchronization)
    참고로 pollInterval: 0 은 default 값이며 최초 1회 후 다시 poll을 진행하지 않는다. 또한 return object 내의 startPolling, stopPolling을 통해 dynamic polling을 진행할 수 있다.

    임의의 User를 관리하는 React component가 있다고 가정한 polling 예제:

    // poll query every 500ms
    const { loading, error, data } = useQuery(GET_USERS, {
      variables: { user },
      pollInterval: 500,
    });

    2. Refetching
    특정 action 후에, query results를 refresh 해주는 역할을 한다. variables를 넣어 다른 query를 요청할 수도 있고, 넣지 않으면 그 전 query를 그대로 실행한다. (optional)

    // return button using refetch
    const { loading, error, data, refetch } = useQuery(GET_USERS, {
      variables: { user }
    });
    
    if (loading) return null;
    if (error) return `Error! ${error}`;
    
    return <button onClick={()=>refetch()}>Refetch Data</button>;

    Mutation

    Query는 data를 요청하는 역할을 하고, 이제 mutation을 통해 data를 update하는 방법을 알아보자.

    Executing a Mutation Example:

    import { gql, useMutation } from '@apollo/client';
    
    const ADD_TODO = gql`
      mutation AddTodo($type: String!) {
        addTodo(type: $type) {
          id
          type
        }
      }
    `;
    
    function AddTodo() {
      let input;
      const [addTodo, { data }] = useMutation(ADD_TODO);
    
      return (
        <div>
          <form
            onSubmit={e => {
              e.preventDefault();
              addTodo({ variables: { type: input.value } });
              input.value = '';
            }}
          >
            <input
              ref={node => {
                input = node;
              }}
            />
            <button type="submit">Add Todo</button>
          </form>
        </div>
      );
    }

     

    Updating the Cache after a Mutation:

    1. Updating Single Entity Data

    const UPDATE_TODO = gql`
      mutation UpdateTodo($id: String!, $type: String!) {
        updateTodo(id: $id, type: $type) {
          id
          type
        }
      }
    `;
    
    function Todos() {
      const { loading, error, data } = useQuery(GET_TODOS);
      const [updateTodo] = useMutation(UPDATE_TODO);
    
      if (loading) return <p>Loading...</p>;
      if (error) return <p>Error :(</p>;
    
      return data.todos.map(({ id, type }) => {
        let input;
    
        return (
          <div key={id}>
            <p>{type}</p>
            <form
              onSubmit={e => {
                e.preventDefault();
                updateTodo({ variables: { id, type: input.value } });
                input.value = '';
              }}
            >
              <input
                ref={node => {
                  input = node;
                }}
              />
              <button type="submit">Update Todo</button>
            </form>
          </div>
        );
      });
    }
    

    2. Updtaing All Other Cache

    entity의 변경이 있을 때 Apollo Client는 이를 자동으로 반영하지 않는다. 이를 반영하기 위해서는 useMutation() 에 내장되어 있는 update() 를 사용해야 한다.

    update function 은 2개의 parameter를 제공하는데,

    • cache object 에서는 readQuery(), writeQuery(), readFragment(), writeFragment(), modify() 등을 쓸 수 있다.
    • update function 내 data property를 통해 cache.writeQuery() 등으로 cache update도 할 수 있다! <-- 내가 필요했던 기능
    import { gql, useMutation } from '@apollo/client';
    
    const ADD_TODO = gql`
      mutation AddTodo($type: String!) {
        addTodo(type: $type) {
          id
          type
        }
      }
    `;
    
    function AddTodo() {
      let input;
      const [addTodo] = useMutation(ADD_TODO, {
        update(cache, { data: { addTodo } }) {
          cache.modify({
            fields: {
              todos(existingTodos = []) {
                const newTodoRef = cache.writeFragment({
                  data: addTodo,
                  fragment: gql`
                    fragment NewTodo on Todo {
                      id
                      type
                    }
                  `
                });
                return [...existingTodos, newTodoRef];
              }
            }
          });
        }
      });
    
      return (
        <div>
          <form
            onSubmit={e => {
              e.preventDefault();
              addTodo({ variables: { type: input.value } });
              input.value = "";
            }}
          >
            <input
              ref={node => {
                input = node;
              }}
            />
            <button type="submit">Add Todo</button>
          </form>
        </div>
      );
    }
    

    www.apollographql.com/docs/react/data/mutations/#updating-the-cache-after-a-mutation

     

    Mutations

    Update data with the useMutation hook

    www.apollographql.com

    www.apollographql.com/docs/react/caching/cache-interaction/#writequery

     

    Reading and writing data to the cache

    A guide to using the Apollo GraphQL Client with React

    www.apollographql.com

     

    References

     

    GraphQL과 RESTful API

    GraphQL vs Restful API?

    www.holaxprogramming.com

     

    TroubleShooting

    내가 구현하고자 하는 기능은 user 하나를 업데이트 하면 get_users query를 다시 불러서 updated data로 렌더링해주는 것이었다. 결과적으로 현재 구현된 user update 기능이 전체 users를 업데이트 하지 않고, updated 유무 및 es_id를 가진 object를 리턴해주며, entity 변동도 없으므로 cache 대신 refetch를 이용하는 것이 훨씬 효율적이고 쉬운 방안이었다.

    결론 .. cache update 함수는 entity 변동이 있을 때만 쓰자!

    반응형

    댓글

Written by Emily.