Download presentation
Presentation is loading. Please wait.
1
Oracle REST data services
Pedro Martel :: BE-ICS-AC
2
What is it? “Oracle REST Data Services (ORDS) makes it easy to develop modern REST interfaces for relational data in the Oracle Database, Oracle Database 12c JSON Document Store, and Oracle NoSQL Database. A mid-tier Java application, ORDS maps HTTP(S) verbs (GET, POST, PUT, DELETE, etc.) to database transactions and returns any results formatted using JSON.” “ORDS is included with both Oracle Database and Oracle SQL Developer installs. It is supported in Weblogic, Tomcat, Glassfish, and also as a standalone application running Jetty in embedded mode.”
3
When should you use it? When you need to pass data to a non-Oracle environment. When you need to perform some sort of Role Based Access Control to data. When you want to authenticate/log the consumption of your data.
4
How does it work? Your data will be accessible via an URL (end point).
You can send whatever you want (JSON, XML, etc) in the body. Up to the consumer to treat the received data.
5
First use case: fetch some data
We want to supply the value of a known entity stored in our database. Let’s start by enabling the ORDS in our schema/account DECLARE PRAGMA AUTONOMOUS_TRANSACTION; BEGIN ORDS.ENABLE_SCHEMA(p_enabled => TRUE, p_schema => 'ADAMS3', p_url_mapping_type => 'BASE_PATH', p_url_mapping_pattern => 'adams3', p_auto_rest_auth => FALSE); commit; END; The pattern and the database schema are now linked, i.e. any URL starting by “ will be served by our account.
6
First use case: fetch some data
Then, let’s define a module. BEGIN ORDS.DEFINE_MODULE( p_module_name => 'adams_rest', p_base_path => ‘demo/’); COMMIT; END; We’re stating that any pattern with “api/” on it (i.e. starting by “ should be treated by the module “adams_rest”. This module is not a programming unit. It is an identifier for a set of end points. Let’s now define our first template + handler
7
First use case: fetch some data
BEGIN ORDS.define_template( p_module_name => 'adams_rest', p_pattern => 'hello_world'); ORDS.define_handler( p_pattern => 'hello_world', p_method => 'GET', p_source_type => ORDS.source_type_query, p_source => 'SELECT SYSDATE FROM DUAL', p_items_per_page => 0); COMMIT; END; The pattern “hello_world” will be handled by the SQL statement. That’s it! Let’s see how it looks… ~]$ curl {"items":[{"sysdate":" T14:49:18Z"}]}
8
Second use case: fetch a particular record’s data
The REST standard does not use arguments. We must identify what is the record we want to fetch in the URL itself (and not on a “?p_1=… syntax”) BEGIN ORDS.define_template( p_module_name => 'adams_rest', p_pattern => 'hello_world/:what'); ORDS.define_handler( p_pattern => 'hello_world/:what', p_method => 'GET', p_source_type => ORDS.source_type_query, p_source => 'SELECT PRS_LASTNAME, PRS_FIRSTNAME FROM T_PERSONS WHERE PRS_ID = :what', p_items_per_page => 0); COMMIT; END; ~]$ curl {"items":[{"prs_lastname":"MARTEL","prs_firstname":"PEDRO"}]}
9
Third use case: send some data to the database
PROCEDURE INSERT_PROC(p_data IN BLOB) IS l_clob CLOB; l_dest_offset PLS_INTEGER := 1; l_src_offset PLS_INTEGER := 1; l_lang_context PLS_INTEGER := DBMS_LOB.default_lang_ctx; l_warning PLS_INTEGER; l_rec_cnt PLS_INTEGER; l_id VARCHAR2(18); l_fn VARCHAR2(100); BEGIN --convert the BLOB to a CLOB. DBMS_LOB.createtemporary(lob_loc => l_clob ,cache => FALSE ,dur => DBMS_LOB.call ); DBMS_LOB.converttoclob(dest_lob => l_clob ,src_blob => p_data ,amount => DBMS_LOB.lobmaxsize ,dest_offset => l_dest_offset ,src_offset => l_src_offset ,blob_csid => DBMS_LOB.default_csid ,lang_context => l_lang_context ,warning => l_warning --parse the CLOB APEX_JSON.parse(l_clob); --count tuples l_rec_cnt := APEX_JSON.get_count(p_path => '.'); --loop through all the tuples FOR i IN 1 .. l_rec_cnt LOOP l_id := APEX_JSON.get_varchar2(p_path => '[%d].id', p0 => i); l_fn := APEX_JSON.get_varchar2(p_path => '[%d].fn', p0 => i); INSERT INTO TOTO VALUES (l_id, SYSDATE, l_fn); END LOOP; DBMS_LOB.freetemporary(lob_loc => l_clob); EXCEPTION WHEN OTHERS THEN NULL; END INSERT_PROC; Third use case: send some data to the database Data sent in a json attachment. PL/SQL procedure handles “:body” (reserved word) BEGIN ORDS.define_template( p_module_name => 'adams_rest', p_pattern => 'put_data'); ORDS.define_handler( p_pattern => 'put_data', p_method => 'POST', p_source_type => ORDS.source_type_plsql, p_source => 'BEGIN INSERT_PROC(p_data => :body); END;', p_items_per_page => 0); COMMIT; END; INSERT_PROC performs a couple of tricks to parse the JSON flow and extract the values.
10
Extra trick: controlling the HTTP status code
PROCEDURE INSERT_PROC(p_data IN BLOB ,p_status OUT INTEGER) IS l_clob CLOB; l_dest_offset PLS_INTEGER := 1; l_src_offset PLS_INTEGER := 1; l_lang_context PLS_INTEGER := DBMS_LOB.default_lang_ctx; l_warning PLS_INTEGER; l_rec_cnt PLS_INTEGER; l_id VARCHAR2(18); l_fn VARCHAR2(100); BEGIN --convert the BLOB to a CLOB. DBMS_LOB.createtemporary(lob_loc => l_clob ,cache => FALSE ,dur => DBMS_LOB.call ); DBMS_LOB.converttoclob(dest_lob => l_clob ,src_blob => p_data ,amount => DBMS_LOB.lobmaxsize ,dest_offset => l_dest_offset ,src_offset => l_src_offset ,blob_csid => DBMS_LOB.default_csid ,lang_context => l_lang_context ,warning => l_warning --parse the CLOB APEX_JSON.parse(l_clob); --count tuples l_rec_cnt := APEX_JSON.get_count(p_path => '.'); --loop through all the tuples FOR i IN 1 .. l_rec_cnt LOOP l_id := APEX_JSON.get_varchar2(p_path => '[%d].id', p0 => i); l_fn := APEX_JSON.get_varchar2(p_path => '[%d].fn', p0 => i); INSERT INTO TOTO VALUES (l_id, SYSDATE, l_fn); END LOOP; DBMS_LOB.freetemporary(lob_loc => l_clob); p_status := 201; --”Created” EXCEPTION WHEN OTHERS THEN NULL; END INSERT_PROC; Extra trick: controlling the HTTP status code It is possible to control the returned status, in our PL/SQL code. List of “correct” status can be found at Lets start by changing our pl/sql procedure, adding a new parameter. Then, lets change our handler. And finally, let’s define the parameter BEGIN ORDS.define_handler( p_module_name => 'adams_rest', p_pattern => 'put_data', p_method => 'POST', p_source_type => ORDS.source_type_plsql, p_source => 'BEGIN INSERT_PROC(p_data => :body, p_status => :status); END;', p_items_per_page => 0); COMMIT; END; BEGIN ORDS.DEFINE_PARAMETER( p_module_name => 'adams_rest', p_pattern => 'put_data', p_method => 'POST', p_name => 'X-APEX-STATUS-CODE', p_bind_variable_name => 'status', p_source_type => 'HEADER', p_access_method => 'OUT' ); COMMIT; END;
11
Authentication So far in this presentation, web services are consumed in an anonymous way. BASIC and OAuth2 authentication exists for ORDS and may co-exist in the same module. We can even have one end point with both BASIC and OAuth2 authentication at the same time. HTTP Basic authentication uses standard fields in the HTTP header, obviating the need for handshakes. OAuth provides to clients a "secure delegated access" to server resources.
12
Authentication Authentication works with “roles”. Let’s create one:
The syntax “ords-rest-access-{OURNAME}” is important. All accounts/Persons in an egroup (to be created) with the same name as the role, are in the role; that’s the trick for authorisation. BEGIN ORDS.create_role( p_role_name => 'ords-rest-access-adams-test' ); COMMIT; END;
13
Authentication Authentication works with “privileges”. Let’s create one: At this point, we have a role applied to a privilege. DECLARE l_arr OWA.vc_arr; BEGIN l_arr(1) := 'ords-rest-access-adams-test'; ORDS.define_privilege ( p_privilege_name => 'rest-adams-test', p_roles => l_arr, p_label => 'Test ADaMS WS', p_description => ‘Test ADaMS WS.' ); COMMIT; END;
14
Authentication - Basic
Finally, let’s map the privilege to our end point At this point, we only serve our end point if the request contains basic authentication for one account/person in the egroup. BEGIN ORDS.create_privilege_mapping( p_privilege_name => 'rest-adams-test', p_pattern => '/demo/hello_world' ); COMMIT; END;
15
Authentication – OAuth2
OAuth2 authentication is (obviously) a bit more laborious. Still, it is about granting a role to a client. As the role is applied to a privilege, and the privilege mapped to an end point, the rest follows. Let’s create an OAuth2 client Notice the p_name and p_privilege_names parameters. BEGIN OAUTH.create_client( p_name => 'adams3', p_grant_type => 'client_credentials', p_owner => 'pmartel', p_description => 'Pedro''s client for test OAUTH2 on ORDS. It will do something on a specific schema (adams3)', p_support_ => p_privilege_names => 'rest-adams-test' ); COMMIT; END;
16
Authentication – OAuth2
We have our client created for one privilege. Remember: a role is (still) mapped to our privilege. Let’s grant our client that role. That’s it! The authentication is set. So, how does it work? BEGIN OAUTH.grant_client_role( p_client_name => 'adams3', p_role_name => 'ords-rest-access-adams-test' ); COMMIT; END;
17
Authentication – OAuth2
We need to pass our client_id and client_secret to the web server in order to get a token back. Now that we have got a token, we may use it. Our token is also able to authenticate us Both authentication methods coexist. SQL> SELECT id, name, client_id, client_secret FROM user_ords_clients; ID NAME CLIENT_ID CLIENT_SECRET adams S8pyfTdBnWRKhStT72AuMA LmQhzlb3qsKGmp2jeVQnUQ.. ~]$ curl --basic --user S8pyfTdBnWRKhStT72AuMA..:LmQhzlb3qsKGmp2jeVQnUQ.. --data "grant_type=client_credentials" {"access_token":"p77gP7ZsXgpJlxHyEQA6Kw..","token_type":"bearer","expires_in":3600} ~]$ curl -H "Authorization: Bearer -PhkvmlZv8mDQNzGi6LsWg.."
18
Some useful queries --Modules SELECT id, name, uri_prefix FROM user_ords_modules ORDER BY name; -- Templates SELECT id, module_id, uri_template FROM user_ords_templates ORDER BY URI_TEMPLATE; -- Handlers. SELECT id, template_id, source_type, method, source FROM user_ords_handlers ORDER BY id; -- Parameters SELECT * FROM user_ords_parameters; --Roles SELECT * FROM user_ords_roles; -- Privileges. FROM user_ords_privileges; --Mappings SELECT privilege_id, name, pattern FROM user_ords_privilege_mappings;
19
References services/overview/index.html reference.htm#AELIG90180 ices
20
Thank you
Similar presentations
© 2025 SlidePlayer.com Inc.
All rights reserved.