
9 minute read
The wizard
OF ORDS
ORDS, Oracle Rest Data Services, is best known as the interface between a browser running an APEX application and the Oracle database. But nowadays it can do much more than just transform a request that comes from the APEX application into a database procedure and transfer the result of that call back to the browser. That’s probably the main reason why Oracle rebranded it from APEX Listener to ORDS.
Advertisement
Currently all programming languages understand the concept of web services and modern application architectures rely heavily on that concept. And while at first glance the Oracle database might look as a huge monolithic object that doesn’t fit it in such an environment, the opposite is true. Using web services is just a way to move data around and the database is the ideal place to store that data. So they are a perfect match. And in this article we’ll see how easy it is to create web services for your database objects and making your database the center of your application architecture.
ENABLE YOUR SCHEMA Using web services means granting access to your database. So before you even start you have to think about security. Because a web service will use a database user to connect, that database user should have very limited privileges. You don’t want to be the person that granted an evil hacker system access! Therefore you should create a separate user that doesn’t hold the real tables and data that you want to expose to the outside world, but just offers a view on that data. So logged in as that low privileged database user, the first thing you have to do is enable your schema for ORDS, while passing in a mapping pattern. The mapping pattern will become a part of the URL of the web service. As it is a good practice to reveal as little as possible, the mapping pattern should not include your schema name.
begin ords.enable_schema ( p_url_mapping_pattern => 'api' -- Obfuscate your real schema name ); commit; end; /
Now you can query one of the user_ords_schema view to inspect the results of this action.
ENABLE YOUR FIRST OBJECT Assuming you have already created the view that you would like to expose in the web service, one more PL/SQL call will do. Just as when enabling the schema, you should not reveal the real table or view name, but obfuscate it by specifying another “alias” than the real object name.
begin ords.enable_object ( p_object => 'CUSTOMERS_VW' , p_object_type => 'VIEW' , p_object_alias => 'customers' ); commit; end; /
Now you’re ready to call your first web service by pointing your browser to this URL : https://<your-machine>/ords/api/customers. You should retrieve a JSON document showing all the data from the view. But this is not the only service we just created. If you query the user_ords_services view, you’ll see we just created seven services! Apart from the “GET” we created a “GET” for just one record - using a /<id> extension at the end of the URL. And some other services to insert, update and delete either one or more records from the view. And that just needed two lines of PL/SQL!
ENABLING PL/SQL OBJECTS Identical to enabling views (and tables) you can enable PL/SQL objects as well. Thus you can create procedures, functions and packages that can be part of your web services architecture. First thing you have to be aware of is that a PL/SQL object is always exposed using a POST method. That means you can’t call it directly from the browser’s URL but you either need to code (in PL/ SQL, JavaScript, Java or whatever your favourite language is) or use a tool like Postman to inspect the results. Let’s create a simple procedure with two in-parameters and two out-parameters:
create or replace procedure add_something ( p_number1 number , p_number2 number , p_result out number , the_answer_is out number ) is begin p_result := p_number1 + p_number2; the_answer_is := 42; end; /
And enable that procedure as a web service:
begin ords.enable_object ( p_object => 'ADD_SOMETHING' , p_object_type => 'PROCEDURE' , p_object_alias => 'add' ); commit; end; /
If we would now create some JavaScript / jQuery code to call that URL, passing in the inparameters:
var settings = { "url": “https://<your-machine>/ords/api/add/“, "method": "POST", "timeout": 0, "headers": {
"Content-Type": "application/json" }, "data": JSON.stringify({"p_number1":4,"p_number2":5}), };
$.ajax(settings).done(function (response) { console.log(response); });
We would see this result: {
"p_result": 9, "the_answer_is": 42 }
Something very similar applies to functions, but functions can only have one result and that’s named “~ret”. So in this case the outcome would be : {“~ret”:9}.
While this is a very simple example, it gets more interesting when you enable a procedure that returns a sys_refcursor or even a nested sys_refcursor like below. If you call this as a web service then a nested JSON object is returned, exactly the way the modern JavaScript developer likes it!
create or replace procedure all_sales ( sales out sys_refcursor ) is begin open sales for select cust.customer_id , cust.cust_first_name , cust.cust_last_name , cursor( select ord.order_id , ord.order_total , cursor ( select itm.order_item_id , itm.unit_price , itm.quantity , prod.product_name from demo_order_items itm join demo_product_info prod on itm.product_id = prod.product_id ) orderlines from demo_orders ord where customer_id = cust.customer_id ) orders from my_customers_vw cust; end; /
If this is not enough and you need full control or need to pass in or out header variables, then you can also defined a PL/SQL block as part of a service. The downside of that approach is that the PL/SQL block is just a stored text block. Thus while a change in your model, like dropping a column, could invalidate a PL/SQL procedure - and you are notified about that and can fix it - the PL/SQL text block will fail on run time.
REST ENABLED SQL If you want to make it even more exciting, you can also open up your database to running any SQL via a URL call. There are a few prerequisites to make that possible. First you have to add one line in your ORDS defaults.xml file :
<entry key=“restEnabledSql.active">true</entry>
This is already enabled in Oracle’s Always Free Autonomous Database environment. One caveat: You will enable SQL for all REST enabled schema’s! Secondly you have to use HTTPS, because you need to send over usernames and passwords. So these better be encrypted. Third, the content-type should be “application/sql”. Now you can execute a SQL statement like “select sysdate from dual” from JavaScript over REST:
var settings = { "url": "https://<your-machine>/ords/api/_/sql", "method": "POST", "timeout": 0, "headers": { "Content-Type": "application/sql", "Authorization": "Basic <encrypted username/password>” }, "data": "select sysdate from dual;", };
$.ajax(settings).done(function (response) { console.log(response); });
You’re not limited to executing just one SQL statement. You can also pass in a SQL file or a JSON file containing multiple statements.
PROTECT YOUR SERVICE Apart from the SQL-over-REST the calls to our views and procedures were open to the general public. So if you do this on something else than your laptop, other people might get access to your data. So how can we protect that? The answer is simple. By just passing in an extra parameter - p_auto_rest_auth - when we enable our object!
begin ords.enable_object ( p_object => 'THIS_IS_SECRET' , p_object_type => 'PROCEDURE' , p_object_alias => 'secret' , p_auto_rest_auth => true ); commit; end; /
If we now try to access that service, we’ll receive a “401 Unauthorized” response. There are more ways to enable access to trusted users, but the current de facto standard is t use OAuth2. To enable that we need to execute a few steps. First we need to create a client:
begin oauth.create_client ( p_name => 'secret client' , p_grant_type => 'client_credentials' , p_owner => 'Wizardry Ltd.' , p_description => 'A client for the Wizard' , p_support_email => 'the.wizard@gmail.com' , p_privilege_names => 'oracle.dbtools.autorest.privilege.<schema-name>.<object-name>' ); commit; end; /
The “privilege_name” is generated when you enabled the object - either with or with our “auto_ rest_auth” switched on. You can see these when you query the user_ords_client_privileges view. And just like that there are client roles created as you can see in the user_ords_client_roles view. Now we need to grant that role to the client we just created.
begin oauth.grant_client_role ( p_client_name => 'secret client' , p_role_name => 'oracle.dbtools.role.autorest.<schema-name>.<object-name>' ); commit; end; /
Once we’ve done that we can retrieve the client-id and client-secret from the user_ords_clients view:
select name, client_id, client_secret from user_ords_clients /
Using id and secret we can obtain an OAuth access token (this time using cUrl as an example):
curl -i -k --user <client-id>:<client-secret> \ --data "grant_type=client_credentials" \ https://<your-machine>/ords/api/oauth/token
The result is an access token that is valid for one hour:
{"access_token":"sWyms9Tx_4L8UnKB4XON3w","token_type":"bearer","expires_in":3600}
Finally we can use that OAuth access token to access our protected service :
curl --location --request POST 'https://<your-machine>/ords/api/secret/' \ --header 'Authorization: Bearer sWyms9Tx_4L8UnKB4XON3w'
CONCLUSION The Oracle database can and should play an important role in an web service architecture. And ORDS facilitates that. By using relatively simple and familiar PL/SQL code and constructs you can enable this while keeping your database secure! n
Oracle ACE Director Roel Hartman is Director & Senior APEX Developer bij APEX Consulting.
OOK ONTVANGEN? ViSIE
Wilt u ook op de hoogte blijven van actuele ontwikkelingen en nieuws en achtergronden over Oracle en Oracle-producten, de Oracle-community en de activiteiten van de Nederlandse Oracle User Group?
Abonneer u dan op het gratis e-magazine
ViSIE
Inschrijving via de website www.nloug.nl
advertentie

APEX OFFICE PRINT


Dimitri Gielis - CEO

APEX Offi ce Print (AOP) is the most integrated, easiest to use, and fl exible printing and reporting solution for Oracle Application Express (APEX). Export your reports exactly as they are shown on the screen! We make it easy by providing a REST API, PL/SQL API, and an APEX plug-in. You can be up-andrunning in minutes!
FREE Cloud Account
apexoffi ceprint.com
FREE Development Reports
UNLIMITED
Licences Cloud and On-premises

APEX MEDIA EXTENSION Transform multimedia in the Oracle Database and Oracle APEX
AME makes it easy to process or convert media before or after it is stored in the Oracle Database. Using our APEX plug-in, PL/SQL API, and REST API you can: • resize images, • rotate and fl ip images, • crop images, • get image information (width, height, mime type, ...), • read media metadata (Exif, IPTC and XMP), • and much more…


Try it out for FREE at apexmediaextension.com
Look for more great products from the same great team, coming soon in 2020!
