SlideShare a Scribd company logo
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

Bootiful Development with Spring Boot and React
Bootiful Development with Spring Boot and ReactBootiful Development with Spring Boot and React
Bootiful Development with Spring Boot and React
VMware Tanzu
 
JPA Week3 Entity Mapping / Hexagonal Architecture
JPA Week3 Entity Mapping / Hexagonal ArchitectureJPA Week3 Entity Mapping / Hexagonal Architecture
JPA Week3 Entity Mapping / Hexagonal Architecture
Covenant Ko
 
Capella Days 2021 | Introduction to CAPELLA/ARCADIA and NASA Systems Engineer...
Capella Days 2021 | Introduction to CAPELLA/ARCADIA and NASA Systems Engineer...Capella Days 2021 | Introduction to CAPELLA/ARCADIA and NASA Systems Engineer...
Capella Days 2021 | Introduction to CAPELLA/ARCADIA and NASA Systems Engineer...
Obeo
 
Oracle APEX, Low Code for Data Driving Apps
Oracle APEX, Low Code for Data Driving AppsOracle APEX, Low Code for Data Driving Apps
Oracle APEX, Low Code for Data Driving Apps
Franco Ucci
 
Dump Answers
Dump AnswersDump Answers
Dump Answers
sailesh kushwaha
 
Oracle Spatial Studio: Fast and Easy Spatial Analytics and Maps
Oracle Spatial Studio:  Fast and Easy Spatial Analytics and MapsOracle Spatial Studio:  Fast and Easy Spatial Analytics and Maps
Oracle Spatial Studio: Fast and Easy Spatial Analytics and Maps
Jean Ihm
 
Chapter 3 stored procedures
Chapter 3 stored proceduresChapter 3 stored procedures
Testing with JUnit 5 and Spring - Spring I/O 2022
Testing with JUnit 5 and Spring - Spring I/O 2022Testing with JUnit 5 and Spring - Spring I/O 2022
Testing with JUnit 5 and Spring - Spring I/O 2022
Sam Brannen
 
【BS1】What’s new in visual studio 2022 and c# 10
【BS1】What’s new in visual studio 2022 and c# 10【BS1】What’s new in visual studio 2022 and c# 10
【BS1】What’s new in visual studio 2022 and c# 10
日本マイクロソフト株式会社
 
Simplify DevOps with Microservices and Mobile Backends.pptx
Simplify DevOps with Microservices and Mobile Backends.pptxSimplify DevOps with Microservices and Mobile Backends.pptx
Simplify DevOps with Microservices and Mobile Backends.pptx
ssuser5faa791
 
Simon Laws – Apache Flink Cluster Deployment on Docker and Docker-Compose
Simon Laws – Apache Flink Cluster Deployment on Docker and Docker-ComposeSimon Laws – Apache Flink Cluster Deployment on Docker and Docker-Compose
Simon Laws – Apache Flink Cluster Deployment on Docker and Docker-Compose
Flink Forward
 
MAINVIEW for DB2.ppt
MAINVIEW for DB2.pptMAINVIEW for DB2.ppt
MAINVIEW for DB2.ppt
Sreedhar Ambatipudi
 
1 - Introduction to PL/SQL
1 - Introduction to PL/SQL1 - Introduction to PL/SQL
1 - Introduction to PL/SQL
rehaniltifat
 
Introduction to PostgreSQL
Introduction to PostgreSQLIntroduction to PostgreSQL
Introduction to PostgreSQL
Jim Mlodgenski
 
Oracle - Program with PL/SQL - Lession 03
Oracle - Program with PL/SQL - Lession 03Oracle - Program with PL/SQL - Lession 03
Oracle - Program with PL/SQL - Lession 03
Thuan Nguyen
 
Oracle sql joins
Oracle sql joinsOracle sql joins
Oracle sql joins
redro
 
Cursors in MySQL
Cursors in MySQL Cursors in MySQL
Cursors in MySQL
Tharindu Weerasinghe
 
From Java 11 to 17 and beyond.pdf
From Java 11 to 17 and beyond.pdfFrom Java 11 to 17 and beyond.pdf
From Java 11 to 17 and beyond.pdf
José Paumard
 
SQL Interview Questions - InterviewBit.pdf
SQL Interview Questions - InterviewBit.pdfSQL Interview Questions - InterviewBit.pdf
SQL Interview Questions - InterviewBit.pdf
Aniket223719
 

What's hot (20)

Bootiful Development with Spring Boot and React
Bootiful Development with Spring Boot and ReactBootiful Development with Spring Boot and React
Bootiful Development with Spring Boot and React
 
JPA Week3 Entity Mapping / Hexagonal Architecture
JPA Week3 Entity Mapping / Hexagonal ArchitectureJPA Week3 Entity Mapping / Hexagonal Architecture
JPA Week3 Entity Mapping / Hexagonal Architecture
 
Capella Days 2021 | Introduction to CAPELLA/ARCADIA and NASA Systems Engineer...
Capella Days 2021 | Introduction to CAPELLA/ARCADIA and NASA Systems Engineer...Capella Days 2021 | Introduction to CAPELLA/ARCADIA and NASA Systems Engineer...
Capella Days 2021 | Introduction to CAPELLA/ARCADIA and NASA Systems Engineer...
 
Oracle APEX, Low Code for Data Driving Apps
Oracle APEX, Low Code for Data Driving AppsOracle APEX, Low Code for Data Driving Apps
Oracle APEX, Low Code for Data Driving Apps
 
Dump Answers
Dump AnswersDump Answers
Dump Answers
 
Commands of DML in SQL
Commands of DML in SQLCommands of DML in SQL
Commands of DML in SQL
 
Oracle Spatial Studio: Fast and Easy Spatial Analytics and Maps
Oracle Spatial Studio:  Fast and Easy Spatial Analytics and MapsOracle Spatial Studio:  Fast and Easy Spatial Analytics and Maps
Oracle Spatial Studio: Fast and Easy Spatial Analytics and Maps
 
Chapter 3 stored procedures
Chapter 3 stored proceduresChapter 3 stored procedures
Chapter 3 stored procedures
 
Testing with JUnit 5 and Spring - Spring I/O 2022
Testing with JUnit 5 and Spring - Spring I/O 2022Testing with JUnit 5 and Spring - Spring I/O 2022
Testing with JUnit 5 and Spring - Spring I/O 2022
 
【BS1】What’s new in visual studio 2022 and c# 10
【BS1】What’s new in visual studio 2022 and c# 10【BS1】What’s new in visual studio 2022 and c# 10
【BS1】What’s new in visual studio 2022 and c# 10
 
Simplify DevOps with Microservices and Mobile Backends.pptx
Simplify DevOps with Microservices and Mobile Backends.pptxSimplify DevOps with Microservices and Mobile Backends.pptx
Simplify DevOps with Microservices and Mobile Backends.pptx
 
Simon Laws – Apache Flink Cluster Deployment on Docker and Docker-Compose
Simon Laws – Apache Flink Cluster Deployment on Docker and Docker-ComposeSimon Laws – Apache Flink Cluster Deployment on Docker and Docker-Compose
Simon Laws – Apache Flink Cluster Deployment on Docker and Docker-Compose
 
MAINVIEW for DB2.ppt
MAINVIEW for DB2.pptMAINVIEW for DB2.ppt
MAINVIEW for DB2.ppt
 
1 - Introduction to PL/SQL
1 - Introduction to PL/SQL1 - Introduction to PL/SQL
1 - Introduction to PL/SQL
 
Introduction to PostgreSQL
Introduction to PostgreSQLIntroduction to PostgreSQL
Introduction to PostgreSQL
 
Oracle - Program with PL/SQL - Lession 03
Oracle - Program with PL/SQL - Lession 03Oracle - Program with PL/SQL - Lession 03
Oracle - Program with PL/SQL - Lession 03
 
Oracle sql joins
Oracle sql joinsOracle sql joins
Oracle sql joins
 
Cursors in MySQL
Cursors in MySQL Cursors in MySQL
Cursors in MySQL
 
From Java 11 to 17 and beyond.pdf
From Java 11 to 17 and beyond.pdfFrom Java 11 to 17 and beyond.pdf
From Java 11 to 17 and beyond.pdf
 
SQL Interview Questions - InterviewBit.pdf
SQL Interview Questions - InterviewBit.pdfSQL Interview Questions - InterviewBit.pdf
SQL Interview Questions - InterviewBit.pdf
 

Viewers also liked

Building Maintainable Applications in Apex
Building Maintainable Applications in ApexBuilding Maintainable Applications in Apex
Building Maintainable Applications in Apex
Jeffrey Kemp
 
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
Jeffrey Kemp
 
Apex and Virtual Private Database
Apex and Virtual Private DatabaseApex and Virtual Private Database
Apex and Virtual Private Database
Jeffrey Kemp
 
Automate Amazon S3 Storage with Alexandria
Automate Amazon S3 Storage with AlexandriaAutomate Amazon S3 Storage with Alexandria
Automate Amazon S3 Storage with Alexandria
Jeffrey Kemp
 
11g Function Result Cache
11g Function Result Cache11g Function Result Cache
11g Function Result Cache
Jeffrey Kemp
 
Aws konferenz vortrag gk
Aws konferenz vortrag gkAws konferenz vortrag gk
Aws konferenz vortrag gk
execupery
 
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 - novahackers
Chris Gates
 
Presantecion 1
Presantecion 1Presantecion 1
Presantecion 1huvabayona
 
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
ScholarChip ☁ Tools for Smarter Schools
 

Viewers also liked (13)

Building Maintainable Applications in Apex
Building Maintainable Applications in ApexBuilding Maintainable Applications in Apex
Building Maintainable Applications in Apex
 
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 Vaswani
vvaswani
 
Passenger 6 generic language support presentation
Passenger 6 generic language support presentationPassenger 6 generic language support presentation
Passenger 6 generic language support presentation
Hongli Lai
 
api-platform: the ultimate API platform
api-platform: the ultimate API platformapi-platform: the ultimate API platform
api-platform: the ultimate API platform
Stefan Adolf
 
Rack
RackRack
Rack
shen liu
 
Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5
Elena 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 Latin
Pietro Michiardi
 
Ice mini guide
Ice mini guideIce mini guide
Ice mini guide
Ady Liu
 
Integration of APEX and Oracle Forms
Integration of APEX and Oracle FormsIntegration of APEX and Oracle Forms
Integration of APEX and Oracle Forms
Roel Hartman
 
PBDL.pdf
PBDL.pdfPBDL.pdf
PBDL.pdf
souzatg
 
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
ManageIQ
 
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 Laravel
Jason 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 2014
Hari K T
 
Zend framework service
Zend framework serviceZend framework service
Zend framework service
Michelangelo van Dam
 

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

20240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 202420240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 2024
Matthew Sinclair
 
Elevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object CalisthenicsElevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object Calisthenics
Dorra BARTAGUIZ
 
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdfObservability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Paige Cruz
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance
 
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
SOFTTECHHUB
 
Free Complete Python - A step towards Data Science
Free Complete Python - A step towards Data ScienceFree Complete Python - A step towards Data Science
Free Complete Python - A step towards Data Science
RinaMondal9
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
DianaGray10
 
Video Streaming: Then, Now, and in the Future
Video Streaming: Then, Now, and in the FutureVideo Streaming: Then, Now, and in the Future
Video Streaming: Then, Now, and in the Future
Alpen-Adria-Universität
 
Removing Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software FuzzingRemoving Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software Fuzzing
Aftab Hussain
 
The Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and SalesThe Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and Sales
Laura Byrne
 
GridMate - End to end testing is a critical piece to ensure quality and avoid...
GridMate - End to end testing is a critical piece to ensure quality and avoid...GridMate - End to end testing is a critical piece to ensure quality and avoid...
GridMate - End to end testing is a critical piece to ensure quality and avoid...
ThomasParaiso2
 
Uni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdfUni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems S.M.S.A.
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
DanBrown980551
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
BookNet Canada
 
PCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase TeamPCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase Team
ControlCase
 
Microsoft - Power Platform_G.Aspiotis.pdf
Microsoft - Power Platform_G.Aspiotis.pdfMicrosoft - Power Platform_G.Aspiotis.pdf
Microsoft - Power Platform_G.Aspiotis.pdf
Uni Systems S.M.S.A.
 
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdfFIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance
 
National Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practicesNational Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practices
Quotidiano Piemontese
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance
 
UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5
DianaGray10
 

Recently uploaded (20)

20240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 202420240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 2024
 
Elevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object CalisthenicsElevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object Calisthenics
 
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdfObservability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
Observability Concepts EVERY Developer Should Know -- DeveloperWeek Europe.pdf
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
 
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...
 
Free Complete Python - A step towards Data Science
Free Complete Python - A step towards Data ScienceFree Complete Python - A step towards Data Science
Free Complete Python - A step towards Data Science
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
 
Video Streaming: Then, Now, and in the Future
Video Streaming: Then, Now, and in the FutureVideo Streaming: Then, Now, and in the Future
Video Streaming: Then, Now, and in the Future
 
Removing Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software FuzzingRemoving Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software Fuzzing
 
The Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and SalesThe Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and Sales
 
GridMate - End to end testing is a critical piece to ensure quality and avoid...
GridMate - End to end testing is a critical piece to ensure quality and avoid...GridMate - End to end testing is a critical piece to ensure quality and avoid...
GridMate - End to end testing is a critical piece to ensure quality and avoid...
 
Uni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdfUni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdf
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
 
PCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase TeamPCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase Team
 
Microsoft - Power Platform_G.Aspiotis.pdf
Microsoft - Power Platform_G.Aspiotis.pdfMicrosoft - Power Platform_G.Aspiotis.pdf
Microsoft - Power Platform_G.Aspiotis.pdf
 
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdfFIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
 
National Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practicesNational Security Agency - NSA mobile device best practices
National Security Agency - NSA mobile device best practices
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
 
UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5UiPath Test Automation using UiPath Test Suite series, part 5
UiPath Test Automation using UiPath Test Suite series, part 5
 

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.