Centralized Master Validation Framework in Oracle APEX
Published on 30 Dec 2025 by CHATURVEDINIDHI26@GMAIL.COM
Centralized Master Validation Framework in Oracle APEX
Centralized Validation Framework in Oracle APEX
In enterprise Oracle APEX applications, validation plays a critical role in
data quality and user experience. A professional validation framework should:
- Show errors exactly below the related item
- Display errors in the notification area
- Allow users to click an error and jump to the field
- Be reusable across multiple pages
This article explains how to build and use a centralized validation package
in Oracle APEX that fulfils all these requirements.
1. Why Centralized Validation Is Required
Creating validations individually on every page leads to duplicate logic,
inconsistent messages, and high maintenance cost.
A centralized PL/SQL package:
- Ensures consistent validation rules
- Reduces page-level complexity
- Makes changes easier and safer
- Improves long-term maintainability
2. Validation Package Specification
The package exposes two core functionalities:
- Mandatory field validation (generic)
- Identity validation (Email, Phone, PAN, GSTIN)
Package Specification
CREATE OR REPLACE PACKAGE validation\_master\_pkg AS
PROCEDURE validate\_identity (
p\_email IN VARCHAR2 DEFAULT NULL,
p\_phone IN VARCHAR2 DEFAULT NULL,
p\_pan IN VARCHAR2 DEFAULT NULL,
p\_gstin IN VARCHAR2 DEFAULT NULL,
p\_email\_required IN BOOLEAN DEFAULT FALSE,
p\_phone\_required IN BOOLEAN DEFAULT FALSE,
p\_pan\_required IN BOOLEAN DEFAULT FALSE,
p\_gstin\_required IN BOOLEAN DEFAULT FALSE
);
PROCEDURE validate\_mandatory (
p\_value IN VARCHAR2,
p\_item\_name IN VARCHAR2,
p\_label IN VARCHAR2
);
END validation\_master\_pkg;
/
3. Validation Package Body (Complete Working Code)
Package Body
CREATE OR REPLACE PACKAGE BODY validation\_master\_pkg AS
PROCEDURE validate\_identity (
p\_email IN VARCHAR2 DEFAULT NULL,
p\_phone IN VARCHAR2 DEFAULT NULL,
p\_pan IN VARCHAR2 DEFAULT NULL,
p\_gstin IN VARCHAR2 DEFAULT NULL,
p\_email\_required IN BOOLEAN DEFAULT FALSE,
p\_phone\_required IN BOOLEAN DEFAULT FALSE,
p\_pan\_required IN BOOLEAN DEFAULT FALSE,
p\_gstin\_required IN BOOLEAN DEFAULT FALSE
) IS
BEGIN
IF p\_email\_required AND p\_email IS NULL THEN
apex\_error.add\_error(
p\_message => '<a href="#P\_EMAIL">Email is required</a>',
p\_display\_location => apex\_error.c\_inline\_with\_field\_and\_notif,
p\_page\_item\_name => 'P\_EMAIL'
);
ELSIF p\_email IS NOT NULL
AND NOT REGEXP\_LIKE(
p\_email,
'^\[A-Za-z0-9.\_%+-\]+@\[A-Za-z0-9.-\]+\\.\[A-Za-z\]{2,}$'
) THEN
apex\_error.add\_error(
p\_message => '<a href="#P\_EMAIL">Invalid Email format</a>',
p\_display\_location => apex\_error.c\_inline\_with\_field\_and\_notif,
p\_page\_item\_name => 'P\_EMAIL'
);
END IF;
IF p\_phone\_required AND p\_phone IS NULL THEN
apex\_error.add\_error(
p\_message => '<a href="#P\_PHONE">Phone number is required</a>',
p\_display\_location => apex\_error.c\_inline\_with\_field\_and\_notif,
p\_page\_item\_name => 'P\_PHONE'
);
ELSIF p\_phone IS NOT NULL
AND NOT REGEXP\_LIKE(p\_phone, '^\[6-9\]\[0-9\]{9}$') THEN
apex\_error.add\_error(
p\_message => '<a href="#P\_PHONE">Invalid Phone Number</a>',
p\_display\_location => apex\_error.c\_inline\_with\_field\_and\_notif,
p\_page\_item\_name => 'P\_PHONE'
);
END IF;
IF p\_pan\_required AND p\_pan IS NULL THEN
apex\_error.add\_error(
p\_message => '<a href="#P\_PAN">PAN is required</a>',
p\_display\_location => apex\_error.c\_inline\_with\_field\_and\_notif,
p\_page\_item\_name => 'P\_PAN'
);
ELSIF p\_pan IS NOT NULL
AND NOT REGEXP\_LIKE(UPPER(p\_pan), '^\[A-Z\]{5}\[0-9\]{4}\[A-Z\]$') THEN
apex\_error.add\_error(
p\_message => '<a href="#P\_PAN">Invalid PAN format</a>',
p\_display\_location => apex\_error.c\_inline\_with\_field\_and\_notif,
p\_page\_item\_name => 'P\_PAN'
);
END IF;
IF p\_gstin\_required AND p\_gstin IS NULL THEN
apex\_error.add\_error(
p\_message => '<a href="#P\_GSTIN">GSTIN is required</a>',
p\_display\_location => apex\_error.c\_inline\_with\_field\_and\_notif,
p\_page\_item\_name => 'P\_GSTIN'
);
ELSIF p\_gstin IS NOT NULL
AND NOT REGEXP\_LIKE(
UPPER(p\_gstin),
'^\[0-9\]{2}\[A-Z\]{5}\[0-9\]{4}\[A-Z\]\[1-9A-Z\]Z\[0-9A-Z\]$'
) THEN
apex\_error.add\_error(
p\_message => '<a href="#P\_GSTIN">Invalid GSTIN format</a>',
p\_display\_location => apex\_error.c\_inline\_with\_field\_and\_notif,
p\_page\_item\_name => 'P\_GSTIN'
);
END IF;
END validate\_identity;
PROCEDURE validate\_mandatory (
p\_value IN VARCHAR2,
p\_item\_name IN VARCHAR2,
p\_label IN VARCHAR2
) IS
BEGIN
IF p\_value IS NULL THEN
apex\_error.add\_error(
p\_message => '<a href="#'||p\_item\_name||'">'||p\_label||' is required</a>',
p\_display\_location => apex\_error.c\_inline\_with\_field\_and\_notif,
p\_page\_item\_name => p\_item\_name
);
END IF;
END validate\_mandatory;
END validation\_master\_pkg;
/
4. How to Use the Package on an APEX Page
All validations are triggered from a single After Submit page process.
Page Process Code
BEGIN
validation\_master\_pkg.validate\_mandatory(
p\_value => :P9999\_COMPANY\_CODE,
p\_item\_name => 'P9999\_COMPANY\_CODE',
p\_label => 'Company Code'
);
validation\_master\_pkg.validate\_mandatory(
p\_value => :P9999\_USERNAME,
p\_item\_name => 'P9999\_USERNAME',
p\_label => 'Username'
);
validation\_master\_pkg.validate\_mandatory(
p\_value => :P9999\_PASSWORD,
p\_item\_name => 'P9999\_PASSWORD',
p\_label => 'Password'
);
END;
5. User Experience Outcome
- Errors appear directly below the related field
- Errors are also visible in the notification area
- Clicking an error focuses the corresponding item
- Errors disappear automatically after valid input
6. Conclusion
This centralized validation framework provides a clean, reusable, and
enterprise-ready approach to validation in Oracle APEX applications.
It improves maintainability, enforces consistency, and delivers a superior
user experience without cluttering page-level logic.