本章说明如何在 Oracle APEX 中集成远程数据:包括通过 REST-Enabled SQL 访问远程 Oracle 或 MySQL 数据库,使用 Web Credential 安全保存认证信息,把 REST API 建模成 REST Data Source,以及在声明式页面流程或 PL/SQL 代码中调用远程服务。

13 集成远程数据#

在 APEX 应用中,性能和可维护性通常以本地表或视图为优先。但真实业务系统经常需要读取或修改远程数据库、Fusion Applications、ORDS、OData 或其他 REST API 中的数据。APEX 的做法是把这些外部能力封装成可声明式使用的数据源、凭据和操作,让页面区域、LOV、流程和 PL/SQL 代码都能复用同一套定义。

学习本章时,应先区分三类集成:REST-Enabled SQL 面向远程数据库;REST Data Source 面向 HTTP API;APEX_WEB_SERVICE 面向需要完全手写请求逻辑或二进制载荷的特殊场景。对一组有自定义约定的 API,还可以开发 REST Source Adapter 插件,把认证、分页、过滤、排序和 DML 规则封装起来。

13.1 使用远程 Oracle 与 MySQL 数据#

REST-Enabled SQL 是 ORDS 提供的能力,允许经过认证的客户端通过 HTTPS 访问远程 Oracle 数据库或 Oracle Cloud MySQL Database System。APEX 工作区保存服务端点和认证信息后,页面区域、LOV 等组件就可以像选择本地数据源一样选择远程数据源。

  • 前提:远程数据库已经启用 ORDS REST-Enabled SQL,且你拥有可用的服务 URL 与认证方式。
  • 涉及位置:Workspace Utilities 中的 REST-Enabled SQL Services,以及 Page Designer 中区域或 LOV 的 Source 设置。
  • 验证点:创建服务引用时,APEX 能成功认证并显示连接成功;页面区域能列出或查询远程对象。
  • 预期结果:远程 Oracle 数据库支持读写;远程 MySQL 当前适合只读展示,Form 和 Interactive Grid 的自动 DML 不适用于 MySQL。

13.1.1 引用 REST-Enabled SQL 服务#

REST-Enabled SQL 引用是工作区级定义。创建时要提供一个清晰名称、服务端点和凭据。多数 REST-Enabled SQL 服务使用 HTTPS 上的 Basic Authentication;如果此前已定义 Web Credential,也可以直接选择已有凭据。

  1. 进入 Workspace Utilities,打开 REST-Enabled SQL Services。
  2. 启动 Create REST Enabled SQL Service 向导,填写服务名称和端点 URL。
  3. 输入新凭据或选择已有 Web Credential。
  4. 点击 Create,让 APEX 验证端点和认证信息。
图 13-1 在 Workspace Utilities 中引用 REST-Enabled SQL 服务。
图 13-2 为 REST-Enabled SQL 服务提供认证凭据。
图 13-3 APEX 验证端点和认证成功后的确认信息。

13.1.2 REST-Enabled SQL 服务 URL#

REST-Enabled SQL 的 URL 取决于服务部署位置。常见 ORDS 或 Autonomous AI Database 场景使用包含 ORDS schema alias 的 URL,APEX 会自动补上后续 SQL 访问路径,因此不要在配置中手工追加 /_/sql

https://domainname/ords/your_schema_alias

如果通过 OCI Database Tools Connection 暴露 MySQL Database System,URL 中会包含 Database Tools Connection 的 OCID,并带有所在 OCI region。配置时要替换成实际 region 与 connection OCID。

https://sql.dbtools.yourregion.oci.oraclecloud.com/20201005/ords/connectionocid

13.1.3 使用 REST-Enabled SQL 服务#

服务引用创建完成后,在区域、LOV 或其他动态列表中把 Source Location 设为 REST-Enabled SQL,即可选择远程数据库中的表、SQL Statement 或 Function Body Returning SQL Query。对远程 Oracle 数据库,读写操作都可使用;对远程 MySQL,适合报表、LOV 和只读展示。

图 13-4 在 Interactive Report 中使用 REST-Enabled SQL 访问远程 EMP 表。

13.2 配置安全 Web 凭据#

Web Credential 用来安全保存访问 REST-Enabled SQL 或 REST API 所需的认证信息。密钥保存后会被加密,不能再以明文取回;页面和 REST Data Source 只引用凭据的定义,而不是直接持有密钥。

凭据类型常见用途
Basic Authentication多数 REST-Enabled SQL 服务和部分 REST API。
OAuth2Client credentials、password flow,以及配合 Social Sign-in 的 authorization code flow。
OCI Native AuthenticationDatabase Tools connection REST-Enabled SQL 服务,以及其他 OCI REST API。
HTTP Header要求在请求头中传递 auth token 或 API key 的服务。
URL Query String要求在 URL 参数中传递 API key 的服务。
Key Pair推送通知和用户断言签名。

配置时应优先使用 Web Credential 保存认证值,不要把 token、API key 或密码做成普通 REST 参数。这样可以减少调试日志泄漏风险,并集中处理密钥轮换。

13.3 把 REST API 用作数据源#

REST Data Source 把 HTTP API 封装成 APEX 可理解的数据源。每个数据源可以有一个或多个操作,对应 GETPUTPOSTPATCHDELETE 请求。运行时,APEX 使用关联的 Web Credential 认证,按配置处理分页、参数、响应映射、缓存和本地同步。

一旦定义完成,REST Data Source 可以用于区域、LOV 和动态列表。支持 DML 操作时,它还可以服务于 Form、Interactive Grid 和 APEX_EXEC 代码。Fusion Applications、ORDS 和 OData 这类有统一约定的 API 可获得更强的自动发现、过滤、排序和 DML 支持。

13.3.1 使用 Simple HTTP REST Data Source#

Simple HTTP 是最通用的 REST Data Source 类型。若 API 支持 GET,Create REST Data Source 向导可先调用端点并分析 JSON 响应,自动生成初始 Data Profile;若 API 不能自动发现,也可以手工创建并补全操作和列定义。

示例 Employees API 的端点如下。它返回包含 items 数组、hasMorelimitoffsetcount 的 JSON,其中 limitoffset 可用于分页。

curl -L https://example.com/ords/cloudcompanion/emp
curl -L "https://example.com/ords/cloudcompanion/emp?limit=2"
curl -L "https://example.com/ords/cloudcompanion/emp?offset=2&limit=2"
  1. 进入 Shared Components > REST Data Sources。
  2. 启动 Create REST Data Source 向导。
  3. 输入 endpoint URL,例如 https://example.com/ords/cloudcompanion/emp
  4. 根据服务文档检查认证、分页和响应结构,再继续完成向导。
图 13-5 通过服务端点 URL 定义新的 REST Data Source。

13.3.2 Service URL 使用 Remote Server#

同一组织的多个 REST 端点通常共享域名和公共路径,只在末尾资源路径不同。APEX 会把公共基础地址保存为 Remote Server,把尾部路径保存为 REST Data Source 的 Service URL Path。这样开发、测试、生产环境可以各自维护不同 Remote Server Base URL,而应用导入升级时仍保留各环境的目标主机。

https://example.com/ords/cloudcompanion/emp
https://example.com/ords/cloudcompanion/dept
图 13-6 APEX 将基础 URL 放入 Remote Server,将尾部路径放入 Service URL Path。

13.3.3 Data Profile 把 JSON 转为行列#

每个 REST Data Source 都包含 Data Profile。它定义 Row Selector、列名、数据类型、JSON selector、主键等信息,让 APEX 可以把 JSON 响应转换为类似数据库查询的行列结果。自动发现只是起点,日期格式、主键、嵌套数组和不需要的列都应人工复核。

图 13-7 向导根据响应负载预览 REST Data Source 返回的行数据。
图 13-8 在 Response Body 中检查顶层 items 数组和嵌套 links 数组。
图 13-9 APEX 自动发现的 Data Profile 列、数据类型和 JSON selector。

如果某列会用于 Form、Interactive Grid 或 DML 操作,应在 Data Profile 中启用 Primary Key。对于 HIREDATE 这类日期字段,如果自动发现的数据类型或格式掩码不准确,应在 REST Data Source 编辑页调整为正确的 DATE 与格式,例如 YYYY-MM-DD"T"HH24:MI:SS"Z"

图 13-10 调整 HIREDATE Data Profile 列的数据类型和格式掩码。

13.3.4 按页检索远程数据#

Simple HTTP REST Data Source 的分页行为在编辑页的 Settings 标签中配置。选择合适的 Pagination Type 后,再配置 API 使用的参数名,例如用 limit 表示页大小、用 offset 表示跳过行数、用 hasMore 表示是否还有下一页。

图 13-11 为 REST Data Source 配置分页策略。

配置完成后,在 Interactive Report 等支持分页的区域中选择 Source Location 为 REST Source,APEX 会自动按区域分页请求远程服务。开启 Debug Info 后,可在日志中看到类似 offsetlimit 的实际请求参数。

图 13-12 Interactive Report 区域使用 REST Data Source。
图 13-13 运行时在 Interactive Report 中按页浏览 REST 数据。

13.3.5 REST 操作与数据库动作#

REST Data Source 通过 Operation 来描述 HTTP 调用,并用 Database Action 告诉 APEX 这个操作用于 Fetch Rows、Fetch Single Row、Insert Row、Update Row 或 Delete Row。只读使用通常只需要 Fetch Rows;如果要让 Form 或 Interactive Grid 自动修改远程数据,就需要补齐单行查询、插入、更新和删除操作。

图 13-14 自动发现的 Fetch Rows GET 操作。
图 13-15 支持读写所需的完整 REST 操作集合。

Fetch Single Row、PUT 和 DELETE 等操作常把主键值放在 URL Pattern 中。APEX 可以使用 Data Profile 主键列的区分大小写 selector 作为隐式 URL 参数,例如 :empno{empno}。不要再额外定义同名 URL Pattern 参数,否则会覆盖隐式参数。

图 13-16 Fetch Single Row 操作用主键获取单行。
图 13-17 在表单页面项上确认 Primary Key 已启用。

验证时可在 Debug 日志中检查 APEX 是否把页面项主键值替换到正确 URL,例如 https://example.com/ords/cloudcompanion/emp/7369

13.3.6 配置 Request Body Template#

Insert Row 和 Update Row 操作通常需要向 REST API 发送请求体。Request Body Template 可以混合 JSON 语法与 #NAME# 替换。列名替换通常不要手工加双引号,APEX 会按值类型转义;如果 API 需要 JSON null 而不是空字符串,可使用 #COMM!NULL#

图 13-18 PUT / Update Row 操作中的 Request Body Template。

如果请求体需要由 PL/SQL 动态生成,可定义 Request Body 参数,例如 PAYLOAD,并把模板写成 #PAYLOAD!RAW#!RAW 表示把参数值按原样放入请求体,避免再次 JSON 转义。

13.3.7 使用参数传入与返回值#

REST Data Source 参数类似 PL/SQL 过程参数,可定义为 INOUTIN/OUT。参数可以放在数据源级,也可以放在某个操作级;可以设置默认值、Required、Static,并在页面区域或 LOV 中按使用场景传入。

参数类型方向用途
URL PatternIN在 URL Pattern 中用 :Name{Name}
URL Query StringIN作为 Name=Val 放入 URL 查询字符串。
HTTP HeaderIN / OUT / IN/OUT设置或返回 HTTP header 值。
Request or Response BodyIN / IN/OUT在模板中用 #Name##Name!NULL##Name!RAW#
Request or Response BodyOUT / IN/OUT返回整个响应体。
Data Profile ColumnOUT从单行响应中返回某个 Data Profile 列。

固定的 Content-Type: application/json 可用静态 HTTP Header 参数。认证和授权相关参数不要这样配置,应使用 Web Credential。

13.4 声明式调用 REST 操作#

Invoke API 页面流程可以无代码调用 REST Data Source Operation。配置时把 API Type 设为 REST Source,选择数据源和操作,再把输入参数绑定到页面项、表达式或工作流变量;如果操作返回值,也可以映射回页面项。

图 13-19 使用 Invoke API 页面流程调用 REST Data Source 操作。
图 13-20 用页面项为 REST Data Source 参数赋值。

参数也可以来自表达式。官方示例用 json_date() 将页面项日期转成 REST API 需要的 ISO 8601 JSON 值:空值返回未加引号的 null,有值返回已经带双引号的日期字符串。模板中再配合 !RAW,避免 APEX 二次转义。

图 13-21 用表达式配置 Invoke API 页面流程参数。
create or replace function json_date(
  p_item in varchar2)
  return varchar2
is
  l_value varchar2(255) := apex_session_state.get_timestamp(p_item);
begin
  return case
    when l_value is null then 'null'
    else apex_string.format(
      '"%s"',
      to_char(
        apex_session_state.get_timestamp(p_item),
        apex_json.c_date_iso8601))
  end;
end;

Invoke API 场景与 Form/Interactive Grid 自动 DML 不同:每个请求体值通常显式定义为 Request Body 参数,字符串替换需要自己在模板里放双引号。

图 13-22 用于 Invoke API 的 REST Data Source,可没有 Data Profile 列。
图 13-23 Invoke API 调用的 REST Data Source Operation。
{
  "job" :"#P_JOB#",
  "mgr" : #P_MGR!NULL#,
  "sal" : #P_SAL!NULL#,
  "comm" : #P_COMM!NULL#,
  "empno" : #P_EMPNO!NULL#,
  "ename" :"#P_ENAME#",
  "deptno" : #P_DEPTNO!NULL#,
  "hiredate": #P_HIREDATE!RAW#
}

13.5 在代码中使用 REST API#

声明式 REST Data Source 是首选,因为它能复用凭据、Data Profile、参数、分页和调试能力。需要在 PL/SQL 中处理远程行或执行操作时,优先使用 APEX_EXEC;只有在需要二进制请求或响应,或必须完全控制 HTTP 细节时,再使用 APEX_WEB_SERVICE.MAKE_REST_REQUEST

13.5.1 在代码中处理 REST Source 行#

APEX_EXEC 通过 context 处理 REST Source 行。查询时打开 query context 并循环读取行;修改时打开 DML context、添加 DML 行、设置列值、执行 DML,最后无论成功或异常都关闭 context。

13.5.1.1 查询 REST Source 行#

查询时使用 OPEN_REST_SOURCE_QUERY。先用 APEX_EXEC.T_COLUMNS 声明要取回的列,用 APEX_EXEC.T_PARAMETERS 传入操作参数,再用 NEXT_ROW 循环读取。

declare
  l_params apex_exec.t_parameters;
  l_cols apex_exec.t_columns;
  l_ctx apex_exec.t_context;
  l_empno number;
  l_ename varchar2(255);
  l_hiredate date;
begin
  apex_exec.add_column(l_cols, 'EMPNO');
  apex_exec.add_column(l_cols, 'ENAME');
  apex_exec.add_column(l_cols, 'HIREDATE');

  apex_exec.add_parameter(
    p_parameters => l_params,
    p_name       => 'MY_PARAM',
    p_value      => 1234);

  l_ctx := apex_exec.open_rest_source_query(
    p_static_id  => 'employees_simple_http',
    p_columns    => l_cols,
    p_parameters => l_params);

  while apex_exec.next_row(l_ctx) loop
    l_empno := apex_exec.get_number(l_ctx, 'EMPNO');
    l_ename := apex_exec.get_varchar2(l_ctx, 'ENAME');
    l_hiredate := apex_exec.get_date(l_ctx, 'HIREDATE');
  end loop;

  apex_exec.close(l_ctx);
exception
  when others then
    apex_exec.close(l_ctx);
    raise;
end;

该函数还支持 order by、filter、最大行数和起始行号。注意 Simple HTTP 默认是在 APEX 数据库中取回后再排序过滤,而 Fusion Applications、ORDS、OData 类型通常会把过滤、排序和分页下推给远程 API。

13.5.1.2 修改 REST Source 行#

修改时使用 OPEN_REST_SOURCE_DML_CONTEXT。列定义必须包含数据类型,至少一个列要标记为主键。然后调用 ADD_DML_ROW 指定 insert、update 或 delete,使用 SET_VALUE 填充当前行,最后 EXECUTE_DML

13.5.1.2.1 插入 REST Source 行#

插入示例向 employees_simple_http REST Data Source 添加两名员工。重点是先声明所有要发送的列和主键,再为每一行调用 ADD_DML_ROW(...c_dml_operation_insert) 并设置列值。

apex_exec.add_dml_row(l_dml_ctx, apex_exec.c_dml_operation_insert);
apex_exec.set_value(l_dml_ctx, 'EMPNO', 1234);
apex_exec.set_value(l_dml_ctx, 'ENAME', 'LUCY');
apex_exec.set_value(l_dml_ctx, 'HIREDATE', date '2025-06-27');

apex_exec.add_dml_row(l_dml_ctx, apex_exec.c_dml_operation_insert);
apex_exec.set_value(l_dml_ctx, 'EMPNO', 1235);
apex_exec.set_value(l_dml_ctx, 'ENAME', 'LEO');
apex_exec.set_value(l_dml_ctx, 'HIREDATE', date '2025-05-14');

apex_exec.execute_dml(l_dml_ctx);
13.5.1.2.2 更新 REST Source 行#

更新示例为了支持 lost update protection,会先用另一个按主键查询的 REST Data Source 取回现有员工,再打开原数据源的 DML context,设置 row version checksum,复制现有值,然后只改需要变更的列。这样可以避免覆盖远端已经被其他用户更新的数据。

图 13-24 用 URL Pattern 参数按主键获取一个员工。

按主键返回单个对象时,响应不是 items 数组,而是一个单独 JSON object。因此这个专用 REST Data Source 的 Data Profile 不设置 Row Selector,并启用 Contains Single Row。

图 13-25 单行响应 Data Profile 不使用 Row Selector,并启用 Contains Single Row。
13.5.1.2.3 删除 REST Source 行#

删除通常只需要主键列,因为 Delete Row 操作没有属性载荷。示例删除 EMPNO 为 7369 的员工。

apex_exec.add_column(
  p_columns        => l_cols,
  p_column_name    => 'EMPNO',
  p_data_type      => apex_exec.c_data_type_number,
  p_is_primary_key => true);

l_dml_ctx := apex_exec.open_rest_source_dml_context(
  p_static_id => 'employees_simple_http',
  p_columns   => l_cols);

apex_exec.add_dml_row(l_dml_ctx, apex_exec.c_dml_operation_delete);
apex_exec.set_value(l_dml_ctx, 'EMPNO', 7369);
apex_exec.execute_dml(l_dml_ctx);

13.5.2 以编程方式调用 REST 操作#

当 REST API 更像一个函数调用,而不是一组可查询行时,可以使用 APEX_EXEC.EXECUTE_REST_SOURCE。官方示例是单本图书下单 API:请求体包含 ISBN 和数量,响应体返回订单号和预计送达日期。

{
  "isbn": "978-1565926912",
  "quantity": 1
}
{
  "orderNumber": 12345,
  "estimatedDelivery": "2025-07-06T00:00:00"
}

13.5.2.1 配置用于调用的 REST Source#

如果 API 没有可自动发现的 GET 方法或 OpenAPI 描述,可在向导中选择 Create REST Source Manually。手工创建后,先调整 Data Profile:删除占位列,设置响应列名、数据类型和 JSON Selector。例如订单响应可定义 ORDER_NUMBERESTIMATED_DELIVERY 两列。

图 13-26 单本图书创建 API 响应负载的 Data Profile。
图 13-27 ESTIMATED_DELIVERY 日期列的格式掩码配置。

随后只保留所需 POST 操作,设置名称、Static ID、Request Body Template 和请求体参数。示例操作使用 P_ISBNP_QUANTITY 作为必填 Request Body 参数,并把响应中的 Data Profile Column 配成输出参数。

{
  "isbn" : "#P_ISBN#",
  "quantity": #P_QUANTITY#
}
图 13-28 Single Book Create REST API 的 POST 操作。

如果 API 需要 Content-Type: application/json,可添加静态 Header 参数。单对象响应不需要分页,因此 Pagination Type 设为 No Pagination。

图 13-29 配置完成后的 Single Book Order REST Data Source。

13.5.2.2 在代码中调用 REST 操作#

代码调用时,先用 APEX_EXEC.T_PARAMETERSADD_PARAMETER 设置入参,再调用 EXECUTE_REST_SOURCE,最后用 GET_PARAMETER_VARCHAR2GET_PARAMETER_CLOB 读取输出参数。

declare
  l_params apex_exec.t_parameters;
  l_new_order_number number;
  l_estimated_delivery date;
begin
  apex_exec.add_parameter(l_params, 'P_ISBN', '978-1565926912');
  apex_exec.add_parameter(l_params, 'P_QUANTITY', 1);

  apex_exec.execute_rest_source(
    p_static_id           => 'single_book_order',
    p_operation_static_id => 'single_book_create',
    p_parameters          => l_params);

  l_new_order_number := apex_exec.get_parameter_varchar2(
    l_params, 'ORDER_NUMBER');
  l_estimated_delivery := to_date(apex_exec.get_parameter_varchar2(
    l_params, 'ESTIMATED_DELIVERY'));
end;

13.5.3 不使用 Data Source 调用 REST API#

需要发送二进制请求体或接收二进制响应时,应使用 APEX_WEB_SERVICE。普通 REST 调用也可以这样写,但分页、JSON 解析、状态码、错误处理、凭据、调试和响应映射都要自己完成。二进制请求使用 p_body_blob,二进制响应使用 MAKE_REST_REQUEST_B

l_response_payload := apex_web_service.make_rest_request(
  p_http_method          => 'POST',
  p_url                  => c_endpoint_url,
  p_body                 => l_request.to_clob,
  p_credential_static_id => null,
  p_token_url            => null);

如果状态码成功且响应非空,再用 JSON_OBJECT_T 解析响应并读取 orderNumberestimatedDelivery 等属性。除非确有特殊需要,优先把 API 定义成 REST Data Source。

13.6 Fusion Apps、ORDS 与 OData 的额外能力#

当一类 REST API 在过滤、排序、字段选择、修改和错误结构上有统一约定时,APEX 可以提供比 Simple HTTP 更强的低代码体验。内置类型包括 Oracle Cloud Applications (SaaS)、Oracle Cloud Applications (BOSS)、Oracle REST Data Services 和 OData。

  • 向导可根据元数据自动发现操作和 Data Profile 列。
  • 运行时可自动添加必要参数和请求体,不必手工维护常见模板。
  • 过滤和排序可委托给后端系统,利用远程索引,只把需要的结果返回给 APEX。
  • Oracle Cloud Applications REST Data Source 可按当前区域所需字段缩小响应负载,并把业务对象校验错误显示为 APEX 错误。
  • 对 Interactive Grid 等场景,可利用 bulk API DML 能力。

验证时应查看 Debug 日志,确认过滤、排序和字段选择确实被放入远程 API 请求,而不是在本地取回后才处理。

13.7 REST Data Source 高级能力#

REST Data Source 不只是远程读取。它可以缓存 GET 响应,把参考数据同步到本地表,添加计算列,设置默认过滤和排序,把远程结果与本地 SQL 后处理结合,也可以通过自定义插件支持 APEX 原生不理解的 API 约定。

13.7.1 缓存 GET 操作响应#

对选定 GET 操作启用服务器端缓存,可以减少重复 HTTP 调用。缓存可跨所有用户共享、按用户保存或限定在当前会话内;失效时间可用分钟数,也可用 DBMS_SCHEDULER calendar expression。失效值为 0 时,仅在当前页面执行期间缓存,适合多个区域共用同一 REST Data Source 的页面。

如果应用修改了会影响缓存结果的远程数据,应在相应处理逻辑中调用 APEX_EXEC.PURGE_REST_SOURCE_CACHE() 清理指定 REST Data Source 的缓存。

13.7.2 本地同步数据#

对于变化不频繁的远程参考数据,APEX 可以为 REST Data Source 创建并维护本地缓存表。你可以配置同步计划,也可以调用 APEX_REST_SOURCE_SYNC.SYNCHRONIZE_DATA 按需刷新。LOV 中启用 Use Synchronization Table,或区域中启用 REST Synchronization 下的 Use Local Table 后,运行时会读取本地表而不是每次远程请求。

13.7.3 添加计算 Data Profile 列#

计算列可以用响应中已有列派生新值,并在区域、LOV 或代码中作为只读列使用。示例中响应包含 firstNamelastName,Data Profile 已有 FIRST_NAMELAST_NAME 后,可添加 SQL Expression 类型列 FULL_NAME

FIRST_NAME || ' ' || LAST_NAME

其他计算列类型还包括 Lookup 和 SQL Query (return single value)。使用时要注意:计算发生在 APEX 处理远程响应之后,不会改变远程 API 返回的原始数据。

13.7.4 配置默认过滤和排序#

Oracle Cloud Applications、ORDS 和 OData 等 REST Data Source 类型支持各自的声明式外部过滤和排序语法。区域或 LOV 启用 External Filter and Order By 后,可写入后端服务能理解的表达式。

StatusCode = 'OPEN' and WinProb >= 75
WinProb:desc,PrimaryContactPartyName:asc

配置前必须查阅目标服务文档,因为 Fusion Applications、ORDS 和 OData 对过滤、排序语法的要求不同。验证时检查请求 URL 或请求体,确认表达式被传给远程服务。

13.7.5 过滤、排序、连接或聚合远程数据#

当远程 API 不支持所需的过滤、排序、连接或聚合时,可使用 Local Post-Processing 在 APEX 数据库中处理已取回的 JSON 行列结果。这种方式灵活,但远程数据仍然要先取回本地,因此不适合超大结果集。

13.7.5.1 理解 JSON_TABLE 查询#

APEX 使用 Data Profile 信息动态生成 JSON_TABLE() 查询,把响应 CLOB 映射为关系型结果。以 Employees API 为例,Data Profile 中的 EMPNOENAMEHIREDATE 会变成 JSON path 列,再按声明的数据类型转换。

select "EMPNO", "ENAME", "HIREDATE"
from (
  select to_number("EMPNO") as "EMPNO",
         "ENAME" as "ENAME",
         to_date("HIREDATE", 'YYYY-MM-DD"T"HH24:MI:SS"Z"') as "HIREDATE"
  from json_table(
    response_payload format json,
    '$."items"[*]'
    columns (
      "EMPNO" varchar2(4000) path '$."empno"',
      "ENAME" varchar2(4000) path '$."ename"',
      "HIREDATE" varchar2(4000) path '$."hiredate"'
    )
  )
)

理解这个结构有助于判断后续 WHERE、ORDER BY 或自定义 SQL 能引用哪些列,以及类型转换发生在哪里。

13.7.5.2 本地过滤与排序远程数据#

把区域或 LOV 的 Local Post-Processing 设为 Where/Order By Clause 后,可以添加本地 WHERE 和 ORDER BY。这些子句追加在 APEX 生成的最外层 SQL 上,因此只能引用最外层 SELECT list 中已有的列;若需要按未显示列过滤或排序,应把该列加入区域并隐藏。

HIREDATE > DATE '1981-10-31'
HIREDATE DESC

这会先从远程 API 取得原始 Employees 数据,再在 APEX 数据库中过滤 1981 年 10 月之后入职的员工,并按入职日期倒序显示。

13.7.5.3 使用涉及远程数据的自定义 SQL#

把 Local Post-Processing 设为 SQL Query 后,可通过 #APEX$SOURCE_DATA# 内联视图访问 APEX 原本生成的远程数据结果。初始 SQL 通常只是原样选择列,你可以加入本地表连接、表达式、聚合或重命名。

select r.EMPNO,
       r.ENAME,
       r.HIREDATE,
       c.NAME as COURSE_NAME,
       t.STATUS
  from #APEX$SOURCE_DATA# r
  join EMP_TRAINING t
    on r.EMPNO = t.EMPNO
  join EMP_COURSE c
    on t.COURSE_ID = c.ID
 where t.STATUS in ('COMPLETED','CERTIFIED')

要求只有两个:SQL 必须语法正确,并且包含 #APEX$SOURCE_DATA#。需要动态 SQL 时,可以改用 PL/SQL Function Body Returning SQL Query。

13.7.6 创建自定义 REST Source 插件#

如果某组 API 有固定约定,但 APEX 原生类型不支持,可以创建 REST Data Source 插件。插件会成为 Create REST Data Source 向导中的新类型,让团队复用你封装的发现、分页、过滤、排序、DML 或执行逻辑。

契约过程作用
Capabilities声明是否支持服务器端过滤、排序和分页。
Discover根据服务元数据发现操作、参数和 Data Profile 列。
Fetch检索数据,并可支持服务器端过滤、排序和分页。
DML保存 Form、Interactive Grid 或 APEX_EXEC 产生的数据变更。
Execute处理 Invoke API 或 EXECUTE_REST_SOURCE 调用场景。

可参考 Oracle APEX GitHub 仓库中对应版本的 plugins/rest-source 示例。插件属于平台级扩展,应配套版本管理、测试和 API 契约文档。

13.8 调试 REST API 错误#

REST API 运行时可能返回 HTTP 400、401、403、404 或 500。APEX 内置 Debug tracing 能显示请求 URL、方法、参数、请求体、响应体、状态码和错误栈,是定位 REST Data Source 问题的首选工具。

官方示例中,Interactive Report 使用 Fusion Applications Sales Opportunities REST Data Source。用户在 Actions > Data > Sort 中把 Assignment Mode 设为第三个排序列,点击 Apply 后收到 ORA-20999: REST Data Source returned an HTTP error: HTTP 400: Bad request

图 13-30 基于 Fusion Apps Sales Opportunities REST Data Source 的 Interactive Report。
图 13-31 通过开发者工具栏启用 Debug tracing 来诊断 HTTP 400。

从 App Builder 运行应用时,开发者工具栏默认显示在页面底部。选择 Debug > Current Debug Level > Info 后,当前页会刷新并开始生成 debug trace。之后每个页面请求或 Ajax 刷新都会产生对应 trace。选择 Debug > View Debug 可打开最近 trace 列表。

图 13-32 在 Debug Viewer 中识别最近请求并进入详情。

Debug 详情页的时间线用红点标识错误位置。Info 级别通常足够定位多数问题;必要时再提高 Debug 级别。点击红点或相关日志行,找到第一个远程调用错误,而不是只看最终页面异常。

图 13-33 通过 Debug trace 时间线快速定位错误。

示例的响应负载说明 AssignmentMode 不可排序。向上查找前一个 REST API 调用,可看到 APEX 把用户排序配置委托成远程 API 的 orderBy 查询字符串。

making GET request to https://server/crmRestApi/resources/11.13.18.05/opportunities
?onlyData=true
&fields=TargetPartyName,Revenue,CurrencyCode,WinProb,PrimaryContactPartyName,...
&orderBy=WinProb:desc,Revenue:desc,AssignmentMode:asc
&limit=500
图 13-34 检查第一处错误和之前的 REST API 调用。

修复方法是回到 Page Designer,选中 Interactive Report 的 ASSIGNMENTMODE 列,关闭 Enable Users To > Sort。这样最终用户在排序对话框中不再能选择该不可排序列。

图 13-35 在列属性中关闭 Assignment Mode 的排序能力。
图 13-36 修复后,用户不能再选择不可排序的 Assignment Mode 列。
  • 验证点:重新运行页面,打开 Actions > Data > Sort,确认 Assignment Mode 不在可排序列列表中。
  • 预期结果:Interactive Report 可正常刷新,不再触发远程服务的 HTTP 400。
  • 后续处理:诊断完成后关闭 Debug tracing,避免继续产生不必要的调试日志。