使用GraphQL从外部应用程序查询AEM

在本章中,我们将探讨如何使用AEM GraphQL API来在外部应用程序中提供体验。

本教程使用一个简单的React应用程序来查询和显示由AEM GraphQL API公开的Adventure内容。 React的使用基本上不重要,任何平台的任何框架都可以编写消耗性外部应用程序。

前提条件

这是一个多部分教程,假定已完成前面部分中概述的步骤。

本章中的IDE屏幕截图来自 Visual Studio代码

或者,也可以选择安装诸如 GraphQL网络检查器 以查看有关GraphQL查询的更多详细信息。

目标

在本章中,我们将学习如何:

  • 开始并了解示例React应用程序的功能
  • 了解如何从外部应用程序对AEM GraphQL端点发起调用
  • 定义GraphQL查询,以按活动筛选历险内容片段列表
  • 更新React应用程序以提供控件,以便通过GraphQL(按活动划分的历险列表)进行筛选

启动React应用程序

由于本章重点介绍如何开发客户端以通过GraphQL使用内容片段,因此示例 必须下载和设置WKND GraphQL React应用程序源代码 本地机器上。

有关启动React应用程序的详细信息,请参阅 快速设置 章节,但可以遵循简略说明:

  1. 如果尚未克隆示例的WKND GraphQL React应用程序,请从 Github.com

    $ git clone --branch tutorial/react git@github.com:adobe/aem-guides-wknd-graphql.git
    
  2. 在IDE中打开WKND GraphQL React应用程序

    VSCode中的React App

  3. 从命令行中,导航到 react-app 文件夹

  4. 通过从项目根(即 react-app 文件夹)

    $ cd aem-guides-wknd-graphql/react-app
    $ npm start
    
  5. 在以下位置查看应用程序 http://localhost:3000/. 示例React应用程序包含两个主要部分:

    • 家庭体验通过查询充当WKND冒险的索引 冒险 AEM中使用GraphQL的内容片段。 在本章中,我们将修改此视图,以支持按活动筛选冒险。

      WKND GraphQL React应用程序 — 主页体验

    • 探险详细信息体验使用GraphQL查询特定 冒险 内容片段,并显示更多数据点。

      WKND GraphQL React应用程序 — 详细体验

  6. 使用浏览器的开发工具和浏览器扩展,如 GraphQL网络检查器 以检查发送到AEM的GraphQL查询及其JSON响应。 此方法可用于监控GraphQL请求和响应,以确保它们得到正确表达,并且其响应符合预期。

    AdventureList的原始查询

    从React应用程序发送到AEM的GraphQL查询

    GraphQL JSON响应

    从AEM到React应用程序的JSON响应

    查询和响应应与GraphiQL IDE中显示的内容相匹配。

    注意

    在开发过程中,React应用程序配置为通过WebPack开发服务器将HTTP请求代理到AEM。 React应用程序会向 http://localhost:3000 将它们代理到上运行的AEM创作服务 http://localhost:4502. 查看文件 src/setupProxy.jsenv.development 以了解详细信息。

    在非开发方案中,将配置React应用程序,以直接向AEM发出请求。

浏览应用程序的GraphQL代码

  1. 在IDE中,打开文件 src/api/useGraphQL.js.

    这是 反应效果挂钩 用于侦听应用程序更改 query,且发生更改时,会向AEM GraphQL端点发出HTTPPOST请求,并将JSON响应返回到应用程序。

    每当React应用程序需要进行GraphQL查询时,都会调用此自定义 useGraphQL(query) 挂接,传入GraphQL以发送到AEM。

    此挂接使用 fetch 模块,以发出HTTPPOSTGraphQL请求,但其他模块,如 Apollo GraphQL客户端 的值。

  2. 打开 src/components/Adventures.js 在IDE中,该IDE负责主视图的历险列表,并回顾调用 useGraphQL 挂。

    此代码设置默认 queryallAdventuresQuery 在此文件下定义。

    const [query, setQuery] = useState(allAdventuresQuery);
    

    随时 query 变量更改, useGraphQL 将调用挂接,进而对AEM执行GraphQL查询,并将JSON返回到 data 变量,该变量随后用于呈现历险列表。

    const { data, errorMessage } = useGraphQL(query);
    

    allAdventuresQuery 是文件中定义的常量GraphQL查询,该查询可查询所有Adventure内容片段(不进行任何筛选),并且只返回渲染主页视图所需的数据点。

    const allAdventuresQuery = `
    {
        adventureList {
          items {
            _path
            adventureTitle
            adventurePrice
            adventureTripLength
            adventurePrimaryImage {
            ... on ImageRef {
                _path
                mimeType
                width
                height
              }
            }
          }
      }
    }
    `;
    
  3. 打开 src/components/AdventureDetail.js, React组件负责显示冒险详细信息体验。 此视图使用特定内容片段的JCR路径作为其唯一ID来请求特定内容片段,并呈现提供的详细信息。

    类似于 Adventures.js,自定义 useGraphQL React Hook可重新用于对AEM执行GraphQL查询。

    内容片段的路径是从组件的 props 顶部用于指定要查询的内容片段。

    const contentFragmentPath = props.location.pathname.substring(props.match.url.length);
    

    …并使用 adventureDetailQuery(..) 函数,并传递到 useGraphQL(query) 用于对AEM执行GraphQL查询,并将结果返回给 data 变量。

    const { data, errorMessage } = useGraphQL(adventureDetailQuery(contentFragmentPath));
    

    adventureDetailQuery(..) 函数只需包装过滤GraphQL查询,该查询使用AEM <modelName>ByPath 用于查询由其JCR路径标识的单个内容片段的语法,并返回呈现冒险详细信息所需的所有指定数据点。

    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
            }
          }
        }
    }
    `;
    }
    

创建参数化GraphQL查询

接下来,让我们修改React应用程序以执行参数化的GraphQL查询,这些查询通过冒险活动来限制主页视图。

  1. 在IDE中,打开文件: src/components/Adventures.js. 此文件表示主页体验的冒险组件,该组件可查询并显示冒险卡片。

  2. Inspect函数 filterQuery(activity),但已准备制定一个GraphQL查询,该查询会按 activity.

    请注意该参数 activity 作为 filteradventureActivity 字段,要求该字段的值与参数的值匹配。

    function filterQuery(activity) {
        return `
            {
            adventures (filter: {
                adventureActivity: {
                _expressions: [
                    {
                    value: "${activity}"
                    }
                  ]
                }
            }){
                items {
                _path
                adventureTitle
                adventurePrice
                adventureTripLength
                adventurePrimaryImage {
                ... on ImageRef {
                    _path
                    mimeType
                    width
                    height
                }
                }
              }
          }
        }
        `;
    }
    
  3. 更新React Adventures组件的 return 语句,以添加调用新参数化的按钮 filterQuery(activity) 来提供要列出的冒险。

    function Adventures() {
        ...
        return (
            <div className="adventures">
    
            {/* Add these three new buttons that set the GraphQL query accordingly */}
    
            {/* The first button uses the default `allAdventuresQuery` */}
            <button onClick={() => setQuery(allAdventuresQuery)}>All</button>
    
            {/* The 2nd and 3rd button use the `filterQuery(..)` to filter by activity */}
            <button onClick={() => setQuery(filterQuery('Camping'))}>Camping</button>
            <button onClick={() => setQuery(filterQuery('Surfing'))}>Surfing</button>
    
            <ul className="adventure-items">
            ...
        )
    }
    
  4. 保存更改,然后在Web浏览器中重新加载React应用程序。 三个新按钮显示在顶部,单击它们会自动使用匹配的活动重新查询AEM的冒险内容片段。

    按活动筛选历程

  5. 尝试为活动添加更多过滤按钮: Rock Climbing, CyclingSkiing

处理GraphQL错误

GraphQL是强类型,因此在查询无效时可能会返回有用的错误消息。 接下来,让我们模拟一个错误的查询,以查看返回的错误消息。

  1. 重新打开文件 src/api/useGraphQL.js. Inspect以下代码片段可查看错误处理:

    //useGraphQL.js
    .then(({data, errors}) => {
            //If there are errors in the response set the error message
            if(errors) {
                setErrors(mapErrors(errors));
            }
            //Otherwise if data in the response set the data as the results
            if(data) {
                setData(data);
            }
        })
        .catch((error) => {
            setErrors(error);
        });
    

    检查响应,以查看其是否包含 errors 对象。 的 errors 如果GraphQL查询存在问题(例如基于架构的未定义字段),则AEM将发送对象。 如果没有 errors 对象 data 设置并返回。

    window.fetch 包括 .catch 语句至 捕捉 任何常见错误,如HTTP请求无效或无法与服务器建立连接。

  2. 打开文件 src/components/Adventures.js.

  3. 修改 allAdventuresQuery 包含无效属性 adventurePetPolicy:

    /**
     * Query for all Adventures
     * adventurePetPolicy has been added beneath items
    */
    const allAdventuresQuery = `
    {
        adventureList {
          items {
            adventurePetPolicy
            _path
            adventureTitle
            adventurePrice
            adventureTripLength
            adventurePrimaryImage {
            ... on ImageRef {
                _path
                mimeType
                width
                height
            }
            }
          }
        }
    }
    `;
    

    我们知道 adventurePetPolicy 不是Adventure模型的一部分,因此这应会触发错误。

  4. 保存更改并返回到浏览器。 您应会看到如下错误消息:

    属性错误无效

    GraphQL API检测到 adventurePetPolicy 在中未定义 AdventureModel 和会返回相应的错误消息。

  5. Inspect来自AEM的响应使用浏览器的开发人员工具查看 errors JSON对象:

    错误JSON对象

    errors 对象是详细的,其中包含有关错误查询的位置和错误分类的信息。

  6. 返回 Adventures.js 并还原查询更改,以将应用程序恢复到正确状态。

恭喜!

恭喜! 您已成功探索了示例WKND GraphQL React应用程序的代码,并将其更新为使用参数化、过滤GraphQL查询来按活动列出冒险! 您还有机会探索一些基本的错误处理。

后续步骤

在下一章中, 使用片段引用进行高级数据建模 您将了解如何使用片段引用功能在两个不同的内容片段之间创建关系。 您还将了解如何修改GraphQL查询以包含引用模型中的字段。

在此页面上