4 minute read

Day 44

strapi를 이용한 GraphQL 서버 만들기

  • strapi GraphQL 설치
  • GraphQL 서버에서 query와 mutation으로 post CRUD, login 해보기

Apollo Client 소개

Apollo Client란?

  • React에서 GraphQL을 쉽게 사용할 수 있게 해주는 라이브러리이다.
  • 상태 관리, fetching, 캐싱, mutation, automatic UI update도 지원해준다.

Apollo Client React 공식 문서

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// const client = ...

client
  .query({
    query: gql`
      query GetLocations {
        locations {
          id
          name
          description
          photo
        }
      }
    `,
  })
  .then((result) => console.log(result));
  • gql은 template literal 문법을 이용해서 단순한 문자열을 graphql 문법으로 보여주는 함수이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import React from 'react';
import * as ReactDOM from 'react-dom/client';
import { ApolloClient, InMemoryCache, ApolloProvider } from '@apollo/client';
import App from './App';

const client = new ApolloClient({
  uri: 'https://flyby-router-demo.herokuapp.com/',
  cache: new InMemoryCache(),
});

// Supported in React 18+
const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(
  <ApolloProvider client={client}>
    <App />
  </ApolloProvider>,
);
  • ApolloProvider를 App에 감싸주어 apollo client를 사용할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// DisplayLocations.js
// Import everything needed to use the `useQuery` hook
import { useQuery, gql } from '@apollo/client';

const GET_LOCATIONS = gql`
  query GetLocations {
    locations {
      id
      name
      description
      photo
    }
  }
`;

function DisplayLocations() {
  const { loading, error, data } = useQuery(GET_LOCATIONS);

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

  return data.locations.map(({ id, name, description, photo }) => (
    <div key={id}>
      <h3>{name}</h3>
      <img width="400" height="250" alt="location-reference" src={`${photo}`} />
      <br />
      <b>About this location:</b>
      <p>{description}</p>
      <br />
    </div>
  ));
}
1
2
3
4
5
6
7
8
9
10
// App.js
export default function App() {
  return (
    <div>
      <h2>My first Apollo app 🚀</h2>
      <br/>
      <DisplayLocations />
    </div>
  );
}
  • gql을 이용하여 graphql 쿼리를 만들고 useQuery에 해당 변수를 대입함으로써 각 상태에 대한 값을 가져올 수 있다.

Queries

기본 사용법

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import { gql, useQuery } from '@apollo/client';

const GET_DOGS = gql`
  query GetDogs {
    dogs {
      id
      breed
    }
  }
`;

function Dogs({ onDogSelected }) {
  const { loading, error, data } = useQuery(GET_DOGS);

  if (loading) return 'Loading...';
  if (error) return `Error! ${error.message}`;

  return (
    <select name='dog' onChange={onDogSelected}>
      {data.dogs.map((dog) => (
        <option key={dog.id} value={dog.breed}>
          {dog.breed}
        </option>
      ))}
    </select>
  );
}

Caching query result

  • graphql은 처음 서버에 query를 날리면 해당 query가 자동으로 클라이언트 단에 caching되기 때문에 굉장히 데이터를 빠르게 받아올 수 있다.

Polling

1
2
3
4
5
6
7
8
9
10
11
12
13
function DogPhoto({ breed }) {
  const { loading, error, data } = useQuery(GET_DOG_PHOTO, {
    variables: { breed },
    pollInterval: 500,
  });

  if (loading) return null;
  if (error) return `Error! ${error}`;

  return (
    <img src={data.dog.displayImage} style= />
  );
}
  • useQuery에 option값으로 pollInterval을 설정하면 0.5초마다 값을 갱신한다.
  • pollInterval이 0이면 값을 갱신하지 않는다.

Refetching

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function DogPhoto({ breed }) {
  const { loading, error, data, refetch } = useQuery(GET_DOG_PHOTO, {
    variables: { breed },
  });

  if (loading) return null;
  if (error) return `Error! ${error}`;

  return (
    <div>
      <img src={data.dog.displayImage} style= />
      <button onClick={() => refetch({ breed: 'new_dog_breed' })}>
        Refetch new breed!
      </button>
    </div>
  );
}

<button
  onClick={() =>
    refetch({
      breed: 'dalmatian', // Always refetches a dalmatian instead of original breed
    })
  }
>
  Refetch!
</button>
  • 위 코드처럼 refetch함수를 이용하여 어떤 특정 이벤트가 발생할 때마다 데이터를 fetch할 수 있다. 이때 인자를 다르게 해서 fetch할 수도 있다.

Loading status 확인

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { NetworkStatus } from '@apollo/client';

function DogPhoto({ breed }) {
  const { loading, error, data, refetch, networkStatus } = useQuery(
    GET_DOG_PHOTO,
    {
      variables: { breed },
      notifyOnNetworkStatusChange: true,
    }
  );

  if (networkStatus === NetworkStatus.refetch) return 'Refetching!';
  if (loading) return null;
  if (error) return `Error! ${error}`;

  return (
    <div>
      <img src={data.dog.displayImage} style= />
      <button onClick={() => refetch({ breed: 'new_dog_breed' })}>
        Refetch!
      </button>
    </div>
  );
}
  • refetching할 때 로딩이 아니라 다른 걸 보여주고 싶을 때 networkStatus 변수를 이용할 수 있다.

useLazyQuery

  • 컴포넌트가 자동으로 데이터를 받지 않고 사용자 이벤트를 이용하여 나중에 데이터를 fetch하고 싶다면 useLazyQuery()를 사용할 수 있다.

Set a fetch policy

  • 기본적으로 네트워크 호출을 통해서 데이터를 받아오고 내부적으로 캐싱하고 다음에 받아올 때는 캐시된 내용을 가져오는 cache-first 정책을 사용하고 있다.
  • 이런 정책을 다른 정책을 사용하여 다르게 동작하도록 지정해줄 수 있다.

mutations

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { gql, useMutation } from '@apollo/client';

// Define mutation
const INCREMENT_COUNTER = gql`
  # Increments a back-end counter and gets its resulting value
  mutation IncrementCounter {
    currentValue
  }
`;

function MyComponent() {
  // Pass mutation to useMutation
  const [mutateFunction, { data, loading, error }] = useMutation(INCREMENT_COUNTER);
}
  • 위와 같이 실행할 함수와 gql 변수를 넣어주면 useLazyQuery와 비슷하게 쓸 수 있다.

GraphQL을 이용한 Todo 프로젝트 만들기

Categories:

Updated: