在本章中,您將探索AEM GraphQL API如何在外部應用程式中推動體驗。
使用簡單的React應用程式來查詢和顯示 團隊 和 個人 AEM GraphQL API公開的內容。 React的使用在很大程度上不重要,而且消費的外部應用程式可以寫入任何平台的任何框架中。
假設此多部分教學課程前面部分所概述的步驟已經完成,或者 basic-tutorial-solution.content.zip 安裝在您的AEMas a Cloud Service製作和發佈服務上。
本章中的IDE熒幕擷取畫面來自 Visual Studio Code
必須安裝下列軟體:
瞭解如何:
在本章中,使用與AEM GraphQL API互動所需的程式碼來實作簡略的範例React應用程式,並顯示從這些應用程式取得的團隊和人員資料。
React應用程式原始碼範例位於Github.com https://github.com/adobe/aem-guides-wknd-graphql/tree/main/basic-tutorial
若要取得React應用程式:
從複製範例WKND GraphQL React應用程式 Github.com.
$ cd ~/Code
$ git clone git@github.com:adobe/aem-guides-wknd-graphql.git
瀏覽至 basic-tutorial
資料夾並在IDE中開啟。
$ cd ~/Code/aem-guides-wknd-graphql/basic-tutorial
$ code .
更新 .env.development
以連線至AEMas a Cloud Service發佈服務。
REACT_APP_HOST_URI
的值設為您的AEMas a Cloud Service的發佈URL (例如 REACT_APP_HOST_URI=https://publish-p123-e456.adobeaemcloud.com
)和 REACT_APP_AUTH_METHOD
的值至 none
請確定您已發佈專案設定、內容片段模型、編寫的內容片段、GraphQL端點,以及先前步驟中的持續查詢。
如果您在本機AEM Author SDK上執行上述步驟,您可以指向 http://localhost:4502
和 REACT_APP_AUTH_METHOD
的值至 basic
.
從命令列,移至 aem-guides-wknd-graphql/basic-tutorial
資料夾
啟動React應用程式
$ cd ~/Code/aem-guides-wknd-graphql/basic-tutorial
$ npm install
$ npm start
React應用程式在開發模式中啟動於 http://localhost:3000/. 在教學課程中對React應用程式所做的變更會立即反映出來。
此React應用程式已部分實作。 依照本教學課程中的步驟完成實作。 需要實施作業的JavaScript檔案有下列註解,請務必使用本教學課程中指定的程式碼,新增/更新這些檔案中的程式碼。
//*****************************
// TODO ::依照AEM Headless教學課程中的步驟來實作此專案
//*****************************
範例React應用程式有三個主要部分:
此 src/api
資料夾包含用來向AEM發出GraphQL查詢的檔案。
src/api/aemHeadlessClient.js
初始化並匯出用於與AEM通訊的AEM Headless使用者端src/api/usePersistedQueries.js
實作 自訂React鉤點 將資料從AEM GraphQL傳回至 Teams.js
和 Person.js
檢視元件。此 src/components/Teams.js
檔案使用清單查詢顯示團隊及其成員的清單。
此 src/components/Person.js
檔案會使用引數化的單一結果查詢,顯示單一人員的詳細資訊。
檢閱 aemHeadlessClient.js
檔案以瞭解如何建立 AEMHeadless
用來與AEM通訊的物件。
開啟 src/api/aemHeadlessClient.js
.
複查明細行1-40:
匯入 AEMHeadless
來自的宣告 適用於JavaScript的AEM Headless使用者端,第11行。
根據中定義的變數設定授權 .env.development
,第14-22行,以及箭頭函式運算式 setAuthorization
,第31-40行。
此 serviceUrl
包含的設定 開發proxy 設定,第27行。
第42到49行是最重要的,因為它們會將 AEMHeadless
使用者端並匯出,以便在整個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;
實作泛型 fetchPersistedQuery(..)
執行AEM GraphQL持續查詢的函式開啟 usePersistedQueries.js
檔案。 此 fetchPersistedQuery(..)
函式使用 aemHeadlessClient
物件的 runPersistedQuery()
函式以非同步方式執行查詢、承諾型行為。
稍後,自訂React useEffect
hook呼叫此函式以從AEM擷取特定資料。
src/api/usePersistedQueries.js
更新 fetchPersistedQuery(..)
,第35行,程式碼如下。/**
* 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 };
}
接下來,建置可在React應用程式的主要檢視上顯示團隊及其成員的功能。 此功能需要:
src/api/usePersistedQueries.js
會叫用 my-project/all-teams
持久查詢,傳回AEM中的團隊內容片段清單。src/components/Teams.js
會叫用新的自訂React useEffect
連結,並轉譯團隊資料。完成後,應用程式的主要檢視會填入來自AEM的團隊資料。
開啟 src/api/usePersistedQueries.js
.
找到函式 useAllTeams()
若要建立 useEffect
叫用持久查詢的連結 my-project/all-teams
via fetchPersistedQuery(..)
,新增下列程式碼。 此掛接也只會從位於的AEM GraphQL回應傳回相關資料 data?.teamList?.items
,使React檢視元件與父JSON結構無關。
/**
* 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 };
}
開啟 src/components/Teams.js
在 Teams
React元件,使用從AEM擷取團隊清單 useAllTeams()
勾點。
import { useAllTeams } from "../api/usePersistedQueries";
...
function Teams() {
// Get the Teams data from AEM using the useAllTeams
const { teams, error } = useAllTeams();
...
}
執行以檢視為基礎的資料驗證,根據傳回的資料顯示錯誤訊息或載入指標。
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 />;
}
...
}
最後,轉譯團隊資料。 從GraphQL查詢傳回的每個團隊都會使用提供的 Team
React子元件。
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;
使用 團隊功能 完成,讓我們實施功能以處理團隊成員或個人詳細資訊上的顯示。
此功能需要:
新 自訂React useEffect勾點 在 src/api/usePersistedQueries.js
會叫用引數化 my-project/person-by-name
持久查詢,並傳回單一人員記錄。
位於的React元件 src/components/Person.js
使用個人全名作為查詢引數的系統,會叫用新的自訂React useEffect
勾選,並呈現個人資料。
完成後,在「團隊」檢視中選取人員名稱,即可呈現人員檢視。
開啟 src/api/usePersistedQueries.js
.
找到函式 usePersonByName(fullName)
若要建立 useEffect
叫用持久查詢的連結 my-project/all-teams
via fetchPersistedQuery(..)
,新增下列程式碼。 此掛接也只會從位於的AEM GraphQL回應傳回相關資料 data?.teamList?.items
,使React檢視元件與父JSON結構無關。
/**
* 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 };
}
開啟 src/components/Person.js
在 Person
React元件,剖析 fullName
route引數,並使用從AEM擷取人員資料 usePersonByName(fullName)
勾點。
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);
...
}
執行以檢視為基礎的資料驗證,根據傳回的資料顯示錯誤訊息或載入指標。
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 />;
}
...
}
最後,呈現人員資料。
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;
檢閱應用程式 http://localhost:3000/ 並按一下 成員 連結。 您也可以在AEM中新增內容片段,以新增更多團隊和/或成員至Team Alpha。
若要驗證您的實作變更,或是在上述變更後無法讓應用程式正常運作,請參閱 基礎教學課程 解決方案分支。
開啟瀏覽器的 開發人員工具 > 網路 和 篩選 的 all-teams
要求。 通知GraphQL API請求 /graphql/execute.json/my-project/all-teams
針對 http://localhost:3000
和 NOT 針對的值 REACT_APP_HOST_URI
(例如, https://publish-p123-e456.adobeaemcloud.com)。 之所以會針對React應用程式的網域提出請求,是因為 Proxy設定 已啟用,使用 http-proxy-middleware
模組。
檢閱主要 ../setupProxy.js
檔案和範圍 ../proxy/setupProxy.auth.**.js
檔案注意如何 /content
和 /graphql
已代理路徑並指示它不是靜態資產。
module.exports = function(app) {
app.use(
['/content', '/graphql'],
...
使用本機Proxy不適合用於生產部署,如需更多詳細資訊,請參閱 生產部署 區段。
恭喜!您已成功建立React應用程式,以使用並顯示AEM GraphQL API中的資料,作為基本教學課程的一部分!