React에 GraphQL 한스푼 더하기: 2. Apollo Client

률루랄라·2020년 8월 16일
0
post-thumbnail

0. why?

다시 말하지만 graphQL은 graphQL 서버와 통신하기 위한 쿼리 언어일뿐 서버 통신 방법이 아닐뿐더러 graphQL 역시 비동기로 처리가 된다.
지난번 블로깅을 통해 graphQL 서버에 QUERY라는 요청하는 방법, 더 자세히는 문법에 대해 알아보았다.
여러가지 문법을 통해 원하는대로 요청을 보내고 원하는대로 응답을 받고 또한 여러 상황에 대해서 서버와 통신하는 graphQL만의 문법을 알아보았다.
그렇다면 실제로 서버와의 통신과정과 통신을 통한 응답을 우리가 만드는 어플리케이션에 가져올 수 있을까?

1.0. Apollo Client

Apollo Client is a fully-featured caching GraphQL client with integrations for React, Angular, and more. It allows you to easily build UI components that fetch data via GraphQL.
출처:npmjs-apollo-client

npmjs.com에 나온 Apollo Client에 대한 설명이다. graphQL API를 어플리케이션 내에서 사용할 때 유용한 package들이 여러개 있는데 (예를 들면 페이스북의 relay) Apollo Client가 최고이며 가장 많이 사용된다고 하는데 이유들은 다음과 같다.

  1. Apollo Client는 개발자로 하여금 graphQL을 통한 local과 remote 데이터 관리가 가능하게 해주는 종합적인 자바스크립트 상태관리 라이브러리 이고 (apollo의 cache 기능과 관련이 있다. 나중에 깊게 정리할 예정)
  2. 경제적이고, 예측 가능하고 선언적인 방법인 모던한 개발 방식과 일관되도록 코드를 작성하도록 도와주고
  3. 그 어떤 프레임워크던지 관계없이 자바스크립트 프론트엔드로 하여금 graphQL 서버로 부터 데이터 통신이 가능하고

등등의 이유가 있다.
하지만 개인적으로 Apollo ClientgraphQL과 찰떡궁합인 이유는 (비록 relay를 사용해보지 못하였지만) graphQL API의 작동원리에 있다고 생각한다.

1.1. graphQL API와 REST API

graphQL API의 작동방법을 간단하게 살펴보면 결국은 fetch이다.
이 말이 무슨 뜻이냐 하면 graphQL API는 결국은 REST API와 다를바 없다는 뜻이다.
REST API는 url로 접근하여 원하는 method를 코드로 작성하여서 서버와 통신을 한다.
graphQL은 이와는 조금 다르게 단 하나의 endpointurl에 접근하여 원하는 방식과 데이터 필드를 querymutation을 통해서 통신한다.
하지만 조금만 더 깊게 살펴보면 graphQL API는 기본적으로 우리가 원하는 정보를 query나 mutation으로 작성하여 Axiosfetch와 함께 POST request를 서버로 보낸다.
graphQL API는 모두 단 하나의 endpoint를 가진다는 차이점을 제외하면 결국 통신은 fetch,POST 등으로 이뤄진다는 점에서 큰 차이점은 없다.


위 이미지의 빨간색 박스 두개를 보듯이 실제 graphQL 통신은 fetch타입에 POST method임을 알 수 있다.
즉 apollo-client와 같은 패키지 없이 graphQL 서버와 통신하기 위해서는 우리가 원하는 정보와 함께 작성한 query를 Axios의 fetch와 함께 POST request로 보내야한다. 그 방법이 존재하는지 어떻게 하는지 알지도 못하지만 매우 복잡해 보이고 번거로워보인다.
그래서 apollo-client를 이용하면 apollo가 직접 이런 방식으로 알아서 서버와 통신을 가능케 해주고 모든 설정을 다 자동으로 해주는 package를 제공해준다.

2.0. REACT에 Apollo-client 더하기

위의 이유들 중 가장 손꼽히는 apollo의 장점은 cache기능으로서 불필요한 서버 통신을 최대한으로 줄여준다.
더 나아가 리액트 개발자로서 apollo-client가 제공해주는 여러 hook들은 나로 하여금 apollo를 사용하지 않을 이유가 전혀 없다고 본다.
물론 react말고도 다른 javascript 프론트엔드 프레임워크에서도 사용이 가능하지만 이상하리만큼 REACT에 대한 기능 제공이 많다.
그럼 너무 감사하니 한번 기본 세팅을 적용해보자.
Apollo-client에서 사용하는 여러 페키지가 있었지만 지금은 core-package하나면 충분히 사용이 가능하게 update되었다

npm install @apollo/client graphql
요 2개의 패키지만으로도 충분히 사용 가능하다.

@apollo/client:
이 싱글 페키지는 Apollo Client를 세팅하기 위해 필요한 사실상 거의 모든것이 들어있다.
[in-memory cache, local state management, error handling, and a React-based view layer] 등등 graphQL서버와 통신을 위해 사용하는 Apollo Client 세팅을 할 수 있게 해준다.
graphql: 이 패키지는 GraphQL 쿼리들을 파싱하는 로직들을 제공해준다.

또한 apoll-client자체가 커뮤니티 오픈 소스 기반으로 개발된 라이브러리라 customized되고 공식 문서에서 인증해주는 패키지들도 존재한다.

2.1. Client 설정하기

역시나 공식문서에 잘 설명이 되어있다. 특히 react관련은 더더욱 다양하고 자세한 설명이 존재한다.
공식문서에 따라 천천히 설정해보자.

import { ApolloClient, InMemoryCache } from '@apollo/client';
import { gql } from '@apollo/client';


const client = new ApolloClient({
  uri: 'endpoint of your graphQL server',
  cache: new InMemoryCache()
});

client
// client에 접근하여
  .query({
  // query요청임을 명시해주고
    query: gql`
      query GetRates {
        rates{
          currency
        }
      }
    `
  // query에서 우리가 원하는 내용을 명시해준다.
  // 이렇게 직접 명시도 가능하지만 지난번 블로그에서 정리했듯이 query내용을 직접 다른 파일에 정의해놓고 import해서 사용도 가능하다. 
  })
  .then(result => console.log(result));
// fetch타입의 post method임으로 Promise패턴으로 접근이 가능하다. 

이게 기본적인 client 설정과 그 설정에 접근하여 실제로 Apollo-client 도움으로 graphQL 서버와 통신하는 방법이다.
하지만 우리는 개발자이기에 매번 요청마다 client를 설정하여 서버와 통신하는 방법보다 조금 더 개발자스러운 방법으로 해보자.

2.2. Provider

Provider 패턴을 통해 매번 client를 정의할 필요없이 props로 받아서 사용해보자.

import React from 'react';
import { render } from 'react-dom';

import { ApolloProvider } from '@apollo/client';
import { ApolloClient, InMemoryCache } from '@apollo/client';

function App() {
  const client = new ApolloClient({
  uri: 'https://48p1r2roz4.sse.codesandbox.io',
  cache: new InMemoryCache()
  });
  return (
    <ApolloProvider client={client}>
      <div>
        <h2>My first Apollo app 🚀</h2>
      </div>
    </ApolloProvider>
  );
}

render(<App />, document.getElementById('root'));

이런식으로 Provider 패턴을 통해 Provider에 의해 감싸진 컴포넌트들은 어느 곳에서든 clientprops로 받아서
서버와 통신이 가능해진다.

// getExchangeRatesQuery.js
import { gql } from '@apollo/client';
export const EXCHANGE_RATES = gql`
  query GetExchangeRates {
    rates {
      currency
      rate
    }
  }
`;

// ExchangeRates.js
import { useQuery} from '@apollo/client';
import {EXCHANGE_RATES} from 'getExchangeRatesQuery.js'

function ExchangeRates() {
  const { loading, error, data } = useQuery(EXCHANGE_RATES);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error :(</p>;

  return data.rates.map(({ currency, rate }) => (
    <div key={currency}>
      <p>
        {currency}: {rate}
      </p>
    </div>
  ));
}

이렇게 hook사용이 가능한 함수형 컴포넌트에서는 apollo-client가 제공해주는 hook으로 사용이 가능하며
class형 컴포넌트에서는 props.client로 접근하여 사용이 가능해진다.

3.0. 마무리

이번 블로그에서 client 설정 즉, apollo-client를 설정하는 다양한 방법에 (Link, onError 등등) 대해서 함께 정리하려했다.
하지만 정말 이번주도 바쁘고 다음주도 바쁠예정이라 오늘은 블로깅이 부끄럽게 느껴질만큼 간단하지만 여기서 마무리 하려 한다.
다음 블로깅에서는 다양한 client 설정 방법과 옵션설정들에 대해서 알아보고 추가로 실제로 accessTokenrefreshToken을 이용한
인증 인가 부분을 개발하며 했었던 삽질과 해결 방법을 통해 Apollo-client의 error handling에 대해서 정리할 계획인다.
개발하며 정리하고 넘어가고 싶은 부분이 정말 많은데 매번 일정에 쫒겨 정리를 못하는 모습에 반성만 하고 있는 내모습에 다시한번 반성하며 이번 블로깅은 여기서 끝.

profile
💻 소프트웨어 엔지니어를 꿈꾸는 개발 신생아👶

0개의 댓글