Menu Docs

Página inicial do DocsDesenvolver aplicaçõesAtlas Device SDKs

Cliente Apollo (React) - SDK da Web

Nesta página

  • Visão geral
  • Configurar o cliente Apollo
  • Instalar dependências
  • Importar dependências
  • Criar um cliente Apollo GraphQL
  • Configurar autenticação de usuário
  • Adicione o cliente Apollo ao seu aplicativo
  • Executar queries e mutações
  • Executar uma consulta
  • Execute uma mutação
  • Paginar dados
  • Atualizar tokens de acesso

Você pode usar o Cliente Apollo para se conectar à API GraphQL exposta do seu aplicativo React. O Cliente Apollo executa consultas e mutações, mantém um cache de dados no lado do cliente e se integra ao seu aplicativo com componentes e ganchos React idiomáticos.

Observação

Veja um aplicativo de demonstração funcional

Confira o Realm GraphQL - Apollo (React) repositório no GitHub para ver um aplicativo React & Apollo totalmente configurado que está pronto para se conectar ao seu próprio backend do Atlas App Services. Ele usa a sample_mflix.movies coleção incluída nos conjuntos de dados de exemplo do MongoDB Atlas .

Se você não quiser clonar o repositório, o aplicativo de demonstração também estará disponível no navegador no Realm GraphQL CodeSandbox.

1

Como em qualquer projeto do Realm, será necessário instalar o Realm Web SDK para autenticar usuários e solicitações.

npm install realm-web

A Apollo agrupa os componentes centrais necessários para criar um cliente em um pacote chamado @apollo/cliente. Também requer o pacote graphql para analisar queries GraphQL.

npm install @apollo/client graphql
2

Importe as dependências necessárias de realm-web e @apollo/client para criar seu cliente Apollo GraphQL e adicionar autenticação com o Realm.

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

Crie um novo objeto ApolloClient que aponte para o ponto de extremidade da API GraphQL do seu aplicativo Realm. Você gera a URL do ponto com base na ID do aplicativo do Realm ou a encontra na página GraphQL da IU do Realm.

// 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

O ApolloClient está configurado para enviar solicitações ao seu aplicativo. No entanto, todas as solicitações do Realm GraphQL devem incluir um token de acesso de usuário válido para autenticar as solicitações. Portanto, no momento, qualquer operação enviada pelo Apollo falhará. Os tokens de acesso expiram após 30 minutos e precisam ser atualizados.

Para autenticar solicitações, você precisa adicionar um cabeçalho de autorização com um token de acesso de usuário do Realm válido a cada solicitação do GraphQ.

Você pode autenticar um usuário e obter seu token de acesso com o Realm Web SDK. O objeto do Apollo HttpLink permite adicionar cabeçalhos personalizados a cada solicitação ao definir uma função de fetch personalizada.

// 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

O objeto Apollo client agora está configurado para enviar solicitações autenticadas do GraphQL para seu back-end do App Services. Tudo o que resta a fazer é disponibilizá-lo para o resto do seu aplicativo React.

O pacote @apollo/client exporta um componente ApolloProvider que disponibiliza o client para qualquer gancho Apollo que você chame de componentes secundários. Envolva seu aplicativo em um ApolloProvider e passe o objeto client para o provedor.

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

O pacote @apollo/client inclui um conjunto de ganchos React declarativos que conectam seus componentes à API GraphQL e gerenciam a execução de consultas e mutações.

Para definir consultas e mutações que você pode passar para os ganchos, instale graphql-tag:

npm install graphql-tag

Importe os ganchos relevantes e o construtor de consulta GraphQL na parte superior do arquivo onde você os está usando.

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

Observação

Os ganchos Apollo devem ter um ApolloProvider

Os componentes que chamam os ganchos de consulta e mutação devem ser descendentes do ApolloProvider que você configurou para o backend do App Services. Os ganchos chamam a consulta e mutação no client objeto fornecido.

O cliente Apollo inclui dois ganchos para executar consultas. Os ganchos aceitam parâmetros idênticos, mas diferem quando executam a consulta:

  • useQuery() é executado automaticamente quando seu componente é montado. Ele também retorna um retorno de chamada que executa novamente a consulta sempre que você a chama.

  • useLazyQuery() retorna uma função de retorno de chamada que executa a consulta sempre que você a chama. Ele não executa a consulta na montagem do componente.

Ambos os ganchos aceitam uma definição de consulta e opções adicionais, incluindo variables que Apollo passa para a consulta. Ambos também retornam informações sobre o status de execução atual da consulta e os dados retornados da execução mais recente.

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} />;
}

O método useMutation() hook aceita uma definição de mutação e um objeto de configuração opcional. A opção mais comum que você precisará passar é um variables objeto do que mapeia para variáveis de GraphQL na definição de mutação.

O gancho retorna vários objetos em uma matriz:

  • uma função de retorno de chamada que executa a mutação

  • um objeto que inclui informações sobre o status de execução da mutação e os dados retornados da execução mais recente.

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>
);
}

Você pode paginar dados em suas consultas com os tipos fornecidos pelo esquema GraphQL gerado pela API. Você pode paginar dados com o cliente Apollo GraphQL usando os ganchos useQuery() e useLazyQueryHook().

A API Atlas GraphQL não tem um operador offset, como a documentação GraphQL recomenda para paginação.

O exemplo abaixo usa o hook useQuery() e uma query GraphQL que pode fazer query de dados em order crescente e decrescente, dependendo das variáveis que você passar para ela.

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>
);
}

Ao usar o Realm GraphQL e um cliente Apollo, os tokens de acesso expiram 30 minutos após serem concedidos. Você pode atualizar tokens de acesso do usuário com o método refreshAccessToken() do Realm Web SDK.

// 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(),
});
← Consulta MongoDB - Web SDK