Apollo
Apollo GraphQL
GraphQL 클라이언트/서버 라이브러리. React, Node.js 통합.
Apollo GraphQL
GraphQL 클라이언트/서버 라이브러리. React, Node.js 통합.
Apollo는 GraphQL 생태계에서 가장 널리 사용되는 클라이언트 및 서버 라이브러리입니다. Apollo Client는 React, Vue, Angular 등 다양한 프론트엔드와 통합되며, 정규화된 캐싱 시스템으로 네트워크 요청을 최소화합니다. Apollo Server는 Node.js 환경에서 GraphQL API를 쉽게 구축하게 해줍니다.
2016년 Meteor Development Group이 시작한 프로젝트로, 현재는 독립 회사인 Apollo GraphQL이 운영합니다. GitHub, Airbnb, Expedia 등 대기업에서 사용하며, GraphQL 도입의 사실상 표준 도구가 되었습니다. 엔터프라이즈 버전인 Apollo Studio는 스키마 관리, 성능 모니터링, 연합 그래프를 지원합니다.
Apollo Client의 핵심은 InMemoryCache입니다. 쿼리 결과를 __typename과 id를 기반으로 정규화하여 저장하고, 동일한 데이터를 요청하면 네트워크 대신 캐시에서 즉시 반환합니다. 또한 useQuery, useMutation, useSubscription 훅으로 React와 자연스럽게 통합됩니다.
실무에서 Apollo는 여러 마이크로서비스의 GraphQL API를 통합(Federation)하거나, 복잡한 데이터 관계를 가진 애플리케이션에서 빛을 발합니다. Optimistic UI 업데이트로 뮤테이션 시 즉각적인 UI 반영이 가능하고, 로컬 상태까지 GraphQL로 관리할 수 있습니다.
// Apollo Client 설정 및 사용법
import { ApolloClient, InMemoryCache, gql, useQuery, useMutation } from '@apollo/client';
// 클라이언트 설정
const client = new ApolloClient({
uri: 'https://api.example.com/graphql',
cache: new InMemoryCache({
typePolicies: {
User: {
keyFields: ['id'],
},
},
}),
});
// 쿼리 정의
const GET_USERS = gql`
query GetUsers($limit: Int!) {
users(limit: $limit) {
id
name
email
avatar
}
}
`;
const CREATE_USER = gql`
mutation CreateUser($input: CreateUserInput!) {
createUser(input: $input) {
id
name
email
}
}
`;
// React 컴포넌트에서 사용
function UserList() {
const { loading, error, data, refetch } = useQuery(GET_USERS, {
variables: { limit: 10 },
fetchPolicy: 'cache-and-network',
});
const [createUser] = useMutation(CREATE_USER, {
// Optimistic UI 업데이트
optimisticResponse: {
createUser: {
__typename: 'User',
id: 'temp-id',
name: '새 사용자',
email: 'new@example.com',
},
},
// 캐시 업데이트
update(cache, { data: { createUser } }) {
const existing = cache.readQuery({ query: GET_USERS, variables: { limit: 10 } });
cache.writeQuery({
query: GET_USERS,
variables: { limit: 10 },
data: { users: [...existing.users, createUser] },
});
},
});
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<ul>
{data.users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
"REST API로 3번 호출하던 걸 Apollo Client로 GraphQL 쿼리 하나로 줄였더니 초기 로딩이 800ms에서 200ms로 개선됐어요. 캐싱도 자동이라 같은 데이터 다시 요청하면 네트워크 안 타고 바로 보여줍니다."
"Apollo Client는 InMemoryCache로 정규화된 캐싱을 합니다. __typename과 id 조합으로 엔티티를 식별하고, 한 곳에서 업데이트하면 그 데이터를 참조하는 모든 쿼리에 반영돼요. fetchPolicy로 cache-first, network-only 등 전략을 선택할 수 있습니다."
"이 뮤테이션에 optimisticResponse 추가하면 좋겠어요. 서버 응답 기다리지 않고 UI가 즉시 업데이트되어서 체감 속도가 훨씬 빨라집니다. 실패하면 Apollo가 자동으로 롤백해주고요."
id 필드 없이 쿼리하면 캐시 정규화가 안 됩니다. 모든 타입에 id를 포함하거나 typePolicies에서 keyFields를 지정하세요.
Apollo Server에서 DataLoader 없이 resolver를 작성하면 N+1 문제가 발생합니다. 반드시 DataLoader로 배치 처리하세요.
쿼리에 항상 id와 __typename을 포함하고, 뮤테이션 후 refetchQueries나 cache.modify로 캐시를 업데이트하세요.