App React react-app

[AEM headless as a Cloud Service]{class="badge informative"}

Le applicazioni di esempio sono un ottimo modo per esplorare le funzionalità headless di Adobe Experience Manager (AEM). Questa applicazione React illustra come eseguire query sui contenuti che utilizzano le API GraphQL dell’AEM utilizzando query persistenti. Il client headless AEM per JavaScript viene utilizzato per eseguire le query persistenti GraphQL che alimentano l’app.

App React con AEM headless

Visualizza il codice sorgente in GitHub

È disponibile un tutorial completo che descrive come è stata generata l'app React.

Prerequisiti prerequisites

I seguenti strumenti devono essere installati localmente:

Requisiti AEM

L’applicazione React funziona con le seguenti opzioni di implementazione dell’AEM. Tutte le distribuzioni richiedono l'installazione del sito WKND v3.0.0+.

  • AEM as a Cloud Service
  • Configurazione locale con SDK AEM Cloud Service
    • Richiede [JDK 11](https://experience.adobe.com/#/downloads/content/software-distribution/en/general.html?1_group.propertyvalues.property=.%2Fjcr%3Acontent%2Fmetadata%2Fdc%3AsoftwareType&1_group.propertyvalues.operation=equals&1_group.propertyvalues.0_values=tipo di software%3Atooling&fulltext=Oracle%7E+JDK%7E+11%7E&orderby=%40jcr%3Acontent%2Fjcr%3AlastModified&orderby.sort=desc&layout=list&p.offset=0&p.limit=14)

L'applicazione React è progettata per connettersi a un ambiente AEM Publish, tuttavia può creare contenuto da AEM Author se l'autenticazione viene fornita nella configurazione dell'applicazione React.

Come usare

  1. Clona l'archivio adobe/aem-guides-wknd-graphql:

    code language-shell
    $ git clone git@github.com:adobe/aem-guides-wknd-graphql.git
    
  2. Modificare il file aem-guides-wknd-graphql/react-app/.env.development e impostare REACT_APP_HOST_URI in modo che punti all'AEM di destinazione.

    Se ti connetti a un’istanza Autore, aggiorna il metodo di autenticazione.

    code language-plain
    # Server namespace
    REACT_APP_HOST_URI=https://publish-p123-e456.adobeaemcloud.com
    
    #AUTH (Choose one method)
    # Authentication methods: 'service-token', 'dev-token', 'basic' or leave blank to use no authentication
    REACT_APP_AUTH_METHOD=basic
    
    # For Bearer auth, use DEV token (dev-token) from Cloud console
    REACT_APP_DEV_TOKEN=dev-token
    
    # For Service toke auth, provide path to service token file (download file from Cloud console)
    REACT_APP_SERVICE_TOKEN=auth/service-token.json
    
    # For Basic auth, use AEM ['user','pass'] pair (eg for Local AEM Author instance)
    REACT_APP_BASIC_AUTH_USER=admin
    REACT_APP_BASIC_AUTH_PASS=admin
    
  3. Apri un terminale ed esegui i comandi:

    code language-shell
    $ cd aem-guides-wknd-graphql/react-app
    $ npm install
    $ npm start
    
  4. Una nuova finestra del browser deve essere caricata su http://localhost:3000

  5. Nell’applicazione deve essere visualizzato un elenco di avventure dal sito di riferimento WKND.

Il codice

Di seguito è riportato un riepilogo di come viene creata l’applicazione React, di come si connette a AEM Headless per recuperare contenuti utilizzando query persistenti di GraphQL e di come vengono presentati tali dati. Il codice completo si trova su GitHub.

Query persistenti

Seguendo le best practice di AEM Headless, l’applicazione React utilizza query persistenti di AEM GraphQL per eseguire query sui dati di avventura. L’applicazione utilizza due query persistenti:

  • Query persistente wknd/adventures-all, che restituisce tutte le avventure in AEM con un set abbreviato di proprietà. Questa query persistente guida l’elenco di avventure della visualizzazione iniziale.
# Retrieves a list of all Adventures
#
# Optional query variables:
# - { "offset": 10 }
# - { "limit": 5 }
# - {
#    "imageFormat": "JPG",
#    "imageWidth": 1600,
#    "imageQuality": 90
#   }
query ($offset: Int, $limit: Int, $sort: String, $imageFormat: AssetTransformFormat=JPG, $imageWidth: Int=1200, $imageQuality: Int=80) {
  adventureList(
    offset: $offset
    limit: $limit
    sort: $sort
    _assetTransform: {
      format: $imageFormat
      width: $imageWidth
      quality: $imageQuality
      preferWebp: true
  }) {
    items {
      _path
      slug
      title
      activity
      price
      tripLength
      primaryImage {
        ... on ImageRef {
          _path
          _dynamicUrl
        }
      }
    }
  }
}
  • Query persistente wknd/adventure-by-slug, che restituisce una singola avventura di slug (una proprietà personalizzata che identifica in modo univoco un'avventura) con un set completo di proprietà. Questa query persistente attiva le visualizzazioni dei dettagli dell’avventura.
# Retrieves an Adventure Fragment based on it's unique slug.
#
# Required query variables:
# - {"slug": "bali-surf-camp"}
#
# Optional query variables:
# - {
#     "imageFormat": "JPG",
#     "imageSeoName": "my-adventure",
#     "imageWidth": 1600,
#     "imageQuality": 90
#   }
#
# This query returns an adventure list but since the the slug property is set to be unique in the Content Fragment Model, only a single Content Fragment is expected.

query ($slug: String!, $imageFormat:AssetTransformFormat=JPG, $imageSeoName: String, $imageWidth: Int=1200, $imageQuality: Int=80) {
  adventureList(
    filter: {slug: {_expressions: [{value: $slug}]}}
    _assetTransform: {
      format: $imageFormat
      seoName: $imageSeoName
      width: $imageWidth
      quality: $imageQuality
      preferWebp: true
  }) {
    items {
      _path
      title
      slug
      activity
      adventureType
      price
      tripLength
      groupSize
      difficulty
      price
      primaryImage {
        ... on ImageRef {
          _path
          _dynamicUrl
        }
      }
      description {
        json
        plaintext
        html
      }
      itinerary {
        json
        plaintext
        html
      }
    }
    _references {
      ... on AdventureModel {
        _path
        slug
        title
        price
        __typename
      }
    }
  }
}

Esegui query persistente GraphQL

Le query persistenti dell'AEM vengono eseguite su HTTP GET, pertanto il client AEM Headless per JavaScript viene utilizzato per eseguire le query GraphQL persistenti sull'AEM e caricare il contenuto dell'avventura nell'app.

Ogni query persistente ha un hook React useEffect corrispondente in src/api/usePersistedQueries.js, che chiama in modo asincrono l'endpoint della query persistente HTTP AEM GET e restituisce i dati relativi all'avventura.

Ogni funzione a sua volta richiama aemHeadlessClient.runPersistedQuery(...), eseguendo la query GraphQL persistente.

// src/api/usePersistedQueries.js

/**
 * React custom hook that returns a list of adevntures by activity. If no activity is provided, all adventures are returned.
 *
 * Custom hook that calls the 'wknd-shared/adventures-all' or 'wknd-shared/adventures-by-activity' persisted query.
 *
 * @returns an array of Adventure JSON objects, and array of errors
 */
export function useAdventuresByActivity(adventureActivity, params = {}) {
  ...
  let queryVariables = params;

  // If an activity is provided (i.e "Camping", "Hiking"...) call wknd-shared/adventures-by-activity query
  if (adventureActivity) {
    // The key is 'activity' as defined in the persisted query
    queryVariables = { ...queryVariables, activity: adventureActivity };

    // Call the AEM GraphQL persisted query named "wknd-shared/adventures-by-activity" with parameters
    response = await fetchPersistedQuery("wknd-shared/adventures-by-activity", queryVariables);
  } else {
    // Else call the AEM GraphQL persisted query named "wknd-shared/adventures-all" to get all adventures
    response = await fetchPersistedQuery("wknd-shared/adventures-all", queryVariables);
  }

  ...
}

...
/**
 * Private 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 .then(..) { ... } 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 { data, err };
}

Viste

L’applicazione React utilizza due visualizzazioni per presentare i dati dell’avventura nell’esperienza web.

  • src/components/Adventures.js

    Richiama getAdventuresByActivity(..) da src/api/usePersistedQueries.js e visualizza le avventure restituite in un elenco.

  • src/components/AdventureDetail.js

    Richiama getAdventureBySlug(..) utilizzando il parametro slug trasmesso tramite la selezione di avventura nel componente Adventures e visualizza i dettagli di una singola avventura.

Variabili di ambiente

Diverse variabili di ambiente sono utilizzate per connettersi a un ambiente AEM. L'impostazione predefinita si connette al Publish AEM in esecuzione alle http://localhost:4503. Aggiornare il file .env.development per modificare la connessione AEM:

  • REACT_APP_HOST_URI=https://publish-p123-e456.adobeaemcloud.com: impostato sull'host di destinazione AEM

  • REACT_APP_GRAPHQL_ENDPOINT=/content/graphql/global/endpoint.json: impostare il percorso dell'endpoint GraphQL. Questa app React non la utilizza, in quanto utilizza solo query persistenti.

  • REACT_APP_AUTH_METHOD=: metodo di autenticazione preferito. Facoltativo, per impostazione predefinita non viene utilizzata alcuna autenticazione.

    • service-token: usa le credenziali del servizio per ottenere un token di accesso su AEM as a Cloud Service
    • dev-token: usa il token di sviluppo per lo sviluppo locale su AEM as a Cloud Service
    • basic: usa user/pass per lo sviluppo locale con Autore AEM locale
    • Lascia vuoto per connetterti a AEM senza autenticazione
  • REACT_APP_AUTHORIZATION=admin:admin: impostare le credenziali di autenticazione di base da utilizzare per la connessione a un ambiente di creazione AEM (solo per lo sviluppo). Se ci si connette a un ambiente Publish, questa impostazione non è necessaria.

  • REACT_APP_DEV_TOKEN: stringa token di sviluppo. Per connettersi all’istanza remota, oltre all’autenticazione di base (utente:passaggio) puoi utilizzare l’autenticazione Bearer con il token DEV dalla console Cloud

  • REACT_APP_SERVICE_TOKEN: percorso del file delle credenziali del servizio. Per connettersi all’istanza remota, l’autenticazione può essere eseguita anche con il token di servizio (scarica il file da Developer Console).

Richieste proxy AEM

Quando si utilizza il server di sviluppo Webpack (npm start), il progetto si basa su una configurazione proxy che utilizza http-proxy-middleware. Il file è configurato in src/setupProxy.js e si basa su diverse variabili di ambiente personalizzate impostate in .env e .env.development.

Se ci si connette a un ambiente di authoring AEM, è necessario configurare il metodo di autenticazione corrispondente.

Condivisione delle risorse tra le origini (CORS)

Questa applicazione React si basa su una configurazione CORS basata su AEM in esecuzione nell'ambiente AEM di destinazione e presuppone che l'app React sia in esecuzione su http://localhost:3000 in modalità di sviluppo. Consulta ladocumentazione sulla distribuzione headless dell'AEM per ulteriori informazioni su come impostare e configurare CORS.

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