Professional Documents
Culture Documents
APEX 18.1
In this blog posting we will highlight the new REST capabilities of Application Express
18.1 once more. This time we will show how to create a form to insert, update or delete
rows - but not from a table, the form will work on a REST service instead.
APEX 18.1 provides declarative support to build components on top of a REST service.
However, only Read Only components like like reports or charts can use Web Source
Modules directly; there is no wizard to create a form on a Web Source Module.
So we have to implement some custom PL/SQL code in order to build a DML form on a
REST service. As this blog posting shows, Web Source Modules can still do a lot of the
work for us: We will still be able to use the APEX_EXEC package - no manual JSON
parsing will be required and we won't have to do any manual HTTP request.
Note that full declarative support for Read/Write components like Forms or the
Interactive Grid is planned for one of the next releases of Application Express - when
that is available, you will be able to create a Form on a REST service directly, without
any manual work at all - as you can do today with a report.
1 begin
2 ords.enable_schema;
3 ords.enable_object( p_object => 'EMP' );
4 end;
5 /
Then, to check whether the REST Service works, try to execute the REST Service using
a browser or the "curl" command line utility. Use the
URL: http://{ords-server}:{port}/ords/{schema}/emp/. With a browser, the response
should look as follows:
Create the APEX Web Source Module
Then, head over to Application Express, log into your workspace and create an
application. Navigate to Shared Components and lookup Web Source Modules. In a
new application, this section is empty. Click the Create button in order to create a new
Web Source Module from Scratch.
The request body contains the data for the new row in JSON format.
UPDATE:
The request body contains the data for the new row in JSON format.
DELETE:
curl -H"Content-Type:application/json" \
1 -X POST \
2 -d'{"empno":4711,"ename":"APEX","job":"DEV","hiredate":"2001-01-
3 01T20:00:00Z","sal":10,"comm":null,"deptno":10,"mgr":7839}' \
4 http://localhost:28080/ords/testit/emp/
You should see the following response, indicating that the operation was successful.
{"empno":4711,"ename":"APEX","job":"DEV","mgr":7839,"hiredate":"2001-01-
01T20:00:00Z","sal":10,"comm":null,"deptno":10,"links":
[{"rel":"self","href":"http://localhost:28080/ords/testit/emp/4711"},
{"rel":"edit","href":"http://localhost:28080/ords/testit/emp/4711"},
{"rel":"describedby","href":"http://localhost:28080/ords/testit/metadata-
catalog/emp/item"},{"rel":"collection","href":"http://localhost:28080/
ords/testit/emp/"}]}
Look up your new web source module in Shared Components. First, navigate to
the Advancedtab and note down the exact Static ID value of the Web Source Module
(here: Auto_REST_Service_EMP). We'll need that later on.
We can see that APEX already did some work for us. Since this is an ORDS REST
Service, APEX detected, that URL endpoints for POST, PUT and DELETE exist and it
added these to the REST Service meta data.
Click Apply Changes and then the pencil again to come back to this form. Then click
the Add Parameter button to open the Operation Parameter dialog.
For each column name, which you have created a #PLACEHOLDER# for, add a
Parameter of the Request / Response Body type.
When finished, you should have eight Operation Parameters, one for each column of
the EMP table. Then add another parameter of Type HTTP Header with Content-
Type as its name and application/json as the value. The Operation
Parameters section for the POST operation should finally look as follows.
Then add Web Source Parameters as well, similar as done for the POST operations:
the Name and application/json as the value
Next, we'll add functionality to populate the form with values on page load. We'll need
do this using custom PL/SQL code and the APEX_EXEC package. The blog
posting APEX 18.1 Early Adopter 2: REST Services and PL/SQL contains a good
template for our form loading process.
In Page Designer, navigate to the Before Headers section in the page tree on the left
and create a new Process.
Name the process Load REST Data and provide the following PL/SQL Code:
1 declare
2 l_columns apex_exec.t_columns;
3 l_context apex_exec.t_context;
4 l_filters apex_exec.t_filters;
5
6 type t_column_position is table of pls_integer index by varchar2(32767);
l_column_position t_column_position;
7
begin
8
-- specify columns to select from the web source module
9 apex_exec.add_column( p_columns => l_columns, p_column_name => 'EMPNO');
10 apex_exec.add_column( p_columns => l_columns, p_column_name => 'ENAME');
11 apex_exec.add_column( p_columns => l_columns, p_column_name => 'JOB');
12 apex_exec.add_column( p_columns => l_columns, p_column_name => 'HIREDATE');
13 apex_exec.add_column( p_columns => l_columns, p_column_name => 'MGR');
14 apex_exec.add_column( p_columns => l_columns, p_column_name => 'SAL');
15 apex_exec.add_column( p_columns => l_columns, p_column_name => 'COMM');
16 apex_exec.add_column( p_columns => l_columns, p_column_name => 'DEPTNO');
17
18 -- add a filter to query only the selected row
19 apex_exec.add_filter(
20 p_filters => l_filters,
21 p_column_name => 'EMPNO',
p_filter_type => apex_exec.c_filter_eq,
p_value => to_number( :P2_EMPNO ) );
22 -- invoke Web Source Module and select data
23 l_context := apex_exec.open_web_source_query(
24 p_module_static_id => 'Auto_REST_Service_EMP',
p_filters => l_filters,
25
p_columns => l_columns );
26
27 -- now get result set positions for the selected columns
28 for c in 1 .. l_columns.count loop
29 l_column_position( l_columns( c ).name ) :=
30 apex_exec.get_column_position( l_context, l_columns( c ).name );
31 end loop;
32
33 -- if we have a result set, set the form items
34 if apex_exec.next_row( l_context ) then
35 :P2_ENAME := apex_exec.get_varchar2( l_context,
36 l_column_position( 'ENAME' ) );
37 :P2_JOB := apex_exec.get_varchar2( l_context, l_column_position( 'JOB'
38 ) );
39 :P2_HIREDATE := apex_exec.get_varchar2( l_context,
40 l_column_position( 'HIREDATE' ) );
41 :P2_SAL := apex_exec.get_number ( l_context, l_column_position( 'SAL'
42 ) );
43 :P2_COMM := apex_exec.get_number ( l_context,
44 l_column_position( 'COMM' ) );
45 :P2_MGR := apex_exec.get_number ( l_context, l_column_position( 'MGR'
46 ) );
47 :P2_DEPTNO := apex_exec.get_number ( l_context,
48 l_column_position( 'DEPTNO' ) );
49 -- otherwise raise NO_DATA_FOUND
50 else
51 raise no_data_found;
end if;
52
53
-- finally: release all resources
54 apex_exec.close( l_context );
55 exception
56 when others then
57 -- IMPORTANT: also release all resources, when an exception occcurs!
58 apex_exec.close( l_context );
raise;
end;
Target: Page 2 (the form page); set Clear Cache for page 2 (the form page)
When clicking the link in the EMPNO column, the form page should be loaded and
populated with the values for the selected row; when clicking the Create New button, an
empty form should be loaded.
This concludes the first part of the form page. We loaded data from the REST service
into the page items without using any APEX_WEB_SERVICE call and without doing
any manual JSON parsing.
Add DML processes to the form
Before adding the PL/SQL code to process POST, PUT and DELETE requests add the
required buttons to the page:
1 declare
2 l_parameters apex_exec.t_parameters;
3 begin
4
5 -- add the primary key value as the "id" parameter; this will be appended
6 to the URL for DELETE and APPLY_CHANGES
if :REQUEST in ( 'DELETE', 'APPLY_CHANGES' ) then
7
apex_exec.add_parameter( p_parameters => l_parameters, p_name => 'id',
8
p_value => :P2_EMPNO );
9 end if;
10
11 -- add form item values as parameters for CREATE and APPLY_CHANGES
12 if :REQUEST in ( 'CREATE', 'APPLY_CHANGES' ) then
13 apex_exec.add_parameter( p_parameters => l_parameters, p_name =>
14 'ENAME', p_value => :P2_ENAME );
15 apex_exec.add_parameter( p_parameters => l_parameters, p_name =>
16 'EMPNO', p_value => :P2_EMPNO );
17 apex_exec.add_parameter( p_parameters => l_parameters, p_name =>
18 'JOB', p_value => :P2_JOB );
19 apex_exec.add_parameter( p_parameters => l_parameters, p_name =>
20 'HIREDATE', p_value => to_char( to_date( :P2_HIREDATE ), 'YYYY-MM-DD' ) ||
21 'T00:00:00Z' );
22 apex_exec.add_parameter( p_parameters => l_parameters, p_name =>
23 'SAL', p_value => :P2_SAL );
apex_exec.add_parameter( p_parameters => l_parameters, p_name =>
'COMM', p_value => coalesce( :P2_COMM, 'null' ) );
apex_exec.add_parameter( p_parameters => l_parameters, p_name =>
'MGR', p_value => :P2_MGR );
apex_exec.add_parameter( p_parameters => l_parameters, p_name =>
'DEPTNO', p_value => :P2_DEPTNO );
24
end if;
25
26
-- invoke Web Source Module for and select data
27 apex_exec.execute_web_source(
28 p_module_static_id => 'Auto_REST_Service_EMP',
29 p_operation => case :REQUEST
30 when 'APPLY_CHANGES' then 'PUT'
when 'CREATE' then 'POST'
when 'DELETE' then 'DELETE' end,
p_parameters => l_parameters );
end;
Click the Create New button below the report, enter some data and save a
new row
Update the Name value of that new row
Of course, this form can be further extended - think about validations, additional
processes and dynamic Actions. The interesting bit is, that we're able to use Web
Source Modules for a DML form, although APEX 18.1 does not provide declarative
support so far. Using a bit of additional meta data and some custom PL/SQL code using
the APEX_EXEC package we're able to build the form processes without using any
manual HTTP or JSON handling code.