In this post I will try to show you how I used the Oracle Apex and the APEX_WEB_SERVICE PL/SQL package to quickly send a request to a public Internet API and how I handled the response. The code below was written during a 'Hackday' and hasn't been extensively tested.
My use case is integrating Oracle Apex with the public Mendeley REST API for Mendeley Catalog Search.
The idea was to build an application in Oracle Apex to query the Mendeley REST API Catalog with a keyword. Mendeley REST API gives JSON response so I used PL/JSON to parse it. I hear in Oracle 12c JSON is going to be a native data-type. My Oracle Apex host is running Oracle 11g and I had to use PL/JSON for ease.
To cut it short here is how the Mendeley Catalog Search on Oracle Apex application look like. (Click image to go to app or visit http://apex2.enciva.co.uk/apex/f?p=864:2
To integrate with Mendeley REST API from Oracle Apex, I used one PL/SQL function and one procedure.
I used the function to obtain the Mendeley REST API Client Credentials Authorisation flow token and the procedure to do make the API request to Mendeley Catalog Search and to handle the response.
Here is the MENDELEY_CALL PL/SQL function I created:
This function returns the Client Credentials Authorisation Flow token from the Mendeeley REST API
create or replace function mendeley_call (p_id in varchar2)
return varchar2
is
v_token varchar2(1000);
token varchar2(1000);
jtoken json;
v_grant_type varchar2(400) := 'client_credentials';
v_client_id varchar2(500) := p_id;
v_client_secret varchar2(500) := '<put_your_mendeley_client_secret_here>';
v_scope varchar2(300) := 'all';
begin
/*----------Setting Headers----------------------------------------*/
apex_web_service.g_request_headers(1).name := 'Content-Type';
apex_web_service.g_request_headers(1).Value := 'application/x-www-form-urlencoded; charset=utf-8';
/*-----------------------------------------------------------------*/
token := apex_web_service.make_rest_request
(
p_url => 'https://api.mendeley.com/oauth/token'
, p_http_method => 'POST'
, p_parm_name => apex_util.string_to_table('grant_type:client_id:client_secret:scope')
, p_parm_value => apex_util.string_to_table(v_grant_type||':'||v_client_id||':'||v_client_secret||':'
||v_scope)
, p_wallet_path => 'file:/home/app/oracle/product/11.2.0/dbhome_1/owm/wallets/oracle'
, p_wallet_pwd => '<put_your_oracle_wallet_password_here>'
);
-- debug
-- dbms_output.put_line(token);
jtoken := json(token);
v_token := json_ext.get_string(jtoken,'access_token');
-- debug
-- dbms_output.put_line(v_token);
return v_token;
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20001,'An error was encountered - '||SQLCODE||' -ERROR- '||SQLERRM);
end;
Here is the anonymous procedure which I put into a PL/SQL region on the Oracle Apex page:
This procedure incorporates the function above and makes the request and handles the response from the Mendeley REST API
Note how the procedure calls the function MENDELEY_CALL (above) to load the variable v_token.
DECLARE
v_token VARCHAR2(599) := mendeley_call(put_your_mendeley_client_id_here);
v_search VARCHAR2(500);
mendeley_document NCLOB;
v_status VARCHAR2(100);
obj json_list;
v_id VARCHAR2(100);
v_title NVARCHAR2(1000);
v_abstract NCLOB;--varchar2(32000);
v_link VARCHAR2(1000);
v_source VARCHAR2(500);
v_type VARCHAR2(100);
v_pct_hit VARCHAR2(10);
v_rows NUMBER(10);
v_batch_id NUMBER(10);
BEGIN
-- Oracle Wallet
utl_http.set_wallet('file:/home/app/oracle/product/11.2.0/dbhome_1/owm/wallets/oracle',
'my_secret_password');
-- Set Authorisation headers and utf8
-- the following lilne is necessary if you need to use languages other than latin and
-- you will use APEX_WEB_SERVICE package
utl_http.set_body_charset('UTF-8');
-- build the Authorisation header
apex_web_service.g_request_headers(1).name := 'Content-Type';
apex_web_service.g_request_headers(1).value := 'application/jsonrequest';
apex_web_service.g_request_headers(1).name := 'Authorization';
apex_web_service.g_request_headers(1).value := 'Bearer '||v_token||'';
-- Make the request and load the response into a CLOB
mendeley_document := apex_web_service.make_rest_request
(
p_url => 'https://api.mendeley.com:443/search/catalog'
, p_http_method => 'GET'
, p_parm_name => apex_util.string_to_table('title:limit')
, p_parm_value => apex_util.string_to_table('Mendeley:10')
);
-- Load the response to JSON_LIST PL/JSON object
obj := json_list(mendeley_document);
-- Start extracting values from the JSON and writhe some HTML
-- Traverse over JSON_LIST extract elements you like
FOR i IN 1..obj.count
LOOP
v_id := json_ext.get_string(json(obj.get(i)),'id');
v_title := json_ext.get_string(json(obj.get(i)),'title');
v_abstract := json_ext.get_string(json(obj.get(i)),'abstract');
v_link := json_ext.get_string(json(obj.get(i)),'link');
v_source := json_ext.get_string(json(obj.get(i)),'source');
v_type := json_ext.get_string(json(obj.get(i)),'type');
-- write extracted data
dbms_output.put_line(v_title||' ==> '||v_abstract);
END LOOP;
END;
END;
This shows how easy is, in this case using one function and one procedure to make a REST API request to an external Web Service from Oracle Apex.
My use case is integrating Oracle Apex with the public Mendeley REST API for Mendeley Catalog Search.
The idea was to build an application in Oracle Apex to query the Mendeley REST API Catalog with a keyword. Mendeley REST API gives JSON response so I used PL/JSON to parse it. I hear in Oracle 12c JSON is going to be a native data-type. My Oracle Apex host is running Oracle 11g and I had to use PL/JSON for ease.
To cut it short here is how the Mendeley Catalog Search on Oracle Apex application look like. (Click image to go to app or visit http://apex2.enciva.co.uk/apex/f?p=864:2
To integrate with Mendeley REST API from Oracle Apex, I used one PL/SQL function and one procedure.
I used the function to obtain the Mendeley REST API Client Credentials Authorisation flow token and the procedure to do make the API request to Mendeley Catalog Search and to handle the response.
Here is the MENDELEY_CALL PL/SQL function I created:
This function returns the Client Credentials Authorisation Flow token from the Mendeeley REST API
create or replace function mendeley_call (p_id in varchar2)
return varchar2
is
v_token varchar2(1000);
token varchar2(1000);
jtoken json;
v_grant_type varchar2(400) := 'client_credentials';
v_client_id varchar2(500) := p_id;
v_client_secret varchar2(500) := '<put_your_mendeley_client_secret_here>';
v_scope varchar2(300) := 'all';
begin
/*----------Setting Headers----------------------------------------*/
apex_web_service.g_request_headers(1).name := 'Content-Type';
apex_web_service.g_request_headers(1).Value := 'application/x-www-form-urlencoded; charset=utf-8';
/*-----------------------------------------------------------------*/
token := apex_web_service.make_rest_request
(
p_url => 'https://api.mendeley.com/oauth/token'
, p_http_method => 'POST'
, p_parm_name => apex_util.string_to_table('grant_type:client_id:client_secret:scope')
, p_parm_value => apex_util.string_to_table(v_grant_type||':'||v_client_id||':'||v_client_secret||':'
||v_scope)
, p_wallet_path => 'file:/home/app/oracle/product/11.2.0/dbhome_1/owm/wallets/oracle'
, p_wallet_pwd => '<put_your_oracle_wallet_password_here>'
);
-- debug
-- dbms_output.put_line(token);
jtoken := json(token);
v_token := json_ext.get_string(jtoken,'access_token');
-- debug
-- dbms_output.put_line(v_token);
return v_token;
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20001,'An error was encountered - '||SQLCODE||' -ERROR- '||SQLERRM);
end;
Here is the anonymous procedure which I put into a PL/SQL region on the Oracle Apex page:
This procedure incorporates the function above and makes the request and handles the response from the Mendeley REST API
Note how the procedure calls the function MENDELEY_CALL (above) to load the variable v_token.
DECLARE
v_token VARCHAR2(599) := mendeley_call(put_your_mendeley_client_id_here);
v_search VARCHAR2(500);
mendeley_document NCLOB;
v_status VARCHAR2(100);
obj json_list;
v_id VARCHAR2(100);
v_title NVARCHAR2(1000);
v_abstract NCLOB;--varchar2(32000);
v_link VARCHAR2(1000);
v_source VARCHAR2(500);
v_type VARCHAR2(100);
v_pct_hit VARCHAR2(10);
v_rows NUMBER(10);
v_batch_id NUMBER(10);
BEGIN
-- Oracle Wallet
utl_http.set_wallet('file:/home/app/oracle/product/11.2.0/dbhome_1/owm/wallets/oracle',
'my_secret_password');
-- Set Authorisation headers and utf8
-- the following lilne is necessary if you need to use languages other than latin and
-- you will use APEX_WEB_SERVICE package
utl_http.set_body_charset('UTF-8');
-- build the Authorisation header
apex_web_service.g_request_headers(1).name := 'Content-Type';
apex_web_service.g_request_headers(1).value := 'application/jsonrequest';
apex_web_service.g_request_headers(1).name := 'Authorization';
apex_web_service.g_request_headers(1).value := 'Bearer '||v_token||'';
-- Make the request and load the response into a CLOB
mendeley_document := apex_web_service.make_rest_request
(
p_url => 'https://api.mendeley.com:443/search/catalog'
, p_http_method => 'GET'
, p_parm_name => apex_util.string_to_table('title:limit')
, p_parm_value => apex_util.string_to_table('Mendeley:10')
);
-- Load the response to JSON_LIST PL/JSON object
obj := json_list(mendeley_document);
-- Start extracting values from the JSON and writhe some HTML
-- Traverse over JSON_LIST extract elements you like
FOR i IN 1..obj.count
LOOP
v_id := json_ext.get_string(json(obj.get(i)),'id');
v_title := json_ext.get_string(json(obj.get(i)),'title');
v_abstract := json_ext.get_string(json(obj.get(i)),'abstract');
v_link := json_ext.get_string(json(obj.get(i)),'link');
v_source := json_ext.get_string(json(obj.get(i)),'source');
v_type := json_ext.get_string(json(obj.get(i)),'type');
-- write extracted data
dbms_output.put_line(v_title||' ==> '||v_abstract);
END LOOP;
END;
END;
This shows how easy is, in this case using one function and one procedure to make a REST API request to an external Web Service from Oracle Apex.
Thank you for your post.
ReplyDeleteI keep getting a SQL Error: ORA-20001: An error was encountered - -29273 -ERROR- ORA-29273: HTTP request failed
Any pointers would be appreciated
I have a working ACL and have loaded the endpoint certificate into my wallet
Thank you in advance
Hi there
ReplyDeleteAskTom has some comments on the issue here: https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:9526497800346930725
Hope is uselful
Thanks
Please ignore my previous comment, I found PL/JSON
ReplyDeleteRegards
S