Créer une application React qui utilise les API GraphQL d’AEM

Dans ce chapitre, vous découvrirez comment les API GraphQL d’AEM peuvent piloter l’expérience dans une application externe.

Une application React simple est utilisée pour interroger et afficher du contenu Équipe et Personne exposé par les API GraphQL d’AEM. L’utilisation de React n’est pas vraiment importante, et l’application externe consommatrice peut être écrite dans n’importe quel framework pour n’importe quelle plateforme.

Conditions préalables

Nous partons du principe que les étapes décrites dans les parties précédentes de ce tutoriel en plusieurs parties ont été terminées, ou que basic-tutorial-solution-content.zip est installé sur vos services de création et de publication d’AEM as a Cloud Service.

Les captures d’écran de l’IDE de ce chapitre proviennent de Visual Studio Code.

Les logiciels suivants doivent être installés :

Objectifs

Découvrez comment :

  • télécharger et démarrer l’exemple d’application React ;
  • interroger les points d’entrée GraphQL d’AEM à l’aide du SDK JS d’AEM Headless ;
  • interroger AEM concernant une liste d’équipes et de leurs personnes membres référencées ;
  • interroger AEM concernant les détails d’une personne membre de l’équipe.

Obtenir l’exemple d’application React

Dans ce chapitre, un exemple d’application React qui fait l’objet d’un bouchon est implémenté avec le code requis pour interagir avec l’API GraphQL d’AEM, et afficher les données de l’équipe et de la personne obtenues de leur part.

Le code source de l’exmple d’application React est disponible sur Github.com à l’adresse https://github.com/adobe/aem-guides-wknd-graphql/tree/main/basic-tutorial.

Pour obtenir l’application React :

  1. Clonez l’exemple d’application React GraphQL WKND à partir de Github.com.

    code language-shell
    $ cd ~/Code
    $ git clone git@github.com:adobe/aem-guides-wknd-graphql.git
    
  2. Accédez au fichier basic-tutorial et ouvrez-le dans votre IDE.

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

    Application React dans VSCode.

  3. Mettez à jour .env.development pour vous connecter au service de publication d’AEM as a Cloud Service.

    • Définissez la valeur de REACT_APP_HOST_URI sur votre URL d’instance de publication AEM as Cloud Service (par exemple, REACT_APP_HOST_URI=https://publish-p123-e456.adobeaemcloud.com) et la valeur de REACT_APP_AUTH_METHOD sur none.
    note note
    NOTE
    Assurez-vous que vous avez publié la configuration du projet, les modèles de fragment de contenu, les fragments de contenu créés, les points d’entrée GraphQL et les requêtes persistantes des étapes précédentes.
    Si vous avez effectué les étapes ci-dessus sur le SDK local de création d’AEM, vous pouvez définir la valeur de http://localhost:4502 et REACT_APP_AUTH_METHOD sur basic.
  4. À partir de la ligne de commande, accédez au fichier aem-guides-wknd-graphql/basic-tutorial.

  5. Démarrer l’application React

    code language-shell
    $ cd ~/Code/aem-guides-wknd-graphql/basic-tutorial
    $ npm install
    $ npm start
    
  6. L’application React démarre en mode de développement sur http://localhost:3000/. Les modifications apportées à l’application React tout au long du tutoriel sont répercutées immédiatement.

Application React partiellement implémentée.

IMPORTANT
Cette application React est partiellement implémentée. Suivez les étapes de ce tutoriel pour terminer la mise en œuvre. Les fichiers JavaScript qui doivent être implémentés comportent les commentaires suivants. Veillez à ajouter ou mettre à jour le code dans ces fichiers avec le code spécifié dans ce tutoriel.
//*********************************
// Tâche : implémentez ceci en suivant les étapes du tutoriel sur AEM Headless.
//*********************************

Anatomie de l’application React

L’exemple d’application React comporte trois parties principales :

  1. Le dossier src/api contient les fichiers utilisés pour effectuer des requêtes GraphQL à AEM.

    • src/api/aemHeadlessClient.js initialise et exporte le client AEM Headless utilisé pour communiquer avec AEM.
    • src/api/usePersistedQueries.js implémente les données de renvoi des hooks React personnalisés depuis GraphQL d’AEM vers les composants d’affichage Teams.js et Person.js.
  2. Le fichier src/components/Teams.js affiche une liste des équipes et de leurs personnes membres à l’aide d’une requête de liste.

  3. Le fichier src/components/Person.js affiche les détails d’une seule personne à l’aide d’une requête paramétrée à résultat unique.

Vérifier l’objet AEM Headless

Consultez le fichier aemHeadlessClient.js pour savoir comment créer l’objet AEMHeadless utilisé pour communiquer avec AEM.

  1. Ouvrez src/api/aemHeadlessClient.js.

  2. Vérifiez les lignes 1 à 40 :

    • L’importation de la déclaration AEMHeadless depuis le client AEM Headless pour JavaScript, ligne 11.

    • La configuration de l’autorisation en fonction de variables définies dans .env.development, lignes 14 à 22, et l’expression de fonction de flèche setAuthorization, lignes 31 à 40.

    • La configuration serviceUrl pour la configuration de proxy de développement inclue, ligne 27.

  3. Les lignes 42 à 49 sont les plus importantes, car elles instancient le client AEMHeadless et l’exportent pour l’utiliser dans l’application 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;

Implémenter pour exécuter les requêtes persistantes GraphQL d’AEM

Pour mettre en œuvre la fonction fetchPersistedQuery(..) générique pour exécuter les requêtes persistantes GraphQL AEM, ouvrez le fichier usePersistedQueries.js. La fonction fetchPersistedQuery(..) utilise la fonction aemHeadlessClient de l’objet runPersistedQuery() pour exécuter la requête de manière asynchrone avec un comportement basé sur la promesse.

Plus tard, le hook personnalisé useEffect de React appelle cette fonction pour récupérer des données spécifiques d’AEM.

  1. Dans src/api/usePersistedQueries.js, mettez à jour fetchPersistedQuery(..), ligne 35, avec le code ci-dessous.
/**
 * 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 };
}

Implémenter la fonctionnalité Équipes

Ensuite, développez la fonctionnalité pour afficher les équipes et leurs personnes membres sur la vue principale de l’application React. Cette fonctionnalité requiert :

  • Un nouveau hook personnalisé React useEffect dans src/api/usePersistedQueries.js qui appelle la requête persistante my-project/all-teams, renvoyant une liste de fragments de contenu d’équipe dans AEM.
  • Un composant React sous src/components/Teams.js qui appelle le nouveau hook personnalisé React useEffect et effectue le rendu des données des équipes.

Une fois l’opération terminée, la vue principale de l’application est renseignée avec les données de l’équipe provenant d’AEM.

Vue Équipes.

Étapes

  1. Ouvrez src/api/usePersistedQueries.js.

  2. Localiser la fonction useAllTeams()

  3. Pour créer un hook useEffect qui appelle la requête persistante my-project/all-teams via fetchPersistedQuery(..), ajoutez le code suivant. Le hook renvoie également uniquement les données appropriées de la réponse GraphQL d’AEM à data?.teamList?.items, ce qui permet aux composants de la vue React d’être indépendants des structures JSON parentes.

    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. Ouvrez src/components/Teams.js.

  5. Dans le composant React Teams, récupérez la liste des équipes d’AEM à l’aide du 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. Effectuez la validation des données basées sur la vue en affichant un message d’erreur ou un indicateur de chargement en fonction des données renvoyées.

    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. Enfin, effectuez le rendu des données des équipes. Chaque équipe renvoyée à partir de la requête GraphQL est rendue à l’aide du sous-composant React Team fourni.

    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;
    

Implémenter la fonctionnalité Personne

Une fois la fonctionnalité Équipes implémentée, implémentez la fonctionnalité permettant de gérer l’affichage sur les détails d’un ou d’une membre de l’équipe, ou d’une personne.

Cette fonctionnalité requiert :

  • Un nouveau hook personnalisé React useEffect dans src/api/usePersistedQueries.js qui appelle la requête persistante paramétrée my-project/person-by-name, et renvoie un enregistrement de personne unique.

  • Un composant React sous src/components/Person.js qui utilise le nom complet d’une personne comme paramètre de requête, appelle le nouveau hook React personnalisé useEffect et effectue le rendu des données de la personne.

Une fois l’opération terminée, la sélection du nom d’une personne dans la vue Équipes affiche la vue de la personne.

Personne.

  1. Ouvrez src/api/usePersistedQueries.js.

  2. Localiser la fonction usePersonByName(fullName)

  3. Pour créer un hook useEffect qui appelle la requête persistante my-project/all-teams via fetchPersistedQuery(..), ajoutez le code suivant. Le hook renvoie également uniquement les données appropriées de la réponse GraphQL d’AEM à data?.teamList?.items, ce qui permet aux composants de la vue React d’être indépendants des structures JSON parentes.

    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. Ouvrez src/components/Person.js.

  5. Dans le composant React Person, analysez le paramètre d’itinéraire fullName, et récupérez les données de la personne depuis AEM à l’aide du 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. Effectuez la validation des données basée sur la vue, affichant un message d’erreur ou un indicateur de chargement en fonction des données renvoyées.

    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. Enfin, effectuez le rendu des données de la personne.

    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;
    

Essayer l’application

Vérifiez l’application http://localhost:3000/ et cliquez sur les liens des Membres. Vous pouvez également ajouter d’autres équipes et/ou membres à l’équipe Alpha en ajoutant des fragments de contenu dans AEM.

IMPORTANT
Pour vérifier les modifications apportées à votre mise en œuvre ou si vous ne parvenez pas à faire fonctionner l’application après les modifications ci-dessus, reportez-vous à la solution basic-tutorial.

Ce qui se passe

Dans le navigateur, ouvrez Outils de développement  > Réseau et Filtrez pour la requête all-teams. Remarquez que la requête /graphql/execute.json/my-project/all-teams de l’API GraphQL est faite par rapport à http://localhost:3000 et NON par rapport à la valeur de REACT_APP_HOST_URI, par exemple <https://publish-pxxx-exxx.adobeaemcloud.com. Les requêtes sont effectuées par rapport au domaine de l’application React, car la configuration du proxy est activée à l’aide du module http-proxy-middleware.

Requête de l’API GraphQL via proxy.

Vérifiez le fichier principal ../setupProxy.js et dans les fichiers ../proxy/setupProxy.auth.**.js, notez la manière dont les chemins d’accès /content et /graphql sont traités par proxy et marqués comme n’étant pas une ressource statique.

module.exports = function(app) {
  app.use(
    ['/content', '/graphql'],
  ...

Cependant, le proxy local n’est pas une option appropriée pour le déploiement en production et vous trouverez plus de détails dans la section Déploiement en production.

Félicitations ! congratulations

Félicitations. Vous avez réussi à créer l’application React pour utiliser et afficher les données à partir des API GraphQL d’AEM dans le cadre d’un tutoriel de base.

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