Creare un’app React che utilizza le API GraphQL dell’AEM
In questo capitolo, scopri come le API GraphQL dell’AEM possono stimolare l’esperienza in un’applicazione esterna.
Viene utilizzata una semplice app React per eseguire query e visualizzare il contenuto di Team e Persona esposto dalle API GraphQL dell'AEM. L’utilizzo di React è in gran parte poco importante e l’applicazione esterna che lo utilizza potrebbe essere scritta in qualsiasi framework per qualsiasi piattaforma.
Prerequisiti
Si presume che i passaggi descritti nelle parti precedenti di questo tutorial in più parti siano stati completati o che basic-tutorial-solution.content.zip sia installato nei servizi AEM as a Cloud Service Author e Publish.
Le schermate IDE in questo capitolo provengono da Visual Studio Code
È necessario installare il seguente software:
Obiettivi
Scopri come:
- Scarica e avvia l’app React di esempio
- Eseguire query sugli endpoint GraphQL dell'AEM utilizzando l'SDK JS headless dell'AEM
- Query AEM per un elenco di team e dei relativi membri di riferimento
- Eseguire una query AEM per i dettagli di un membro del team
Scarica l’app React di esempio
In questo capitolo, viene implementata un’app React di esempio sottoposta a stubbed-out con il codice necessario per interagire con l’API GraphQL dell’AEM e visualizzare i dati di team e persone ottenuti da tali API.
Il codice sorgente dell'app React di esempio è disponibile sul sito Github.com all'indirizzo https://github.com/adobe/aem-guides-wknd-graphql/tree/main/basic-tutorial
Per ottenere l’app React:
-
Clona l'app WKND GraphQL React di esempio da Github.com.
code language-shell $ cd ~/Code $ git clone git@github.com:adobe/aem-guides-wknd-graphql.git
-
Passare alla cartella
basic-tutorial
e aprirla nell'IDE.code language-shell $ cd ~/Code/aem-guides-wknd-graphql/basic-tutorial $ code .
-
Aggiorna
.env.development
per la connessione al servizio AEM as a Cloud Service Publish.- Imposta il valore di
REACT_APP_HOST_URI
come URL Publish dell'AEM as a Cloud Service (ad es.REACT_APP_HOST_URI=https://publish-p123-e456.adobeaemcloud.com
) e il valore diREACT_APP_AUTH_METHOD
innone
note note NOTE Assicurati di aver pubblicato la configurazione del progetto, i modelli per frammenti di contenuto, i frammenti di contenuto creati, gli endpoint di GraphQL e le query persistenti dei passaggi precedenti. Se hai eseguito i passaggi precedenti sull'SDK dell'autore AEM locale, puoi puntare a http://localhost:4502
e al valore diREACT_APP_AUTH_METHOD
abasic
. - Imposta il valore di
-
Dalla riga di comando, passare alla cartella
aem-guides-wknd-graphql/basic-tutorial
-
Avviare l’app React
code language-shell $ cd ~/Code/aem-guides-wknd-graphql/basic-tutorial $ npm install $ npm start
-
L'app React viene avviata in modalità di sviluppo il http://localhost:3000/. Le modifiche apportate all’app React durante l’esercitazione vengono riportate immediatamente.
Anatomia dell’app React
L’app React di esempio è composta da tre parti principali:
-
La cartella
src/api
contiene i file utilizzati per eseguire query GraphQL all'AEM.src/api/aemHeadlessClient.js
inizializza ed esporta il client headless AEM utilizzato per comunicare con AEMsrc/api/usePersistedQueries.js
implementa hook React personalizzati per restituire dati da GraphQL AEM ai componenti di visualizzazioneTeams.js
ePerson.js
.
-
Nel file
src/components/Teams.js
viene visualizzato un elenco di team e dei relativi membri tramite una query elenco. -
Nel file
src/components/Person.js
vengono visualizzati i dettagli di una singola persona mediante una query con parametri a risultato singolo.
Esaminare l'oggetto AEMHeadless
Esaminare il file aemHeadlessClient.js
per informazioni su come creare l'oggetto AEMHeadless
utilizzato per comunicare con AEM.
-
Apri
src/api/aemHeadlessClient.js
. -
Rivedi le righe da 1 a 40:
-
Dichiarazione di importazione di
AEMHeadless
dal client headless AEM per JavaScript, riga 11. -
Configurazione dell'autorizzazione basata sulle variabili definite in
.env.development
, riga 14-22, e sull'espressione della funzione frecciasetAuthorization
, riga 31-40. -
Configurazione di
serviceUrl
per la configurazione di development proxy inclusa, riga 27.
-
-
Le righe da 42 a 49 sono le più importanti, in quanto creano un'istanza del client
AEMHeadless
e lo esportano per l'utilizzo in tutta l'app React.
// Initialize the AEM Headless Client and export it for other files to use
const aemHeadlessClient = new AEMHeadless({
serviceURL: serviceURL,
endpoint: REACT_APP_GRAPHQL_ENDPOINT,
auth: setAuthorization(),
});
export default aemHeadlessClient;
Implementazione per eseguire query persistenti AEM GraphQL
Per implementare la funzione generica fetchPersistedQuery(..)
per eseguire le query persistenti di GraphQL AEM, aprire il file usePersistedQueries.js
. La funzione fetchPersistedQuery(..)
utilizza la funzione runPersistedQuery()
dell'oggetto aemHeadlessClient
per eseguire query in modo asincrono, in base a promesse.
Successivamente, l'hook personalizzato React useEffect
chiama questa funzione per recuperare dati specifici dall'AEM.
- In
src/api/usePersistedQueries.js
updatefetchPersistedQuery(..)
, riga 35, con il codice seguente.
/**
* Private, shared function that invokes the AEM Headless client.
*
* @param {String} persistedQueryName the fully qualified name of the persisted query
* @param {*} queryParameters an optional JavaScript object containing query parameters
* @returns the GraphQL data or an error message
*/
async function fetchPersistedQuery(persistedQueryName, queryParameters) {
let data;
let err;
try {
// AEM GraphQL queries are asynchronous, either await their return or use Promise-based syntax
const response = await aemHeadlessClient.runPersistedQuery(
persistedQueryName,
queryParameters
);
// The GraphQL data is stored on the response's data field
data = response?.data;
} catch (e) {
// An error occurred, return the error messages
err = e
.toJSON()
?.map((error) => error.message)
?.join(", ");
console.error(e.toJSON());
}
// Return the GraphQL and any errors
return { data, err };
}
Implementare le funzionalità dei team
Quindi, crea la funzionalità per visualizzare i team e i relativi membri nella visualizzazione principale dell’app React. Questa funzionalità richiede:
- Nuovo hook useEffect personalizzato di React in
src/api/usePersistedQueries.js
che richiama la query persistentemy-project/all-teams
, restituendo un elenco di frammenti di contenuto team in AEM. - Un componente React in
src/components/Teams.js
che richiama il nuovo hook personalizzato di ReactuseEffect
ed esegue il rendering dei dati dei team.
Una volta completata, la vista principale dell’app si popola con i dati dei team provenienti dall’AEM.
Passaggi
-
Apri
src/api/usePersistedQueries.js
. -
Individua la funzione
useAllTeams()
-
Per creare un hook
useEffect
che richiama la query persistentemy-project/all-teams
tramitefetchPersistedQuery(..)
, aggiungere il codice seguente. L'hook restituisce inoltre solo i dati rilevanti della risposta GraphQL dell'AEM indata?.teamList?.items
, consentendo ai componenti della visualizzazione React di essere agnostici delle strutture JSON padre.code language-javascript /** * Custom hook that calls the 'my-project/all-teams' persisted query. * * @returns an array of Team JSON objects, and array of errors */ export function useAllTeams() { const [teams, setTeams] = useState(null); const [error, setError] = useState(null); // Use React useEffect to manage state changes useEffect(() => { async function fetchData() { // Call the AEM GraphQL persisted query named "my-project/all-teams" const { data, err } = await fetchPersistedQuery( "my-project/all-teams" ); // Sets the teams variable to the list of team JSON objects setTeams(data?.teamList?.items); // Set any errors setError(err); } // Call the internal fetchData() as per React best practices fetchData(); }, []); // Returns the teams and errors return { teams, error }; }
-
Apri
src/components/Teams.js
-
Nel componente React
Teams
, recupera l'elenco dei team dall'AEM utilizzando l'hookuseAllTeams()
.code language-javascript import { useAllTeams } from "../api/usePersistedQueries"; ... function Teams() { // Get the Teams data from AEM using the useAllTeams const { teams, error } = useAllTeams(); ... }
-
Eseguire la convalida dei dati basati sulla visualizzazione, visualizzando un messaggio di errore o caricando un indicatore basato sui dati restituiti.
code language-javascript function Teams() { const { teams, error } = useAllTeams(); // Handle error and loading conditions if (error) { // If an error ocurred while executing the GraphQL query, display an error message return <Error errorMessage={error} />; } else if (!teams) { // While the GraphQL request is executing, show the Loading indicator return <Loading />; } ... }
-
Infine, esegui il rendering dei dati dei team. Viene eseguito il rendering di ogni team restituito dalla query GraphQL utilizzando il sottocomponente React
Team
fornito.code language-javascript import React from "react"; import { Link } from "react-router-dom"; import { useAllTeams } from "../api/usePersistedQueries"; import Error from "./Error"; import Loading from "./Loading"; import "./Teams.scss"; function Teams() { const { teams, error } = useAllTeams(); // Handle error and loading conditions if (error) { return <Error errorMessage={error} />; } else if (!teams) { return <Loading />; } // Teams have been populated by AEM GraphQL query. Display the teams. return ( <div className="teams"> {teams.map((team, index) => { return <Team key={index} {...team} />; })} </div> ); } // Render single Team function Team({ title, shortName, description, teamMembers }) { // Must have title, shortName and at least 1 team member if (!title || !shortName || !teamMembers) { return null; } return ( <div className="team"> <h2 className="team__title">{title}</h2> <p className="team__description">{description.plaintext}</p> <div> <h4 className="team__members-title">Members</h4> <ul className="team__members"> {/* Render the referenced Person models associated with the team */} {teamMembers.map((teamMember, index) => { return ( <li key={index} className="team__member"> <Link to={`/person/${teamMember.fullName}`}> {teamMember.fullName} </Link> </li> ); })} </ul> </div> </div> ); } export default Teams;
Implementare le funzionalità della persona
Con la funzionalità Team completata, implementiamo la funzionalità per gestire la visualizzazione dei dettagli di un membro del team o di una persona.
Questa funzionalità richiede:
-
Un nuovo hook useEffect personalizzato di React in
src/api/usePersistedQueries.js
che richiama la query persistente con parametrimy-project/person-by-name
e restituisce un singolo record persona. -
Un componente React in
src/components/Person.js
che utilizza il nome completo di una persona come parametro di query, richiama il nuovo hook personalizzato ReactuseEffect
ed esegue il rendering dei dati della persona.
Una volta completato, selezionando il nome di una persona nella vista Team, viene riprodotta la vista della persona.
-
Apri
src/api/usePersistedQueries.js
. -
Individua la funzione
usePersonByName(fullName)
-
Per creare un hook
useEffect
che richiama la query persistentemy-project/all-teams
tramitefetchPersistedQuery(..)
, aggiungere il codice seguente. L'hook restituisce inoltre solo i dati rilevanti della risposta GraphQL dell'AEM indata?.teamList?.items
, consentendo ai componenti della visualizzazione React di essere agnostici delle strutture JSON padre.code language-javascript /** * Calls the 'my-project/person-by-name' and provided the {fullName} as the persisted query's `name` parameter. * * @param {String!} fullName the full * @returns a JSON object representing the person */ export function usePersonByName(fullName) { const [person, setPerson] = useState(null); const [errors, setErrors] = useState(null); useEffect(() => { async function fetchData() { // The key is the variable name as defined in the persisted query, and may not match the model's field name const queryParameters = { name: fullName }; // Invoke the persisted query, and pass in the queryParameters object as the 2nd parameter const { data, err } = await fetchPersistedQuery( "my-project/person-by-name", queryParameters ); if (err) { // Capture errors from the HTTP request setErrors(err); } else if (data?.personList?.items?.length === 1) { // Set the person data after data validation setPerson(data.personList.items[0]); } else { // Set an error if no person could be found setErrors(`Cannot find person with name: ${fullName}`); } } fetchData(); }, [fullName]); return { person, errors }; }
-
Apri
src/components/Person.js
-
Nel componente React
Person
, analizzare il parametro di routefullName
e recuperare i dati della persona dall'AEM utilizzando l'hookusePersonByName(fullName)
.code language-javascript import { useParams } from "react-router-dom"; import { usePersonByName } from "../api/usePersistedQueries"; ... function Person() { // Read the person's `fullName` which is the parameter used to query for the person's details const { fullName } = useParams(); // Query AEM for the Person's details, using the `fullName` as the filtering parameter const { person, error } = usePersonByName(fullName); ... }
-
Eseguire la convalida dei dati basata sulla visualizzazione, visualizzando un messaggio di errore o caricando un indicatore basato sui dati restituiti.
code language-javascript function Person() { // Read the person's `fullName` which is the parameter used to query for the person's details const { fullName } = useParams(); // Query AEM for the Person's details, using the `fullName` as the filtering parameter const { person, error } = usePersonByName(fullName); // Handle error and loading conditions if (error) { return <Error errorMessage={error} />; } else if (!person) { return <Loading />; } ... }
-
Infine, esegui il rendering dei dati della persona.
code language-javascript import React from "react"; import { useParams } from "react-router-dom"; import { usePersonByName } from "../api/usePersistedQueries"; import { mapJsonRichText } from "../utils/renderRichText"; import Error from "./Error"; import Loading from "./Loading"; import "./Person.scss"; function Person() { // Read the person's `fullName` which is the parameter used to query for the person's details const { fullName } = useParams(); // Query AEM for the Person's details, using the `fullName` as the filtering parameter const { person, error } = usePersonByName(fullName); // Handle error and loading conditions if (error) { return <Error errorMessage={error} />; } else if (!person) { return <Loading />; } // Render the person data return ( <div className="person"> <img className="person__image" src={process.env.REACT_APP_HOST_URI+person.profilePicture._path} alt={person.fullName} /> <div className="person__occupations"> {person.occupation.map((occupation, index) => { return ( <span key={index} className="person__occupation"> {occupation} </span> ); })} </div> <div className="person__content"> <h1 className="person__full-name">{person.fullName}</h1> <div className="person__biography"> {/* Use this utility to transform multi-line text JSON into HTML */} {mapJsonRichText(person.biographyText.json)} </div> </div> </div> ); } export default Person;
Prova l’app
Rivedi l'app http://localhost:3000/ e fai clic sui collegamenti Membri. Inoltre, puoi aggiungere più team e/o membri all’Alpha Team aggiungendo Frammenti di contenuto all’AEM.
Sotto il cappuccio
Apri Strumenti per sviluppatori > Rete e Filtro del browser per la richiesta all-teams
. Si noti che la richiesta API di GraphQL /graphql/execute.json/my-project/all-teams
viene effettuata per http://localhost:3000
e NOT rispetto al valore di REACT_APP_HOST_URI
, ad esempio <https://publish-pxxx-exxx.adobeaemcloud.com
. Le richieste vengono effettuate sul dominio dell'app React perché la configurazione proxy è abilitata utilizzando il modulo http-proxy-middleware
.
Rivedi il file ../setupProxy.js
principale e nei file ../proxy/setupProxy.auth.**.js
osserva come /content
e /graphql
percorsi sono proxy e indica che non si tratta di una risorsa statica.
module.exports = function(app) {
app.use(
['/content', '/graphql'],
...
L'utilizzo del proxy locale non è un'opzione adatta per la distribuzione di produzione. Ulteriori dettagli sono disponibili nella sezione Distribuzione di produzione.
Congratulazioni. congratulations
Congratulazioni Hai creato correttamente l’app React per utilizzare e visualizzare dati dalle API GraphQL dell’AEM come parte di un’esercitazione di base.