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
- Paginate Data
- Atualizar tokens de acesso
GraphQL estĆ” obsoleto. Saiba mais.
VisĆ£o geral
VocĆŖ pode usar o cliente Apollo para se conectar Ć GraphQL API exposta do seu aplicativo Realm a partir de um aplicaĆ§Ć£o 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 Atlas App Services backend do . Ele usa a collection sample_mflix.movies
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.
Configurar o cliente Apollo
Instalar dependĆŖncias
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
Criar um cliente Apollo GraphQL
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(), });
Configurar autenticaĆ§Ć£o de usuĆ”rio
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(), });
Adicione o cliente Apollo ao seu aplicativo
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> );
Executar queries e mutaƧƵes
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 Atlas App Services backend do . Os ganchos chamam a consulta e mutaĆ§Ć£o no client
objeto fornecido.
Executar uma consulta
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 uma chamada de respostas que executa novamente a consulta sempre que vocĆŖ a chama.
useLazyQuery() retorna uma funĆ§Ć£o chamada de respostas 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} />; }
Execute uma mutaĆ§Ć£o
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 que mapeia para variĆ”veis 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> ); }
Paginate Data
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}> ← Previous Page </button> <button disabled={pageNextDisabled} onClick={goToNextPage}> Next Page → </button> </div> </div> ); }
Atualizar tokens de acesso
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(), });