Docs Menu
Docs Home
/ /
Atlas Device SDK
/

Apollo Client(React) - Web SDK

項目一覧

  • Overview
  • Apollo Client を設定する
  • 依存関係のインストール
  • 依存関係のインポート
  • Apollo GraphQL クライアントの作成
  • ユーザー認証を設定する
  • Apollo Client をアプリに追加する
  • クエリとミューテーションの実行
  • クエリの実行
  • ミューテーションを実行する
  • Paginate Data
  • アクセス トークンを更新

Apollo Client を使用できます を使用して、 Realmアプリの 公開GraphQL API にReactアプリケーションから接続します。 Apollo Client は、クエリとミューテーションを実行し、クライアント側のデータキャッシュを維持し、慣用的なReactコンポーネントとフックを使用してアプリに統合します。

注意

動作中のデモアプリケーションを見る

の確認 RealmGraphQL- Apollo(React ) のリポジトリを参照して、独自のGithubReact バックエンドに接続する準備ができている完全に設定された & ApolloAtlas App Services アプリケーションを確認してください。MongoDB Atlasサンプル データ セットに含まれる sample_mflix.moviesコレクションを使用します。

リポジトリをクローンしたくない場合は、 Realm GraphQL CodeSandbox のブラウザ内でデモ アプリケーションも利用できます。

1

どの Realm プロジェクトと同様に、 Realm Web SDK をインストールする必要があります ユーザーとリクエストを認証するため。

npm install realm-web

Apollo は、クライアントを作成するために必要なコア コンポーネントを @apollo/client というパッケージにバンドルします。 。GraphQLGraphQLも必要です クエリを解析するためのパッケージ。

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

新しい ApolloClient を作成する Realm アプリの GraphQL API エンドポイントを示す オブジェクト。Realm App 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 分後に期限切れになり、更新する必要があります。

リクエストを認証するには、有効な Realm ユーザー アクセス トークンを各GraphQLリクエストに追加する必要があります。

Realm Web 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

Apollo clientオブジェクトは、認証された GraphQL リクエストを App Services バックエンドに送信するように構成されました。 残りの操作は、React アプリケーションの残りの部分で使用できるようにすることです。

@apollo/clientパッケージはApolloProviderコンポーネントをエクスポートします。これにより、子コンポーネントから呼び出す任意の Apollo フックでclientを使用できるようになります。 アプリをApolloProviderでラップし、 clientオブジェクトをプロバイダーに渡します。

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

@apollo/clientパッケージには、コンポーネントを GraphQL API に接続し、クエリとミューテーションの実行を処理する宣言型の React フックのセットが含まれています。

フックに渡すことができるクエリとミューテーションを定義するには、 graphql タグ をインストールします。

npm install graphql-tag

関連するフックと GraphQL クエリ コンストラクターを、それらを使用しているファイルの上部にインポートします。

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

注意

Apollo フックには ApolloProvider が必要です

クエリとミューテーション フックを呼び出すコンポーネントは、 ApolloProvider の子孫である必要があります App Services バックエンド用に構成したフックは クエリ を呼び出します および ミューテーション 提供された オブジェクトのメソッド。client

Apollo Client には、クエリを実行するための 2 つのフックが含まれています。 フックは同一のパラメーターを受け入れますが、クエリを実行するタイミングは異なります。

  • useQuery() は、 コンポーネントがマウントされると自動的に実行されます。また、クエリを呼び出すたびにクエリを再実行するコールバックも返します。

  • useLazyQuery() は、呼び出すたびにクエリを実行するコールバック関数を返します。コンポーネント マウントではクエリは実行されません。

どちらのフックも、Apollo がクエリに渡すvariablesなどのクエリ定義と追加のオプションを受け入れます。 また、クエリの現在の実行状態に関する情報と最新の実行から返されたデータも返します。

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() フックは、ミューテーション定義とオプションの構成オブジェクトを受け入れます。渡す必要がある最も一般的なオプションは、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 スキーマによって提供されるタイプを使用して、クエリのデータをページ分割できます。 フックと フックを使用して、Apollo GraphQL クライアントでデータをページ分割できます。useQuery()useLazyQueryHook()

Atlas GraphQL API には、 GraphQL offsetのドキュメントがページ分割を推奨して いるように、 演算子 はありません 。

次の例では、 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 クライアントを使用する場合、アクセス トークンは付与後 30 分で期限切れになります。 Realm Web 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 のクエリ