SlideShare a Scribd company logo
1 of 62
Why You Should Use TAPIs
Jeffrey Kemp
AUSOUG Connect Perth, November 2016
All artifacts including code are presented for illustration
purposes only. Use at your own risk. Test thoroughly in
a non-critical environment before use.
Main Menu
1. Why a data API?
2. Why choose PL/SQL?
3. How to structure your API?
4. Data API for Apex
5. Table APIs (TAPIs)
6. Open Source TAPI project
Background
“Building Maintainable Apex Apps”, 2014
https://jeffkemponoracle.com/2014/11/14/sample-tapi-apex-application/
https://jeffkemponoracle.com/2016/02/11/tapi-generator-mkii/
https://jeffkemponoracle.com/2016/02/12/apex-api-call-a-package-for-all-your-dml/
https://jeffkemponoracle.com/2016/02/16/apex-api-for-tabular-forms/
https://jeffkemponoracle.com/2016/06/30/interactive-grid-apex-5-1-ea/
Why a data API?
Why a data API?
“I’m building a simple Apex app.
I’ll just use the built-in processes
to handle all the DML.”
Your requirements get more
complex.
– More single-row and/or tabular
forms
– More pages, more load routines,
more validations, more
insert/update processes
– Complex conditions
– Edge cases, special cases, weird
cases
Another system must create the same data –
outside of Apex
– Re-use validations and processing
– Rewrite the validations
– Re-engineer all processing (insert/update) logic
– Same edge cases
– Different edge cases
Define all validations and processes in one place
– Integrated error messages
– Works with Apex single-row and tabular forms
Simple wrapper to allow code re-use
– Same validations and processes included
– Reduced risk of regression
– Reduced risk of missing bits
• They get exactly the same logical outcome as we get
• No hidden surprises from Apex features
TAPIs
Business Rule Validations
Default Values
Reusability
Encapsulation
Maintainability
Maintainability is in the eye of the
beholder maintainer.
Techniques
• DRY
• Consistency
• Naming
• Single-purpose
• Assertions
Why use PL/SQL for your API?
Why use PL/SQL for your API?
• Data is forever
• UIs come and go
• Business logic
– tighter coupling with Data than UI
Business Logic
• your schema
• your data constraints
• your validation rules
• your insert/update/delete logic
• keep business logic close to your data
• on Oracle, PL/SQL is the best
Performance
#ThickDB
#ThickDB
How should you structure your API?
How should you structure your API?
Use packages
Focus each Package
For example:
– “Employees” API
– “Departments” API
– “Workflow” API
– Security (user roles and privileges) API
– Apex Utilities
Package names as context
GENERIC_PKG.get_event (event_id => nv('P1_EVENT_ID'));
GENERIC_PKG.get_member (member_id => nv('P1_MEMBER_ID'));
EVENT_PKG.get (event_id => nv('P1_EVENT_ID'));
MEMBER_PKG.get (member_id => nv('P1_MEMBER_ID'));
Apex processes, simplified
MVC Architecture
entity$APEX
table$TAPI
Process: load
load
1. Get PK value
2. Call TAPI to query record
3. Set session state for each column
Validation
validate
1. Get values from session state into record
2. Pass record to TAPI
3. Call APEX_ERROR for each validation error
process page request
process
1. Get v('REQUEST')
2. Get values from session state into record
3. Pass record to TAPI
Process a page requestprocedure process is
rv EVENTS$TAPI.rvtype;
r EVENTS$TAPI.rowtype;
begin
UTIL.check_authorization(SECURITY.Operator);
case
when APEX_APPLICATION.g_request = 'CREATE'
then
rv := apex_get;
r := EVENTS$TAPI.ins (rv => rv);
apex_set (r => r);
UTIL.success('Event created.');
when APEX_APPLICATION.g_request like 'SAVE%'
then
rv := apex_get;
r := EVENTS$TAPI.upd (rv => rv);
apex_set (r => r);
UTIL.success('Event updated.');
when APEX_APPLICATION.g_request = 'DELETE'
then
rv := apex_get_pk;
EVENTS$TAPI.del (rv => rv);
UTIL.clear_page_cache;
UTIL.success('Event deleted.');
else
null;
end case;
end process;
get_rowfunction apex_get return VOLUNTEERS$TAPI.rvtype is
rv VOLUNTEERS$TAPI.rvtype;
begin
rv.vol_id := nv('P9_VOL_ID');
rv.given_name := v('P9_GIVEN_NAME');
rv.surname := v('P9_SURNAME');
rv.date_of_birth := v('P9_DATE_OF_BIRTH');
rv.address_line := v('P9_ADDRESS_LINE');
rv.suburb := v('P9_SUBURB');
rv.postcode := v('P9_POSTCODE');
rv.state := v('P9_STATE');
rv.home_phone := v('P9_HOME_PHONE');
rv.mobile_phone := v('P9_MOBILE_PHONE');
rv.email_address := v('P9_EMAIL_ADDRESS');
rv.version_id := nv('P9_VERSION_ID');
return rv;
end apex_get;
set row
procedure apex_set (r in VOLUNTEERS$TAPI.rowtype) is
begin
sv('P9_VOL_ID', r.vol_id);
sv('P9_GIVEN_NAME', r.given_name);
sv('P9_SURNAME', r.surname);
sd('P9_DATE_OF_BIRTH', r.date_of_birth);
sv('P9_ADDRESS_LINE', r.address_line);
sv('P9_STATE', r.state);
sv('P9_SUBURB', r.suburb);
sv('P9_POSTCODE', r.postcode);
sv('P9_HOME_PHONE', r.home_phone);
sv('P9_MOBILE_PHONE', r.mobile_phone);
sv('P9_EMAIL_ADDRESS', r.email_address);
sv('P9_VERSION_ID', r.version_id);
end apex_set;
PL/SQL in Apex
PKG.proc;
SQL in Apex
select t.col_a
,t.col_b
,t.col_c
from my_table t;
• Move joins, select expressions, etc. to a
view
– except Apex-specific stuff like generated APEX_ITEMs
Pros
• Fast development
• Smaller apex app
• Dependency analysis
• Refactoring
• Modularity
• Code re-use
• Customisation
• Version control
Cons
• Misspelled/missing item names
– Mitigation: isolate all apex code in one set of
packages
– Enforce naming conventions – e.g. P1_COLUMN_NAME
• Apex Advisor doesn’t check database package
code
Apex API Coding Standards
• All v() calls at start of proc, once per item
• All sv() calls at end of proc
• Constants instead of 'P1_COL'
• Dynamic Actions calling PL/SQL – use parameters
• Replace PL/SQL with Javascript (where possible)
Error Handling
• Validate - only record-level validation
• Cross-record validation – db constraints + XAPI
• Capture DUP_KEY_ON_VALUE and ORA-02292 for unique and
referential constraints
• APEX_ERROR.add_error
TAPIs
• Encapsulate all DML for a table
• Row-level validation
• Detect lost updates
• Generated
TAPI contents
• Record types
– rowtype, arraytype, validation record type
• Functions/Procedures
– ins / upd / del / merge / get
– bulk_ins / bulk_upd / bulk_merge
• Constants for enumerations
Why not a simple rowtype?
procedure ins
(emp_name in varchar2
,dob in date
,salary in number
) is
begin
if is_invalid_date (dob) then
raise_error('Date of birth bad');
elsif is_invalid_number (salary) then
raise_error('Salary bad');
end if;
insert into emp (emp_name, dob, salary) values (emp_name, dob, salary);
end ins;
ins (emp_name => :P1_EMP_NAME, dob => :P1_DOB, salary => :P1_SALARY);
ORA-01858: a non-numeric character was found where a numeric was expected
It’s too late to validate
data types here!
Validation record type
type rv is record
( emp_name varchar2(4000)
, dob varchar2(4000)
, salary varchar2(4000));
procedure ins (rv in rvtype) is
begin
if is_invalid_date (dob) then
raise_error('Date of birth bad');
elsif is_invalid_number (salary) then
raise_error('Salary bad');
end if;
insert into emp (emp_name, dob, salary) values (emp_name, dob, salary);
end ins;
ins (emp_name => :P1_EMP_NAME, dob => :P1_DOB, salary => :P1_SALARY);
I’m sorry Dave, I can’t do that - Date of birth bad
Example Table
create table venues
( venue_id integer default on null venue_id_seq.nextval
, name varchar2(200 char)
, map_position varchar2(200 char)
, created_dt date default on null sysdate
, created_by varchar2(100 char)
default on null sys_context('APEX$SESSION','APP_USER')
, last_updated_dt date default on null sysdate
, last_updated_by varchar2(100 char)
default on null sys_context('APEX$SESSION','APP_USER')
, version_id integer default on null 1
);
TAPI example
package VENUES$TAPI as
cursor cur is select x.* from venues;
subtype rowtype is cur%rowtype;
type arraytype is table of rowtype
index by binary_integer;
type rvtype is record
(venue_id venues.venue_id%type
,name varchar2(4000)
,map_position varchar2(4000)
,version_id venues.version_id%type
);
type rvarraytype is table of rvtype
index by binary_integer;
-- validate the row
function val (rv IN rvtype) return varchar2;
-- insert a row
function ins (rv IN rvtype) return rowtype;
-- update a row
function upd (rv IN rvtype) return rowtype;
-- delete a row
procedure del (rv IN rvtype);
end VENUES$TAPI;
TAPI ins
function ins (rv in rvtype)
return rowtype is
r rowtype;
error_msg varchar2(32767);
begin
error_msg := val (rv => rv);
if error_msg is not null then
UTIL.raise_error(error_msg);
end if;
insert into venues
(name
,map_position)
values(rv.name
,rv.map_position)
returning
venue_id
,...
into r;
return r;
exception
when dup_val_on_index then
UTIL.raise_dup_val_on_index;
end ins;
TAPI val
function val (rv in rvtype) return varchar2 is
begin
UTIL.val_not_null (val => rv.host_id, column_name => HOST_ID);
UTIL.val_not_null (val => rv.event_type, column_name => EVENT_TYPE);
UTIL.val_not_null (val => rv.title, column_name => TITLE);
UTIL.val_not_null (val => rv.start_dt, column_name => START_DT);
UTIL.val_max_len (val => rv.event_type, len => 100, column_name => EVENT_TYPE);
UTIL.val_max_len (val => rv.title, len => 100, column_name => TITLE);
UTIL.val_max_len (val => rv.description, len => 4000, column_name => DESCRIPTION);
UTIL.val_datetime (val => rv.start_dt, column_name => START_DT);
UTIL.val_datetime (val => rv.end_dt, column_name => END_DT);
UTIL.val_domain
(val => rv.repeat
,valid_values => t_str_array(DAILY, WEEKLY, MONTHLY, ANNUALLY)
,column_name => REPEAT);
UTIL.val_integer (val => rv.repeat_interval, range_low => 1, column_name => REPEAT_INTERVAL);
UTIL.val_date (val => rv.repeat_until, column_name => REPEAT_UNTIL);
UTIL.val_ind (val => rv.repeat_ind, column_name => REPEAT_IND);
return UTIL.first_error;
end val;
TAPI upd
function upd (rv in rvtype) return rowtype is
r rowtype;
error_msg varchar2(32767);
begin
error_msg := val (rv => rv);
if error_msg is not null then
UTIL.raise_error(error_msg);
end if;
update venues x
set x.name = rv.name
,x.map_position = rv.map_position
where x.venue_id = rv.venue_id
and x.version_id = rv.version_id
returning
venue_id
,...
into r;
if sql%notfound then
raise UTIL.lost_update;
end if;
return r;
exception
when dup_val_on_index then
UTIL.raise_dup_val_on_index;
when UTIL.ref_constraint_violation then
UTIL.raise_ref_con_violation;
when UTIL.lost_update then
lost_upd (rv => rv);
end upd;
Lost update handler
procedure lost_upd (rv in rvtype) is
db_last_updated_by venues.last_updated_by%type;
db_last_updated_dt venues.last_updated_dt%type;
begin
select x.last_updated_by
,x.last_updated_dt
into db_last_updated_by
,db_last_updated_dt
from venues x
where x.venue_id = rv.venue_id;
UTIL.raise_lost_update
(updated_by => db_last_updated_by
,updated_dt => db_last_updated_dt);
exception
when no_data_found then
UTIL.raise_error('LOST_UPDATE_DEL');
end lost_upd;
“This record was changed by
JOE BLOGGS at 4:31pm.
Please refresh the page to see
changes.”
“This record was deleted by
another user.”
TAPI bulk_ins
function bulk_ins (arr in rvarraytype) return number is
begin
bulk_val(arr);
forall i in indices of arr
insert into venues
(name
,map_position)
values (arr(i).name
,arr(i).map_position);
return sql%rowcount;
exception
when dup_val_on_index then
UTIL.raise_dup_val_on_index;
end bulk_ins;
What about queries?
Tuning a complex, general-purpose query
is more difficult than
tuning a complex, single-purpose query.
Generating Code
• Only PL/SQL
• Templates compiled in the schema
• Simple syntax
• Sub-templates (“includes”) for extensibility
OraOpenSource TAPI
• Runs on NodeJS
• Uses Handlebars for template processing
• https://github.com/OraOpenSource/oos-tapi/
• Early stages, needs contributors
OOS-TAPI Example
create or replace package body {{toLowerCase table_name}} as
gc_scope_prefix constant varchar2(31) := lower($$plsql_unit) || '.';
procedure ins_rec(
{{#each columns}}
p_{{toLowerCase column_name}} in {{toLowerCase data_type}}
{{#unless @last}},{{lineBreak}}{{/unless}}
{{~/each}}
);
end {{toLowerCase table_name}};
oddgen
• SQL*Developer plugin
• Code generator, including TAPIs
• Support now added in jk64 Apex TAPI generator
https://www.oddgen.org
Takeaways
Be Consistent
Consider Your Successors
Thank you
jeffkemponoracle.com

More Related Content

What's hot

Fundamental of ELK Stack
Fundamental of ELK StackFundamental of ELK Stack
Fundamental of ELK Stack주표 홍
 
MySQL Performance Tuning: Top 10 Tips
MySQL Performance Tuning: Top 10 TipsMySQL Performance Tuning: Top 10 Tips
MySQL Performance Tuning: Top 10 TipsOSSCube
 
[2015-06-05] Oracle TX Lock
[2015-06-05] Oracle TX Lock[2015-06-05] Oracle TX Lock
[2015-06-05] Oracle TX LockSeok-joon Yun
 
엘라스틱서치 실무 가이드_202204.pdf
엘라스틱서치 실무 가이드_202204.pdf엘라스틱서치 실무 가이드_202204.pdf
엘라스틱서치 실무 가이드_202204.pdf한 경만
 
《保哥線上講堂》打造一個具有 Linux 溫度的 Windows 命令提示字元工具
《保哥線上講堂》打造一個具有 Linux 溫度的 Windows 命令提示字元工具《保哥線上講堂》打造一個具有 Linux 溫度的 Windows 命令提示字元工具
《保哥線上講堂》打造一個具有 Linux 溫度的 Windows 命令提示字元工具Will Huang
 
CLUB DB2 第122回 DB2管理本の著者が教える 簡単運用管理入門
CLUB DB2 第122回  DB2管理本の著者が教える 簡単運用管理入門CLUB DB2 第122回  DB2管理本の著者が教える 簡単運用管理入門
CLUB DB2 第122回 DB2管理本の著者が教える 簡単運用管理入門Akira Shimosako
 
Oracle - SQL-PL/SQL context switching
Oracle - SQL-PL/SQL context switchingOracle - SQL-PL/SQL context switching
Oracle - SQL-PL/SQL context switchingSmitha Padmanabhan
 
LLVM Backend Porting
LLVM Backend PortingLLVM Backend Porting
LLVM Backend PortingShiva Chen
 
Indexing and Query Optimization
Indexing and Query OptimizationIndexing and Query Optimization
Indexing and Query OptimizationMongoDB
 
Security Learning Vol2 話題の脆弱性をコードで紐解く!
Security Learning Vol2 話題の脆弱性をコードで紐解く!Security Learning Vol2 話題の脆弱性をコードで紐解く!
Security Learning Vol2 話題の脆弱性をコードで紐解く!YOJI WATANABE
 
How to use histograms to get better performance
How to use histograms to get better performanceHow to use histograms to get better performance
How to use histograms to get better performanceMariaDB plc
 
Apache Bookkeeper and Apache Zookeeper for Apache Pulsar
Apache Bookkeeper and Apache Zookeeper for Apache PulsarApache Bookkeeper and Apache Zookeeper for Apache Pulsar
Apache Bookkeeper and Apache Zookeeper for Apache PulsarEnrico Olivelli
 
[29DCF] PostgreSQL에서 DB Lock을 줄이는 5가지 팁
[29DCF] PostgreSQL에서 DB Lock을 줄이는 5가지 팁[29DCF] PostgreSQL에서 DB Lock을 줄이는 5가지 팁
[29DCF] PostgreSQL에서 DB Lock을 줄이는 5가지 팁jiminlee81
 
[스마트스터디]MongoDB 의 역습
[스마트스터디]MongoDB 의 역습[스마트스터디]MongoDB 의 역습
[스마트스터디]MongoDB 의 역습smartstudy_official
 
[Pgday.Seoul 2021] 2. Porting Oracle UDF and Optimization
[Pgday.Seoul 2021] 2. Porting Oracle UDF and Optimization[Pgday.Seoul 2021] 2. Porting Oracle UDF and Optimization
[Pgday.Seoul 2021] 2. Porting Oracle UDF and OptimizationPgDay.Seoul
 
CA_7_final_ppt.ppt
CA_7_final_ppt.pptCA_7_final_ppt.ppt
CA_7_final_ppt.pptssuser600df4
 
Commit Wait Class 대기시간 감소 방안_Wh oracle
Commit Wait Class 대기시간 감소 방안_Wh oracleCommit Wait Class 대기시간 감소 방안_Wh oracle
Commit Wait Class 대기시간 감소 방안_Wh oracle엑셈
 
RedisConf18 - Redis Memory Optimization
RedisConf18 - Redis Memory OptimizationRedisConf18 - Redis Memory Optimization
RedisConf18 - Redis Memory OptimizationRedis Labs
 

What's hot (20)

Fundamental of ELK Stack
Fundamental of ELK StackFundamental of ELK Stack
Fundamental of ELK Stack
 
MySQL Performance Tuning: Top 10 Tips
MySQL Performance Tuning: Top 10 TipsMySQL Performance Tuning: Top 10 Tips
MySQL Performance Tuning: Top 10 Tips
 
[2015-06-05] Oracle TX Lock
[2015-06-05] Oracle TX Lock[2015-06-05] Oracle TX Lock
[2015-06-05] Oracle TX Lock
 
엘라스틱서치 실무 가이드_202204.pdf
엘라스틱서치 실무 가이드_202204.pdf엘라스틱서치 실무 가이드_202204.pdf
엘라스틱서치 실무 가이드_202204.pdf
 
《保哥線上講堂》打造一個具有 Linux 溫度的 Windows 命令提示字元工具
《保哥線上講堂》打造一個具有 Linux 溫度的 Windows 命令提示字元工具《保哥線上講堂》打造一個具有 Linux 溫度的 Windows 命令提示字元工具
《保哥線上講堂》打造一個具有 Linux 溫度的 Windows 命令提示字元工具
 
CLUB DB2 第122回 DB2管理本の著者が教える 簡単運用管理入門
CLUB DB2 第122回  DB2管理本の著者が教える 簡単運用管理入門CLUB DB2 第122回  DB2管理本の著者が教える 簡単運用管理入門
CLUB DB2 第122回 DB2管理本の著者が教える 簡単運用管理入門
 
Oracle - SQL-PL/SQL context switching
Oracle - SQL-PL/SQL context switchingOracle - SQL-PL/SQL context switching
Oracle - SQL-PL/SQL context switching
 
LLVM Backend Porting
LLVM Backend PortingLLVM Backend Porting
LLVM Backend Porting
 
Indexing and Query Optimization
Indexing and Query OptimizationIndexing and Query Optimization
Indexing and Query Optimization
 
Security Learning Vol2 話題の脆弱性をコードで紐解く!
Security Learning Vol2 話題の脆弱性をコードで紐解く!Security Learning Vol2 話題の脆弱性をコードで紐解く!
Security Learning Vol2 話題の脆弱性をコードで紐解く!
 
How to use histograms to get better performance
How to use histograms to get better performanceHow to use histograms to get better performance
How to use histograms to get better performance
 
Apache Bookkeeper and Apache Zookeeper for Apache Pulsar
Apache Bookkeeper and Apache Zookeeper for Apache PulsarApache Bookkeeper and Apache Zookeeper for Apache Pulsar
Apache Bookkeeper and Apache Zookeeper for Apache Pulsar
 
[29DCF] PostgreSQL에서 DB Lock을 줄이는 5가지 팁
[29DCF] PostgreSQL에서 DB Lock을 줄이는 5가지 팁[29DCF] PostgreSQL에서 DB Lock을 줄이는 5가지 팁
[29DCF] PostgreSQL에서 DB Lock을 줄이는 5가지 팁
 
Gcc porting
Gcc portingGcc porting
Gcc porting
 
[스마트스터디]MongoDB 의 역습
[스마트스터디]MongoDB 의 역습[스마트스터디]MongoDB 의 역습
[스마트스터디]MongoDB 의 역습
 
[Pgday.Seoul 2021] 2. Porting Oracle UDF and Optimization
[Pgday.Seoul 2021] 2. Porting Oracle UDF and Optimization[Pgday.Seoul 2021] 2. Porting Oracle UDF and Optimization
[Pgday.Seoul 2021] 2. Porting Oracle UDF and Optimization
 
CA_7_final_ppt.ppt
CA_7_final_ppt.pptCA_7_final_ppt.ppt
CA_7_final_ppt.ppt
 
Spring framework aop
Spring framework aopSpring framework aop
Spring framework aop
 
Commit Wait Class 대기시간 감소 방안_Wh oracle
Commit Wait Class 대기시간 감소 방안_Wh oracleCommit Wait Class 대기시간 감소 방안_Wh oracle
Commit Wait Class 대기시간 감소 방안_Wh oracle
 
RedisConf18 - Redis Memory Optimization
RedisConf18 - Redis Memory OptimizationRedisConf18 - Redis Memory Optimization
RedisConf18 - Redis Memory Optimization
 

Viewers also liked

Why You Should Use Oracle SQL Developer
Why You Should Use Oracle SQL DeveloperWhy You Should Use Oracle SQL Developer
Why You Should Use Oracle SQL DeveloperJeffrey Kemp
 
Apex and Virtual Private Database
Apex and Virtual Private DatabaseApex and Virtual Private Database
Apex and Virtual Private DatabaseJeffrey Kemp
 
Automate Amazon S3 Storage with Alexandria
Automate Amazon S3 Storage with AlexandriaAutomate Amazon S3 Storage with Alexandria
Automate Amazon S3 Storage with AlexandriaJeffrey Kemp
 
11g Function Result Cache
11g Function Result Cache11g Function Result Cache
11g Function Result CacheJeffrey Kemp
 
Aws konferenz vortrag gk
Aws konferenz vortrag gkAws konferenz vortrag gk
Aws konferenz vortrag gkexecupery
 
Učinkovitejše iskanje v Google
Učinkovitejše iskanje v GoogleUčinkovitejše iskanje v Google
Učinkovitejše iskanje v GoogleTomaž Bešter
 
Migrate BI to APEX 5: Are We There Yet?
Migrate BI to APEX 5: Are We There Yet?Migrate BI to APEX 5: Are We There Yet?
Migrate BI to APEX 5: Are We There Yet?Karen Cannell
 
Open Canary - novahackers
Open Canary - novahackersOpen Canary - novahackers
Open Canary - novahackersChris Gates
 
Presantecion 1
Presantecion 1Presantecion 1
Presantecion 1huvabayona
 

Viewers also liked (12)

Why You Should Use Oracle SQL Developer
Why You Should Use Oracle SQL DeveloperWhy You Should Use Oracle SQL Developer
Why You Should Use Oracle SQL Developer
 
Apex and Virtual Private Database
Apex and Virtual Private DatabaseApex and Virtual Private Database
Apex and Virtual Private Database
 
Automate Amazon S3 Storage with Alexandria
Automate Amazon S3 Storage with AlexandriaAutomate Amazon S3 Storage with Alexandria
Automate Amazon S3 Storage with Alexandria
 
11g Function Result Cache
11g Function Result Cache11g Function Result Cache
11g Function Result Cache
 
Aws konferenz vortrag gk
Aws konferenz vortrag gkAws konferenz vortrag gk
Aws konferenz vortrag gk
 
Učinkovitejše iskanje v Google
Učinkovitejše iskanje v GoogleUčinkovitejše iskanje v Google
Učinkovitejše iskanje v Google
 
Migrate BI to APEX 5: Are We There Yet?
Migrate BI to APEX 5: Are We There Yet?Migrate BI to APEX 5: Are We There Yet?
Migrate BI to APEX 5: Are We There Yet?
 
Open Canary - novahackers
Open Canary - novahackersOpen Canary - novahackers
Open Canary - novahackers
 
Single page App
Single page AppSingle page App
Single page App
 
Presantecion 1
Presantecion 1Presantecion 1
Presantecion 1
 
Nature Walk
Nature Walk Nature Walk
Nature Walk
 
Taking Human Error out of K12 Attendance Equation
Taking Human Error out of K12 Attendance EquationTaking Human Error out of K12 Attendance Equation
Taking Human Error out of K12 Attendance Equation
 

Similar to Why You Should Use TAPIs

Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQueryRemedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQueryTatsuhiko Miyagawa
 
Mock Servers - Fake All the Things!
Mock Servers - Fake All the Things!Mock Servers - Fake All the Things!
Mock Servers - Fake All the Things!Atlassian
 
PHP applications/environments monitoring: APM & Pinba
PHP applications/environments monitoring: APM & PinbaPHP applications/environments monitoring: APM & Pinba
PHP applications/environments monitoring: APM & PinbaPatrick Allaert
 
Creating REST Applications with the Slim Micro-Framework by Vikram Vaswani
Creating REST Applications with the Slim Micro-Framework by Vikram VaswaniCreating REST Applications with the Slim Micro-Framework by Vikram Vaswani
Creating REST Applications with the Slim Micro-Framework by Vikram Vaswanivvaswani
 
Passenger 6 generic language support presentation
Passenger 6 generic language support presentationPassenger 6 generic language support presentation
Passenger 6 generic language support presentationHongli Lai
 
api-platform: the ultimate API platform
api-platform: the ultimate API platformapi-platform: the ultimate API platform
api-platform: the ultimate API platformStefan Adolf
 
Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5Elena Kolevska
 
High-level Programming Languages: Apache Pig and Pig Latin
High-level Programming Languages: Apache Pig and Pig LatinHigh-level Programming Languages: Apache Pig and Pig Latin
High-level Programming Languages: Apache Pig and Pig LatinPietro Michiardi
 
Ice mini guide
Ice mini guideIce mini guide
Ice mini guideAdy Liu
 
Integration of APEX and Oracle Forms
Integration of APEX and Oracle FormsIntegration of APEX and Oracle Forms
Integration of APEX and Oracle FormsRoel Hartman
 
PBDL.pdf
PBDL.pdfPBDL.pdf
PBDL.pdfsouzatg
 
Design Summit - Rails 4 Migration - Aaron Patterson
Design Summit - Rails 4 Migration - Aaron PattersonDesign Summit - Rails 4 Migration - Aaron Patterson
Design Summit - Rails 4 Migration - Aaron PattersonManageIQ
 
How and why i roll my own node.js framework
How and why i roll my own node.js frameworkHow and why i roll my own node.js framework
How and why i roll my own node.js frameworkBen Lin
 
From CakePHP to Laravel
From CakePHP to LaravelFrom CakePHP to Laravel
From CakePHP to LaravelJason McCreary
 
[245] presto 내부구조 파헤치기
[245] presto 내부구조 파헤치기[245] presto 내부구조 파헤치기
[245] presto 내부구조 파헤치기NAVER D2
 
Aura for PHP at Fossmeet 2014
Aura for PHP at Fossmeet 2014Aura for PHP at Fossmeet 2014
Aura for PHP at Fossmeet 2014Hari K T
 

Similar to Why You Should Use TAPIs (20)

Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQueryRemedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
 
Mock Servers - Fake All the Things!
Mock Servers - Fake All the Things!Mock Servers - Fake All the Things!
Mock Servers - Fake All the Things!
 
PHP applications/environments monitoring: APM & Pinba
PHP applications/environments monitoring: APM & PinbaPHP applications/environments monitoring: APM & Pinba
PHP applications/environments monitoring: APM & Pinba
 
Creating REST Applications with the Slim Micro-Framework by Vikram Vaswani
Creating REST Applications with the Slim Micro-Framework by Vikram VaswaniCreating REST Applications with the Slim Micro-Framework by Vikram Vaswani
Creating REST Applications with the Slim Micro-Framework by Vikram Vaswani
 
Passenger 6 generic language support presentation
Passenger 6 generic language support presentationPassenger 6 generic language support presentation
Passenger 6 generic language support presentation
 
api-platform: the ultimate API platform
api-platform: the ultimate API platformapi-platform: the ultimate API platform
api-platform: the ultimate API platform
 
Rack
RackRack
Rack
 
Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5
 
High-level Programming Languages: Apache Pig and Pig Latin
High-level Programming Languages: Apache Pig and Pig LatinHigh-level Programming Languages: Apache Pig and Pig Latin
High-level Programming Languages: Apache Pig and Pig Latin
 
Ice mini guide
Ice mini guideIce mini guide
Ice mini guide
 
Integration of APEX and Oracle Forms
Integration of APEX and Oracle FormsIntegration of APEX and Oracle Forms
Integration of APEX and Oracle Forms
 
PBDL.pdf
PBDL.pdfPBDL.pdf
PBDL.pdf
 
Design Summit - Rails 4 Migration - Aaron Patterson
Design Summit - Rails 4 Migration - Aaron PattersonDesign Summit - Rails 4 Migration - Aaron Patterson
Design Summit - Rails 4 Migration - Aaron Patterson
 
How and why i roll my own node.js framework
How and why i roll my own node.js frameworkHow and why i roll my own node.js framework
How and why i roll my own node.js framework
 
Intro to Rack
Intro to RackIntro to Rack
Intro to Rack
 
From CakePHP to Laravel
From CakePHP to LaravelFrom CakePHP to Laravel
From CakePHP to Laravel
 
[245] presto 내부구조 파헤치기
[245] presto 내부구조 파헤치기[245] presto 내부구조 파헤치기
[245] presto 내부구조 파헤치기
 
Plack - LPW 2009
Plack - LPW 2009Plack - LPW 2009
Plack - LPW 2009
 
Aura for PHP at Fossmeet 2014
Aura for PHP at Fossmeet 2014Aura for PHP at Fossmeet 2014
Aura for PHP at Fossmeet 2014
 
Zend framework service
Zend framework serviceZend framework service
Zend framework service
 

Recently uploaded

How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?Igalia
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FMESafe Software
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...DianaGray10
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAndrey Devyatkin
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsRoshan Dwivedi
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century educationjfdjdjcjdnsjd
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Principled Technologies
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsJoaquim Jorge
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesBoston Institute of Analytics
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CVKhem
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodJuan lago vázquez
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...apidays
 

Recently uploaded (20)

How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live StreamsTop 5 Benefits OF Using Muvi Live Paywall For Live Streams
Top 5 Benefits OF Using Muvi Live Paywall For Live Streams
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation Strategies
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 

Why You Should Use TAPIs

  • 1. Why You Should Use TAPIs Jeffrey Kemp AUSOUG Connect Perth, November 2016
  • 2. All artifacts including code are presented for illustration purposes only. Use at your own risk. Test thoroughly in a non-critical environment before use.
  • 3. Main Menu 1. Why a data API? 2. Why choose PL/SQL? 3. How to structure your API? 4. Data API for Apex 5. Table APIs (TAPIs) 6. Open Source TAPI project
  • 4. Background “Building Maintainable Apex Apps”, 2014 https://jeffkemponoracle.com/2014/11/14/sample-tapi-apex-application/ https://jeffkemponoracle.com/2016/02/11/tapi-generator-mkii/ https://jeffkemponoracle.com/2016/02/12/apex-api-call-a-package-for-all-your-dml/ https://jeffkemponoracle.com/2016/02/16/apex-api-for-tabular-forms/ https://jeffkemponoracle.com/2016/06/30/interactive-grid-apex-5-1-ea/
  • 5. Why a data API?
  • 6. Why a data API? “I’m building a simple Apex app. I’ll just use the built-in processes to handle all the DML.”
  • 7. Your requirements get more complex. – More single-row and/or tabular forms – More pages, more load routines, more validations, more insert/update processes – Complex conditions – Edge cases, special cases, weird cases
  • 8.
  • 9. Another system must create the same data – outside of Apex – Re-use validations and processing – Rewrite the validations – Re-engineer all processing (insert/update) logic – Same edge cases – Different edge cases
  • 10. Define all validations and processes in one place – Integrated error messages – Works with Apex single-row and tabular forms
  • 11. Simple wrapper to allow code re-use – Same validations and processes included – Reduced risk of regression – Reduced risk of missing bits
  • 12. • They get exactly the same logical outcome as we get • No hidden surprises from Apex features
  • 13. TAPIs Business Rule Validations Default Values Reusability Encapsulation Maintainability
  • 14. Maintainability is in the eye of the beholder maintainer.
  • 15. Techniques • DRY • Consistency • Naming • Single-purpose • Assertions
  • 16. Why use PL/SQL for your API?
  • 17. Why use PL/SQL for your API? • Data is forever • UIs come and go • Business logic – tighter coupling with Data than UI
  • 18. Business Logic • your schema • your data constraints • your validation rules • your insert/update/delete logic
  • 19. • keep business logic close to your data • on Oracle, PL/SQL is the best
  • 23. How should you structure your API?
  • 24. How should you structure your API? Use packages
  • 25. Focus each Package For example: – “Employees” API – “Departments” API – “Workflow” API – Security (user roles and privileges) API – Apex Utilities
  • 26. Package names as context GENERIC_PKG.get_event (event_id => nv('P1_EVENT_ID')); GENERIC_PKG.get_member (member_id => nv('P1_MEMBER_ID')); EVENT_PKG.get (event_id => nv('P1_EVENT_ID')); MEMBER_PKG.get (member_id => nv('P1_MEMBER_ID'));
  • 30. load 1. Get PK value 2. Call TAPI to query record 3. Set session state for each column
  • 32. validate 1. Get values from session state into record 2. Pass record to TAPI 3. Call APEX_ERROR for each validation error
  • 34. process 1. Get v('REQUEST') 2. Get values from session state into record 3. Pass record to TAPI
  • 35. Process a page requestprocedure process is rv EVENTS$TAPI.rvtype; r EVENTS$TAPI.rowtype; begin UTIL.check_authorization(SECURITY.Operator); case when APEX_APPLICATION.g_request = 'CREATE' then rv := apex_get; r := EVENTS$TAPI.ins (rv => rv); apex_set (r => r); UTIL.success('Event created.'); when APEX_APPLICATION.g_request like 'SAVE%' then rv := apex_get; r := EVENTS$TAPI.upd (rv => rv); apex_set (r => r); UTIL.success('Event updated.'); when APEX_APPLICATION.g_request = 'DELETE' then rv := apex_get_pk; EVENTS$TAPI.del (rv => rv); UTIL.clear_page_cache; UTIL.success('Event deleted.'); else null; end case; end process;
  • 36. get_rowfunction apex_get return VOLUNTEERS$TAPI.rvtype is rv VOLUNTEERS$TAPI.rvtype; begin rv.vol_id := nv('P9_VOL_ID'); rv.given_name := v('P9_GIVEN_NAME'); rv.surname := v('P9_SURNAME'); rv.date_of_birth := v('P9_DATE_OF_BIRTH'); rv.address_line := v('P9_ADDRESS_LINE'); rv.suburb := v('P9_SUBURB'); rv.postcode := v('P9_POSTCODE'); rv.state := v('P9_STATE'); rv.home_phone := v('P9_HOME_PHONE'); rv.mobile_phone := v('P9_MOBILE_PHONE'); rv.email_address := v('P9_EMAIL_ADDRESS'); rv.version_id := nv('P9_VERSION_ID'); return rv; end apex_get;
  • 37. set row procedure apex_set (r in VOLUNTEERS$TAPI.rowtype) is begin sv('P9_VOL_ID', r.vol_id); sv('P9_GIVEN_NAME', r.given_name); sv('P9_SURNAME', r.surname); sd('P9_DATE_OF_BIRTH', r.date_of_birth); sv('P9_ADDRESS_LINE', r.address_line); sv('P9_STATE', r.state); sv('P9_SUBURB', r.suburb); sv('P9_POSTCODE', r.postcode); sv('P9_HOME_PHONE', r.home_phone); sv('P9_MOBILE_PHONE', r.mobile_phone); sv('P9_EMAIL_ADDRESS', r.email_address); sv('P9_VERSION_ID', r.version_id); end apex_set;
  • 39. SQL in Apex select t.col_a ,t.col_b ,t.col_c from my_table t; • Move joins, select expressions, etc. to a view – except Apex-specific stuff like generated APEX_ITEMs
  • 40. Pros • Fast development • Smaller apex app • Dependency analysis • Refactoring • Modularity • Code re-use • Customisation • Version control
  • 41. Cons • Misspelled/missing item names – Mitigation: isolate all apex code in one set of packages – Enforce naming conventions – e.g. P1_COLUMN_NAME • Apex Advisor doesn’t check database package code
  • 42. Apex API Coding Standards • All v() calls at start of proc, once per item • All sv() calls at end of proc • Constants instead of 'P1_COL' • Dynamic Actions calling PL/SQL – use parameters • Replace PL/SQL with Javascript (where possible)
  • 43. Error Handling • Validate - only record-level validation • Cross-record validation – db constraints + XAPI • Capture DUP_KEY_ON_VALUE and ORA-02292 for unique and referential constraints • APEX_ERROR.add_error
  • 44. TAPIs • Encapsulate all DML for a table • Row-level validation • Detect lost updates • Generated
  • 45. TAPI contents • Record types – rowtype, arraytype, validation record type • Functions/Procedures – ins / upd / del / merge / get – bulk_ins / bulk_upd / bulk_merge • Constants for enumerations
  • 46. Why not a simple rowtype? procedure ins (emp_name in varchar2 ,dob in date ,salary in number ) is begin if is_invalid_date (dob) then raise_error('Date of birth bad'); elsif is_invalid_number (salary) then raise_error('Salary bad'); end if; insert into emp (emp_name, dob, salary) values (emp_name, dob, salary); end ins; ins (emp_name => :P1_EMP_NAME, dob => :P1_DOB, salary => :P1_SALARY); ORA-01858: a non-numeric character was found where a numeric was expected It’s too late to validate data types here!
  • 47. Validation record type type rv is record ( emp_name varchar2(4000) , dob varchar2(4000) , salary varchar2(4000)); procedure ins (rv in rvtype) is begin if is_invalid_date (dob) then raise_error('Date of birth bad'); elsif is_invalid_number (salary) then raise_error('Salary bad'); end if; insert into emp (emp_name, dob, salary) values (emp_name, dob, salary); end ins; ins (emp_name => :P1_EMP_NAME, dob => :P1_DOB, salary => :P1_SALARY); I’m sorry Dave, I can’t do that - Date of birth bad
  • 48. Example Table create table venues ( venue_id integer default on null venue_id_seq.nextval , name varchar2(200 char) , map_position varchar2(200 char) , created_dt date default on null sysdate , created_by varchar2(100 char) default on null sys_context('APEX$SESSION','APP_USER') , last_updated_dt date default on null sysdate , last_updated_by varchar2(100 char) default on null sys_context('APEX$SESSION','APP_USER') , version_id integer default on null 1 );
  • 49. TAPI example package VENUES$TAPI as cursor cur is select x.* from venues; subtype rowtype is cur%rowtype; type arraytype is table of rowtype index by binary_integer; type rvtype is record (venue_id venues.venue_id%type ,name varchar2(4000) ,map_position varchar2(4000) ,version_id venues.version_id%type ); type rvarraytype is table of rvtype index by binary_integer; -- validate the row function val (rv IN rvtype) return varchar2; -- insert a row function ins (rv IN rvtype) return rowtype; -- update a row function upd (rv IN rvtype) return rowtype; -- delete a row procedure del (rv IN rvtype); end VENUES$TAPI;
  • 50. TAPI ins function ins (rv in rvtype) return rowtype is r rowtype; error_msg varchar2(32767); begin error_msg := val (rv => rv); if error_msg is not null then UTIL.raise_error(error_msg); end if; insert into venues (name ,map_position) values(rv.name ,rv.map_position) returning venue_id ,... into r; return r; exception when dup_val_on_index then UTIL.raise_dup_val_on_index; end ins;
  • 51. TAPI val function val (rv in rvtype) return varchar2 is begin UTIL.val_not_null (val => rv.host_id, column_name => HOST_ID); UTIL.val_not_null (val => rv.event_type, column_name => EVENT_TYPE); UTIL.val_not_null (val => rv.title, column_name => TITLE); UTIL.val_not_null (val => rv.start_dt, column_name => START_DT); UTIL.val_max_len (val => rv.event_type, len => 100, column_name => EVENT_TYPE); UTIL.val_max_len (val => rv.title, len => 100, column_name => TITLE); UTIL.val_max_len (val => rv.description, len => 4000, column_name => DESCRIPTION); UTIL.val_datetime (val => rv.start_dt, column_name => START_DT); UTIL.val_datetime (val => rv.end_dt, column_name => END_DT); UTIL.val_domain (val => rv.repeat ,valid_values => t_str_array(DAILY, WEEKLY, MONTHLY, ANNUALLY) ,column_name => REPEAT); UTIL.val_integer (val => rv.repeat_interval, range_low => 1, column_name => REPEAT_INTERVAL); UTIL.val_date (val => rv.repeat_until, column_name => REPEAT_UNTIL); UTIL.val_ind (val => rv.repeat_ind, column_name => REPEAT_IND); return UTIL.first_error; end val;
  • 52. TAPI upd function upd (rv in rvtype) return rowtype is r rowtype; error_msg varchar2(32767); begin error_msg := val (rv => rv); if error_msg is not null then UTIL.raise_error(error_msg); end if; update venues x set x.name = rv.name ,x.map_position = rv.map_position where x.venue_id = rv.venue_id and x.version_id = rv.version_id returning venue_id ,... into r; if sql%notfound then raise UTIL.lost_update; end if; return r; exception when dup_val_on_index then UTIL.raise_dup_val_on_index; when UTIL.ref_constraint_violation then UTIL.raise_ref_con_violation; when UTIL.lost_update then lost_upd (rv => rv); end upd;
  • 53. Lost update handler procedure lost_upd (rv in rvtype) is db_last_updated_by venues.last_updated_by%type; db_last_updated_dt venues.last_updated_dt%type; begin select x.last_updated_by ,x.last_updated_dt into db_last_updated_by ,db_last_updated_dt from venues x where x.venue_id = rv.venue_id; UTIL.raise_lost_update (updated_by => db_last_updated_by ,updated_dt => db_last_updated_dt); exception when no_data_found then UTIL.raise_error('LOST_UPDATE_DEL'); end lost_upd; “This record was changed by JOE BLOGGS at 4:31pm. Please refresh the page to see changes.” “This record was deleted by another user.”
  • 54. TAPI bulk_ins function bulk_ins (arr in rvarraytype) return number is begin bulk_val(arr); forall i in indices of arr insert into venues (name ,map_position) values (arr(i).name ,arr(i).map_position); return sql%rowcount; exception when dup_val_on_index then UTIL.raise_dup_val_on_index; end bulk_ins;
  • 55. What about queries? Tuning a complex, general-purpose query is more difficult than tuning a complex, single-purpose query.
  • 56. Generating Code • Only PL/SQL • Templates compiled in the schema • Simple syntax • Sub-templates (“includes”) for extensibility
  • 57. OraOpenSource TAPI • Runs on NodeJS • Uses Handlebars for template processing • https://github.com/OraOpenSource/oos-tapi/ • Early stages, needs contributors
  • 58. OOS-TAPI Example create or replace package body {{toLowerCase table_name}} as gc_scope_prefix constant varchar2(31) := lower($$plsql_unit) || '.'; procedure ins_rec( {{#each columns}} p_{{toLowerCase column_name}} in {{toLowerCase data_type}} {{#unless @last}},{{lineBreak}}{{/unless}} {{~/each}} ); end {{toLowerCase table_name}};
  • 59. oddgen • SQL*Developer plugin • Code generator, including TAPIs • Support now added in jk64 Apex TAPI generator https://www.oddgen.org
  • 60.

Editor's Notes

  1. It’s declarative – no code required to load, validate, insert, update and delete data.” Apex handles so much for us, making the app more reliable and us more productive – such as automatic lost update detection, basic data type validations including maximum field lengths, date formats, mandatory fields and more.” (Why would a sane developer want to rebuild any of this?)
  2. (and you have a hard time remembering the details of what you built last week)
  3. No need to reverse-engineer the logic, no need to replicate things with added risk of hidden surprises
  4. Code that is easy to maintain is code that is easy to read, and easy to test.
  5. Remember, maintainability is NOT a problem for you while you are writing the code. It is a problem you need to solve for the person 3 months later who needs to maintain your code.
  6. How do we make code easier to read and test?
  7. Organise and name your packages according to how they will be used elsewhere. This means your function and procedure names can be very short, because you no longer have to say “get_event”
  8. Table APIs will form the “Model” part of the MVC equation. Apex provides the “View” part. The Controller is what we’ll implement almost completely in PL/SQL in database packages.
  9. NV is only used for hidden items that should always have numerical values. The TAPI will handle all other data type conversions (such as numbers and dates).
  10. For Dynamic Actions, since performance is the top priority, I’d always use parameters for any data required.
  11. IF/ELSE and CASE statements instead of Apex conditions. The code is more re-usable: both across pages within the application, as well as by other apex applications or even other UIs and system interfaces. Easier to read, debug, diagnose and version control. Code merge has been solved for database PL/SQL source files, but not for Apex components.
  12. Especially good for external interfaces, e.g. for inserting into an eBus interface table
  13. Where multiple rows might need to be processed, always use bulk binding and bulk DML. Never ever call single-row routines from within a loop!
  14. The val routine in a TAPI should rarely if ever query other tables – it usually only validates the row in isolation within its own context. Generally cross-record and cross-table validation should be done at the XAPI level, or rely on table constraints.