18.4.8.8 Using BOSS REST Data Sources in PL/SQL
Use BOSS REST Data Sources to show data in any APEX region
When using BOSS REST Data Sources based on business object endpoints
with form and interactive grid regions, you can also insert, update, and delete
data. None of these capabilities requires writing any code to achieve, however
sometimes you may need to interact with a BOSS endpoint programmatically using the
APEX_EXEC
package. Use cases include:
- Creating pipelined table functions that programmatically reshape BOSS data.
- Working programmatically with BOSS endpoints in APEX business logic, workflows, automations, or background execution chain processes.
- Arbitrary scripting tasks involving interacting with BOSS endpoints.
Each BOSS REST data source has a unique identifier that APEX calls its static id. For example, an APEX developer creating a REST Data Source for a BOSS endpoint
../v1/opportunities
might configure its static id to be
opportunities
. This is the identifier you use when working with
the functions in the APEX_EXEC
package.
Retrieving Data from a BOSS Endpoint
To retrieve data from a BOSS endpoint, use the
apex_exec.open_rest_source_query
function to create an
apex_exec.t_context
object that works like a cursor, then use a
while apex_exec.next_row(ctx) loop
to iterate through the results.
For each iteration, use the apex_exec.get_xxx()
functions to access
the attribute values from the current query result row. When done, call
apex_exec.close()
to close the context. For example:
declare
l_ctx apex_exec.t_context;
-- other declarations here
begin
-- Process top five winnable opportunties for salesperson 12345 by amount
-- get_opportunities_columns() returns apex_exec.t_columns for columns
-- corresponding to fields: optyId,amount,customerName,closeDate
l_ctx := apex_exec.open_rest_source_query(
p_static_id => 'opportunities',
p_columns => get_opportunities_columns,
p_external_filter_expr => 'resourceId = 12345 and winPct > 0.80',
p_external_order_by_expr => 'amount:desc'
p_max_rows => 5);
while apex_exec.next_row(l_ctx) loop
l_amount := apex_exec.get_number(l_ctx,'AMOUNT');
l_customer := apex_exec.get_varchar2(l_ctx,'CUSTOMERNAME');
l_closes := apex_exec.get_date(l_ctx,'CLOSEDATE');
-- Work with data here...
end loop;
apex_exec.close(l_ctx);
exception
when others then
apex_exec.close(l_ctx);
raise;
end;
Inserting Data Using a BOSS Endpoint
To insert data using a BOSS endpoint, use the
apex_exec.open_rest_source_dml_context
function to create an
apex_exec.t_context
object that works like a temporary rowset.
Then for each new row you want to add, call apex_exec.add_dml_row()
and then use apex_exec.set_value()
to set the value of each
attribute necessary. Finally, to process the pending changes call
apex_exec.execute_dml()
. When done, call
apex_exec.close()
to close the context. For example:
declare
l_ctx apex_exec.t_context;
-- other declarations here
begin
-- Insert two new opportunities
-- get_opportunities_columns() returns apex_exec.t_columns for columns
-- corresponding to fields: APEX$ResourceKey,optyId,amount,customerName,closeDate
l_ctx := apex_exec.open_rest_source_dml_context(
p_static_id => 'opportunities',
p_columns => get_opportunities_columns,
p_lost_update_detection => apex_exec.c_lost_update_none);
apex_exec.add_dml_row(l_ctx, apex_exec.c_dml_operation_insert);
apex_exec.set_value(l_ctx,'AMOUNT',45000);
apex_exec.set_value(l_ctx,'CUSTOMERNAME','Tesla');
apex_exec.set_value(l_ctx,'CLOSEDATE','2024-05-11');
apex_exec.add_dml_row(l_ctx, apex_exec.c_dml_operation_insert);
apex_exec.set_value(l_ctx,'AMOUNT',1500000);
apex_exec.set_value(l_ctx,'CUSTOMERNAME','Apple');
apex_exec.set_value(l_ctx,'CLOSEDATE','2024-06-30');
-- Save the changes
apex_exec.execute_dml(l_ctx);
apex_exec.close(l_ctx);
exception
when others then
apex_exec.close(l_ctx);
raise;
end;
Updating Existing Row Using a BOSS Endpoint
To update data using a BOSS endpoint, use the
apex_exec.open_rest_source_dml_context
function to create an
apex_exec.t_context
object that works like a temporary rowset.
Then for each row you want to update, call apex_exec.add_dml_row()
with the update operation constant and then use
apex_exec.set_value()
to set the value of each attribute
necessary. Finally, to process the pending changes call
apex_exec.execute_dml()
. Often you will preface this with a
query to retrieve the row first to consider its existing values, before updating
some of them. In that case you can call apex_exec.set_values()
to
copy all the row values from the queried row into the row to be updated. For
example:
declare
l_ctx apex_exec.t_context;
l_dml_ctx apex_exec.t_context;
-- other declarations here
begin
-- Retrieve and update opportunity with resource key 98765
-- to increase its amount by 10% and close date by one week
-- get_opportunities_columns() returns apex_exec.t_columns for columns
-- corresponding to fields: optyId,amount,customerName,closeDate
l_ctx := apex_exec.open_rest_source_query(
p_static_id => 'opportunities',
p_columns => get_opportunities_columns,
p_external_filter_expr => 'optyId = 98765'
p_max_rows => 1);
if not apex_exec.next_row(l_ctx) then
raise_application_error(-20001,'Opportunity 98765 not found');
end if;
l_dml_ctx := apex_exec.open_rest_source_dml_context(
p_static_id => 'opportunities',
p_columns => get_opportunities_columns,
p_lost_update_detection => apex_exec.c_lost_update_implicit);
apex_exec.add_dml_row(l_ctx, apex_exec.c_dml_operation_update);
apex_exec.set_row_version_checksum(
p_context => l_dml_context,
p_checksum => apex_exec.get_row_version_checksum(l_ctx));
-- Copy the values of the fetched opportunity into the update row
apex_exec.set_values(
p_context => l_dml_ctx,
p_source_context => l_ctx );
-- Adjust the amount and closeDate appropriately
apex_exec.set_value(l_dml_ctx,'AMOUNT',
apex_exec.get_number(l_dml_ctx,'AMOUNT') * 1.1);
apex_exec.set_value(l_dml_ctx,'CLOSEDATE',
apex_exec.get_date(l_dml_ctx,'CLOSEDATE') + 7);
-- Save the changes
apex_exec.execute_dml(l_dml_ctx);
apex_exec.close(l_dml_ctx);
apex_exec.close(l_ctx);
exception
when others then
apex_exec.close(l_dml_ctx);
apex_exec.close(l_ctx);
raise;
end;
Deleting an Existing Row Using a BOSS Endpoint
To delete data using a BOSS endpoint, use use the
apex_exec.open_rest_source_dml_context
function to create an
apex_exec.t_context
object that works like a temporary rowset.
Then for each row you want to delete, call apex_exec.add_dml_row()
with the delete operation constant and then use
apex_exec.set_value() to set the value of the resource
key column APEX$RESOURCEKEY
. Finally, to process the pending
changes call apex_exec.execute_dml()
. For example:
declare
l_dml_ctx apex_exec.t_context;
-- other declarations here
begin
-- Delete opportunity with resource key 98765
-- get_resource_key_columns returns apex_exec.t_columns for columns
-- corresponding to fields: APEX$ResourceKey
l_dml_ctx := apex_exec.open_rest_source_dml_context(
p_static_id => 'opportunities',
p_columns => get_resource_key_columns,
p_lost_update_detection => apex_exec.c_lost_update_implicit);
apex_exec.add_dml_row(l_dml_ctx, apex_exec.c_dml_operation_delete);
-- Set the resource key of the row to be deleted
apex_exec.set_value(l_dml_ctx,'APEX$RESOURCEKEY', '98765');
-- Save the changes
apex_exec.execute_dml(l_dml_ctx);
apex_exec.close(l_dml_ctx);
exception
when others then
apex_exec.close(l_dml_ctx);
raise;
end;
Note:
If you need to first fetch the row to reason over its attributes before deciding to delete it, then follow the update example above but use the delete operation instead of the update operation when adding the DML row. Finally, to process the pending changes callapex_exec.execute_dml()
.