Docs Menu
Docs Home
/ /
Atlas Device SDK
/

Apollo 클라이언트(React) - 웹 SDK

이 페이지의 내용

  • 개요
  • Apollo 클라이언트 설정
  • 설치 종속성
  • 종속성 가져오기
  • Apollo GraphQL 클라이언트 생성
  • 사용자 인증 설정
  • 앱에 Apollo 클라이언트 추가
  • 쿼리 및 돌연변이 실행
  • 쿼리 실행
  • 돌연변이 실행
  • Paginate Data
  • 액세스 토큰 새로 고침

Apollo Client 을(를) 사용할 수 있습니다. React 애플리케이션 에서 Realm 앱의 노출된 GraphQL API 에 연결합니다. Apollo Client는 쿼리 및 변형을 실행하고, 클라이언트 사이드 데이터 캐시 를 유지 관리하며, 관용적 인 React 구성 요소 및 후크를 사용하여 앱 에 통합합니다.

참고

워킹 데모 애플리케이션 보기

확인 Realm GraphQL - Apollo(React) 에서 리포지토리를 Github 확인하면 자체 백엔드에 React 연결할 준비가 된 완전히 설정된 & Apollo 애플리케이션을 볼 수 Atlas App Services 있습니다. MongoDB Atlas 샘플 데이터 세트에 포함된 sample_mflix.movies 컬렉션을 사용합니다.

리포지토리 를 복제하지 않으려면 브라우저 내 Realm GraphQL CodeSandbox 에서 데모 애플리케이션 을 사용할 수도 있습니다.

1

다른 Realm 프로젝트와 마찬가지로 사용자와 요청을 인증하기 위해 Realm 웹 SDK 를 설치해야 합니다.

npm install realm-web

Apollo는 클라이언트를 생성하는 데 필요한 핵심 구성 요소를 @apollo/client라는 패키지에 번들로 제공합니다. 또한 GraphQL 쿼리를 구문 분석하려면 graphql 패키지가 필요합니다.

npm install @apollo/client graphql
2

및 에서 필요한 종속성을 realm-web @apollo/client 가져와서 Apollo GraphQL 클라이언트를 만들고 Realm으로 인증을 추가합니다.

import * as Realm from "realm-web";
import {
ApolloClient,
ApolloProvider,
HttpLink,
InMemoryCache,
} from "@apollo/client";
3

Realm 앱의 GraphQL API 점을 새로운 ApolloClient 객체를 생성합니다. Realm 앱 ID를 기반으로 엔드포인트 URL을 생성하거나 Realm UI의 GraphQL 페이지에서 찾을 수 있습니다.

// Add your App ID
const graphqlUri = `https://services.cloud.mongodb.com/api/client/v2.0/app/${APP_ID}/graphql`;
// Local apps should use a local URI!
// const graphqlUri = `https://us-east-1.aws.services.cloud.mongodb.com/api/client/v2.0/app/${APP_ID}/graphql`
// const graphqlUri = `https://eu-west-1.aws.services.cloud.mongodb.com/api/client/v2.0/app/${APP_ID}/graphql`
// const graphqlUri = `https://ap-southeast-1.aws.services.cloud.mongodb.com/api/client/v2.0/app/${APP_ID}/graphql`
const client = new ApolloClient({
link: new HttpLink({
uri: graphqlUri,
}),
cache: new InMemoryCache(),
});
4

은(는)ApolloClient 앱에 요청을 보내도록 구성됩니다. 그러나 모든 Realm GraphQL 요청에는 요청을 인증하기 위한 유효한 사용자 액세스 토큰이 포함되어야 하므로, 현재로서는 Apollo에서 전송된 모든 작업이 실패합니다. 액세스 토큰은 30분 후 만료되며 새로 고침해야 합니다.

요청을 인증하려면 각 GraphQL 요청에 유효한 리.Realm 사용자 액세스 토큰이 포함된 권한 부여 헤더를 추가해야 합니다.

Realm 웹 SDK를 사용하여 사용자를 인증하고 액세스 토큰을 받을 수 있습니다. Apollo HttpLink 객체를 사용하면 사용자 지정 fetch 함수를 정의하여 모든 요청에 사용자 지정 헤더를 추가할 수 있습니다.

// Connect to your MongoDB Realm app
const app = new Realm.App(APP_ID);
// Gets a valid Realm user access token to authenticate requests
async function getValidAccessToken() {
// Guarantee that there's a logged in user with a valid access token
if (!app.currentUser) {
// If no user is logged in, log in an anonymous user. The logged in user will have a valid
// access token.
await app.logIn(Realm.Credentials.anonymous());
} else {
// An already logged in user's access token might be stale. Tokens must be refreshed after
// 30 minutes. To guarantee that the token is valid, we refresh the user's access token.
await app.currentUser.refreshAccessToken();
}
return app.currentUser.accessToken;
}
// Configure the ApolloClient to connect to your app's GraphQL endpoint
const client = new ApolloClient({
link: new HttpLink({
uri: `https://services.cloud.mongodb.com/api/client/v2.0/app/${APP_ID}/graphql`,
// We define a custom fetch handler for the Apollo client that lets us authenticate GraphQL requests.
// The function intercepts every Apollo HTTP request and adds an Authorization header with a valid
// access token before sending the request.
fetch: async (uri, options) => {
const accessToken = await getValidAccessToken();
options.headers.Authorization = `Bearer ${accessToken}`;
return fetch(uri, options);
},
}),
cache: new InMemoryCache(),
});
5

이제 인증된 GraphQL 요청을 App Services 백엔드로 보내도록 Apollo 객체가 구성되었습니다.client 이제 나머지 React 애플리케이션에서 사용할 수 있도록 하는 일만 남았습니다.

패키지는 하위 구성 @apollo/client 요소에서 호출하는 ApolloProvider client 모든 Apollo 후크에서 을(를) 사용할 수 있도록 하는 구성 요소를 내보냅니다. 앱을 ApolloProvider (으)로 래핑하고 client 객체를 제공자에게 전달합니다.

// ... code to create the GraphQL client
const AppWithApollo = () => (
<ApolloProvider client={client}>
<App />
</ApolloProvider>
);

@apollo/client 패키지에는 구성 요소를 GraphQL API에 연결하고 쿼리 및 변형 실행을 처리하는 선언적 React 후크 세트가 포함되어 있습니다.

후크에 전달할 수 있는 쿼리 및 변형을 정의하려면 graphql-tag를 설치하세요.

npm install graphql-tag

관련 후크와 GraphQL 쿼리 생성자를 사용하고 있는 파일 상단에서 이를 가져옵니다.

// import whichever Apollo hooks you're using
import { useQuery, useMutation } from "@apollo/client";
import gql from "graphql-tag";

참고

Apollo Hooks에는 ApolloProvider가 있어야 합니다.

쿼리 및 변형 후크를 호출하는 구성 요소는 ApolloProvider 의 하위 항목이어야 합니다. Atlas App Services 백엔드에 대해 구성한 항목입니다. 후크가 쿼리 client 호출합니다. 및 돌연변이 제공된 객체에 대한 메서드입니다.

Apollo Client에는 쿼리 실행을 위한 후크가 두 개 포함되어 있습니다. 후크는 동일한 매개 변수를 허용하지만, 쿼리를 실행하는 시점이 다릅니다.

  • useQuery()를 호출합니다. 구성 요소가 마운트될 때 자동으로 실행됩니다. 또한 호출할 때마다 쿼리를 다시 실행하는 콜백을 반환합니다.

  • useLazyQuery() 는 호출할 때마다 쿼리를 실행하는 콜백 함수를 반환합니다. 구성 요소 마운트에서 쿼리를 실행하지 않습니다.

두 후크 모두 쿼리 정의와 variables Apollo가 쿼리에 전달하는 을(를) 포함한 추가 옵션을 허용합니다. 또한 두 쿼리 모두 쿼리의 현재 실행 상태와 가장 최근 실행에서 반환된 데이터에 대한 정보를 반환합니다.

const ALL_MOVIES = gql`
query AllMovies {
movies {
_id
title
year
runtime
}
}
`;
// Must be rendered inside of an ApolloProvider
function Movies() {
const { loading, error, data } = useQuery(ALL_MOVIES);
if (loading) {
return <div>loading</div>;
}
if (error) {
return <div>encountered an error: {error}</div>;
}
return <MovieList movies={data.movies} />;
}

useMutation() hook은 변형 정의와 선택적 구성 객체를 허용합니다. 전달해야 하는 가장 일반적인 옵션은 variables GraphQL 변수 에 매핑되는 객체입니다. 변형 정의에 포함됩니다.

후크는 여러 개의 객체를 배열로 반환합니다:

  • 변이를 실행하는 콜백 함수

  • 변형의 실행 상태와 가장 최근 실행에서 반환된 데이터에 대한 정보를 포함하는 객체입니다.

const UPDATE_MOVIE_TITLE = gql`
mutation UpdateMovieTitle($oldTitle: String!, $newTitle: String!) {
updateOneMovie(query: { title: $oldTitle }, set: { title: $newTitle }) {
title
year
}
}
`;
// Must be rendered inside of an ApolloProvider
function MovieList({ movies }) {
const [updateMovieTitle] = useMutation(UPDATE_MOVIE_TITLE);
return (
<ul>
{movies.map((movie) => (
<li key={movie._id}>
<div>{movie.title}</div>
<button
onClick={() => {
updateMovieTitle({
variables: {
oldTitle: movie.title,
newTitle: "Some New Title",
},
});
}}
>
Update Title
</button>
</li>
))}
</ul>
);
}

API에서 생성한 GraphQL 스키마에서 제공하는 유형으로 쿼리의 데이터에 페이지를 매길 수 있습니다. useQuery()useLazyQueryHook() 후크를 사용하여 Apollo GraphQL 클라이언트로 데이터에 페이지를 매길 수 있습니다.

Atlas GraphQL API에는 offset GraphQL 문서에서 페이지 매김에 권장하는 것과 같은 연산자가 없습니다.

다음 예시에서는 useQuery() 후크와 전달한 변수에 따라 데이터를 오름차순 및 내림차순으로 쿼리할 수 있는 GraphQL 쿼리를 사용합니다.

const PAGINATE_MOVIES = gql`
query PaginateMovies(
$prevTitle: String
$nextTitle: String
$limit: Int!
$sortDirection: MovieSortByInput!
) {
movies(
# Can add other query filters here if you'd like
query: { title_gt: $prevTitle, title_lt: $nextTitle }
limit: $limit
sortBy: $sortDirection
) {
_id
title
year
}
}
`;
const resultsPerPage = 5;
function PaginateMovies() {
const [variables, setVariables] = useState({
prevTitle: undefined,
nextTitle: undefined,
limit: resultsPerPage,
sortDirection: "TITLE_ASC",
});
const [firstTitle, setFirstTitle] = useState();
const { data, error, loading } = useQuery(PAGINATE_MOVIES, {
variables,
});
const [pagePreviousDisabled, setPagePreviousDisabled] = useState(true);
const [pageNextDisabled, setPageNextDisabled] = useState(false);
useEffect(() => {
if (data?.movies?.length && firstTitle === undefined) {
setFirstTitle(data.movies[0].title);
}
setPagePreviousDisabled(false);
if (data?.movies?.length < resultsPerPage) {
setPageNextDisabled(true);
setPagePreviousDisabled(false);
}
if (
variables.prevTitle === undefined ||
data?.movies[0]?.title === firstTitle
) {
setPagePreviousDisabled(true);
setPageNextDisabled(false);
}
}, [data, data?.movies?.length, firstTitle, variables.prevTitle]);
if (loading) {
return <div>loading</div>;
}
if (error) {
return <div>encountered an error: {error.message}</div>;
}
function goToNextPage() {
setVariables({
nextTitle: undefined,
prevTitle: data.movies[data.movies.length - 1].title,
limit: resultsPerPage,
sortDirection: "TITLE_ASC",
});
}
function goToPrevPage() {
setVariables({
nextTitle: data.movies[0].title,
prevTitle: undefined,
limit: resultsPerPage,
sortDirection: "TITLE_DESC",
});
}
const sorted = data.movies.sort((a, b) => {
const titleA = a.title.toUpperCase(); // ignore upper and lowercase
const titleB = b.title.toUpperCase(); // ignore upper and lowercase
if (titleA < titleB) {
return -1; // titleA comes first
}
if (titleA > titleB) {
return 1; // titleB comes first
}
});
return (
<div>
<h1>Movies</h1>
{data?.movies?.length ? (
sorted.map((movie) => (
<div key={movie._id}>
<h3>{movie.title}</h3>
<p>Year Published: {" " + movie.year}</p>
<br />
</div>
))
) : (
<p>No movies in system</p>
)}
<div>
<button disabled={pagePreviousDisabled} onClick={goToPrevPage}>
&larr; Previous Page
</button>
<button disabled={pageNextDisabled} onClick={goToNextPage}>
Next Page &rarr;
</button>
</div>
</div>
);
}

Realm GraphQL과 Apollo Client를 사용할 때 액세스 토큰은 부여된 후 30분 후에 만료됩니다. Realm 웹 SDK의 메서드를 사용하여 사용자 액세스 토큰을 새로 고칠 수 refreshAccessToken() 있습니다.

// Connect to your MongoDB Realm app
const app = new Realm.App(APP_ID);
// Gets a valid Realm user access token to authenticate requests
async function getValidAccessToken() {
// Guarantee that there's a logged in user with a valid access token
if (!app.currentUser) {
// If no user is logged in, log in an anonymous user. The logged in user will have a valid
// access token.
await app.logIn(Realm.Credentials.anonymous());
} else {
// An already logged in user's access token might be stale. Tokens must be refreshed after
// 30 minutes. To guarantee that the token is valid, we refresh the user's access token.
await app.currentUser.refreshAccessToken();
}
return app.currentUser.accessToken;
}
// Configure the ApolloClient to connect to your app's GraphQL endpoint
const client = new ApolloClient({
link: new HttpLink({
uri: `https://services.cloud.mongodb.com/api/client/v2.0/app/${APP_ID}/graphql`,
// We define a custom fetch handler for the Apollo client that lets us authenticate GraphQL requests.
// The function intercepts every Apollo HTTP request and adds an Authorization header with a valid
// access token before sending the request.
fetch: async (uri, options) => {
const accessToken = await getValidAccessToken();
options.headers.Authorization = `Bearer ${accessToken}`;
return fetch(uri, options);
},
}),
cache: new InMemoryCache(),
});

돌아가기

MongoDB 쿼리