React App

Example applications are a great way to explore the headless capabilities of Adobe Experience Manager (AEM). A React application is provided that demonstrates how to query content using the GraphQL APIs of AEM. The AEM Headless Client for JavaScript is used to execute the GraphQL queries that power the app.

View the source code on GitHub

React Application

A full step by step tutorial is available here.

Prerequisites

The following tools should be installed locally:

AEM Requirements

The application is designed to connect to an AEM Author or Publish environment with the latest release of the WKND Reference site installed.

We recommend deploying the WKND Reference site to a Cloud Service environment. A local setup using the AEM Cloud Service SDK or AEM 6.5 QuickStart jar can also be used.

How to use

  1. Clone the aem-guides-wknd-graphql repository:

    git clone git@github.com:adobe/aem-guides-wknd-graphql.git
    
  2. Edit the aem-guides-wknd/react-app/.env.development file and ensure that REACT_APP_HOST_URI points to your target AEM instance. Update the authentication method (if connecting to an author instance).

    # Server namespace
    REACT_APP_HOST_URI=http://localhost:4503
    REACT_APP_GRAPHQL_ENDPOINT=/content/graphql/global/endpoint.json
    #AUTH (Choose one method)
    # Authentication methods: 'service-token', 'dev-token', 'basic' or leave blank to use no authentication
    ...
    
  3. Open a terminal and run the commands:

    $ cd aem-guides-wknd-graphql/react-app
    $ npm install
    $ npm start
    
  4. A new browser window should load on http://localhost:3000

  5. A list of adventures from the WKND reference site should be displayed on the application.

The code

Below is a brief summary of the important files and code used to power the application. The full code can be found on GitHub.

AEM Headless Client for JavaScript

The AEM Headless Client is used to execute the GraphQL query. The AEM Headless Client provides two methods for executing queries, runQuery and runPersistedQuery.

runQuery executes a standard GraphQL query for AEM content and is the most common type of query run.

Persisted Queries are a feature in AEM that caches the results of a GraphQL query and then makes the result available over GET. Persisted Queries should be used for common queries that will be executed over and over. In this application the list of Adventures is the first query executed on the home screen. This will be a very popular query and therefore a persisted query should be used. runPersistedQuery executes a request against a persisted query endpoint.

src/api/useGraphQL.js is a React Effect Hook that listens for changes to the parameter query and path. If query is blank then a persisted query is used based on the path. Here is where the AEM Headless Client is constructed and used to fetch data.

function useGraphQL(query, path) {
    let [data, setData] = useState(null);
    let [errorMessage, setErrors] = useState(null);

    useEffect(() => {
      // construct a new AEMHeadless client based on the graphQL endpoint
      const sdk = new AEMHeadless({ endpoint: REACT_APP_GRAPHQL_ENDPOINT })

      // if query is not null runQuery otherwise fall back to runPersistedQuery
      const request = query ? sdk.runQuery.bind(sdk) : sdk.runPersistedQuery.bind(sdk);

      request(query || path)
        .then(({ data, errors }) => {
          //If there are errors in the response set the error message
          if(errors) {
            setErrors(mapErrors(errors));
          }
          //If data in the response set the data as the results
          if(data) {
            setData(data);
          }
        })
        .catch((error) => {
          setErrors(error);
        });
    }, [query, path]);

    return {data, errorMessage}
}

Adventure content

The app primarily displays a list of Adventures and gives the users an option to click into the details of an Adventure.

Adventures.js - Displays a card list of Adventures. The initial state makes use of Persisted Queries which is pre-packaged with the WKND reference site. The endpoint is /wknd/adventures-all. There are several buttons that allow a user to experiment with filtering results based on an activity:

function filterQuery(activity) {
  return `
    {
      adventureList (filter: {
        adventureActivity: {
          _expressions: [
            {
              value: "${activity}"
            }
          ]
        }
      }){
        items {
          _path
        adventureTitle
        adventurePrice
        adventureTripLength
        adventurePrimaryImage {
          ... on ImageRef {
            _path
            mimeType
            width
            height
          }
        }
      }
    }
  }
  `;
}

AdventureDetail.js - Displays a detail view of the Adventure. Makes a graphQL query based on the path to the adventure which is parsed from the url:

//parse the content fragment from the url
const contentFragmentPath = props.location.pathname.substring(props.match.url.length);
...
function adventureDetailQuery(_path) {
  return `{
    adventureByPath (_path: "${_path}") {
      item {
        _path
          adventureTitle
          adventureActivity
          adventureType
          adventurePrice
          adventureTripLength
          adventureGroupSize
          adventureDifficulty
          adventurePrice
          adventurePrimaryImage {
            ... on ImageRef {
              _path
              mimeType
              width
              height
            }
          }
          adventureDescription {
            html
          }
          adventureItinerary {
            html
          }
      }
    }
  }
  `;
}

Environment Variables

Several environment variables are used by this project to connect to an AEM environment. Default connects to an AEM author environment running at http://localhost:4502. If you wish to change this behavior update the .env.development file accordingly:

  • REACT_APP_HOST_URI=http://localhost:4502 - Set to AEM target host
  • REACT_APP_GRAPHQL_ENDPOINT=/content/graphql/global/endpoint.json - Set the GraphQL endpoint path
  • REACT_APP_AUTH_METHOD= - The preferred authentication method. Optional, as per default no authentication is used.
    • service-token - use Service token exchange for Cloud Env PROD
    • dev-token - use Dev token for local development with Cloud Env
    • basic - use user/pass for local development with Local Author Env
    • leave blank to use no authentication method
  • REACT_APP_AUTHORIZATION=admin:admin - set basic auth credentials to use if connecting to an AEM Author environment (for development only). If connecting to a Publish environment, this setting is not necessary.
  • REACT_APP_DEV_TOKEN - Dev token string. To connect to remote instance, beside Basic auth (user:pass) you can use Bearer auth with DEV token from Cloud console
  • REACT_APP_SERVICE_TOKEN - Path to service token file. To connect to remote instance, authentication can be done with Service token also (download file from Cloud console)

Proxy API Requests

When using the webpack development server (npm start) the project relies on a proxy setup using http-proxy-middleware. The file is configured at src/setupProxy.js and relies on several custom environment variables set at .env and .env.development.

If connecting to an AEM author environment, the corresponding authentication method needs to be configured.

CORS - Cross Origin Resource Sharing

This project relies on a CORS configuration running on the target AEM environment and assumes that the app is running on http://localhost:3000 in development mode. The CORs configuration is part of the WKND Reference site.

CORS Configuration

Sample CORS config for Author environment

On this page