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:

  1. 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
    
  2. Passare alla cartella basic-tutorial e aprirla nell'IDE.

    code language-shell
    $ cd ~/Code/aem-guides-wknd-graphql/basic-tutorial
    $ code .
    

    App React in VSCode

  3. 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 di REACT_APP_AUTH_METHOD in none
    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 di REACT_APP_AUTH_METHOD a basic.
  4. Dalla riga di comando, passare alla cartella aem-guides-wknd-graphql/basic-tutorial

  5. Avviare l’app React

    code language-shell
    $ cd ~/Code/aem-guides-wknd-graphql/basic-tutorial
    $ npm install
    $ npm start
    
  6. 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.

App React parzialmente implementata

IMPORTANT
Questa app React è parzialmente implementata. Segui i passaggi descritti in questo tutorial per completare l’implementazione. I file JavaScript che richiedono un lavoro di implementazione presentano il seguente commento. Accertati di aggiungere/aggiornare il codice in tali file con il codice specificato in questa esercitazione.
// ​**​**​**​**​**​**​**​**​**​**​**​**​**​***
// TODO Per implementarlo, segui i passaggi descritti nell’esercitazione su AEM headless
// ​**​**​**​**​**​**​**​**​**​**​**​**​**​***

Anatomia dell’app React

L’app React di esempio è composta da tre parti principali:

  1. 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 AEM
    • src/api/usePersistedQueries.js implementa hook React personalizzati per restituire dati da GraphQL AEM ai componenti di visualizzazione Teams.js e Person.js.
  2. Nel file src/components/Teams.js viene visualizzato un elenco di team e dei relativi membri tramite una query elenco.

  3. 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.

  1. Apri src/api/aemHeadlessClient.js.

  2. 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 freccia setAuthorization, riga 31-40.

    • Configurazione di serviceUrl per la configurazione di development proxy inclusa, riga 27.

  3. 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.

  1. In src/api/usePersistedQueries.js update fetchPersistedQuery(..), 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 persistente my-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 React useEffect 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.

Visualizzazione team

Passaggi

  1. Apri src/api/usePersistedQueries.js.

  2. Individua la funzione useAllTeams()

  3. Per creare un hook useEffect che richiama la query persistente my-project/all-teams tramite fetchPersistedQuery(..), aggiungere il codice seguente. L'hook restituisce inoltre solo i dati rilevanti della risposta GraphQL dell'AEM in data?.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 };
    }
    
  4. Apri src/components/Teams.js

  5. Nel componente React Teams, recupera l'elenco dei team dall'AEM utilizzando l'hook useAllTeams().

    code language-javascript
    import { useAllTeams } from "../api/usePersistedQueries";
    ...
    function Teams() {
      // Get the Teams data from AEM using the useAllTeams
      const { teams, error } = useAllTeams();
      ...
    }
    
  6. 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 />;
      }
      ...
    }
    
  7. 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 parametri my-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 React useEffect 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.

Persona

  1. Apri src/api/usePersistedQueries.js.

  2. Individua la funzione usePersonByName(fullName)

  3. Per creare un hook useEffect che richiama la query persistente my-project/all-teams tramite fetchPersistedQuery(..), aggiungere il codice seguente. L'hook restituisce inoltre solo i dati rilevanti della risposta GraphQL dell'AEM in data?.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 };
    }
    
  4. Apri src/components/Person.js

  5. Nel componente React Person, analizzare il parametro di route fullName e recuperare i dati della persona dall'AEM utilizzando l'hook usePersonByName(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);
      ...
    }
    
  6. 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 />;
      }
      ...
    }
    
  7. 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.

IMPORTANT
Per verificare le modifiche apportate all'implementazione o se non riesci a far funzionare l'app dopo le modifiche di cui sopra, fai riferimento al ramo della soluzione basic-tutorial.

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.

Richiesta API GraphQL tramite Proxy

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.

recommendation-more-help
e25b6834-e87f-4ff3-ba56-4cd16cdfdec4