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 :
-
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
-
Accédez au fichier
basic-tutorial
et ouvrez-le dans votre IDE.code language-shell $ cd ~/Code/aem-guides-wknd-graphql/basic-tutorial $ code .
-
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 deREACT_APP_AUTH_METHOD
surnone
.
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
etREACT_APP_AUTH_METHOD
surbasic
. - Définissez la valeur de
-
À partir de la ligne de commande, accédez au fichier
aem-guides-wknd-graphql/basic-tutorial
. -
Démarrer l’application React
code language-shell $ cd ~/Code/aem-guides-wknd-graphql/basic-tutorial $ npm install $ npm start
-
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.
Anatomie de l’application React
L’exemple d’application React comporte trois parties principales :
-
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’affichageTeams.js
etPerson.js
.
-
Le fichier
src/components/Teams.js
affiche une liste des équipes et de leurs personnes membres à l’aide d’une requête de liste. -
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.
-
Ouvrez
src/api/aemHeadlessClient.js
. -
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èchesetAuthorization
, lignes 31 à 40. -
La configuration
serviceUrl
pour la configuration de proxy de développement inclue, ligne 27.
-
-
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.
- Dans
src/api/usePersistedQueries.js
, mettez à jourfetchPersistedQuery(..)
, 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 persistantemy-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é ReactuseEffect
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.
Étapes
-
Ouvrez
src/api/usePersistedQueries.js
. -
Localiser la fonction
useAllTeams()
-
Pour créer un hook
useEffect
qui appelle la requête persistantemy-project/all-teams
viafetchPersistedQuery(..)
, 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 }; }
-
Ouvrez
src/components/Teams.js
. -
Dans le composant React
Teams
, récupérez la liste des équipes d’AEM à l’aide du hookuseAllTeams()
.code language-javascript import { useAllTeams } from "../api/usePersistedQueries"; ... function Teams() { // Get the Teams data from AEM using the useAllTeams const { teams, error } = useAllTeams(); ... }
-
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 />; } ... }
-
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éemy-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.
-
Ouvrez
src/api/usePersistedQueries.js
. -
Localiser la fonction
usePersonByName(fullName)
-
Pour créer un hook
useEffect
qui appelle la requête persistantemy-project/all-teams
viafetchPersistedQuery(..)
, 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 }; }
-
Ouvrez
src/components/Person.js
. -
Dans le composant React
Person
, analysez le paramètre d’itinérairefullName
, et récupérez les données de la personne depuis AEM à l’aide du 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); ... }
-
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 />; } ... }
-
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.
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
.
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.