Application Express Tips

A collection of Application Express tips.

APEX System Views

-- Definitions
select * from APEX_DICTIONARY;
select * from APEX_WORKSPACES;
select * from APEX_APPLICATIONS ORDER BY WORKSPACE, APPLICATION_ID;
select * from APEX_WORKSPACE_APEX_USERS;
select * from APEX_WORKSPACE_SCHEMAS;

-- Development
select * from APEX_DEBUG_MESSAGES;
select * from APEX_DEVELOPER_ACTIVITY_LOG;
select WORKSPACE_NAME, USER_NAME, IS_ADMIN, IS_APPLICATION_DEVELOPER, ACCOUNT_LOCKED  from APEX_WORKSPACE_DEVELOPERS ORDER BY 1,2;

-- Environment
select * from APEX_RELEASE;
select * from APEX_PATCHES;
select * from APEX_INSTANCE_PARAMETERS;
select * from APEX_WORKSPACE_SESSIONS;

-- Logging
select * from APEX_USAGE_METRICS;
select * from APEX_WORKSPACE_ACCESS_LOG;
select * from APEX_WORKSPACE_ACTIVITY_LOG;

Application Express Helpful Queries

Find Apex Installations

SELECT * FROM ALL_USERS WHERE USERNAME LIKE 'APEX%';

Find Apex Workspaces

SELET WORKSPACE FROM APEX_nnnnnn.APEX_WORKSPACES;

Find Apex Users

SELECT USER_NAME FROM APEX_nnnnnn.WWV_FLOW_FND_USER;

Creating an Application Express URL from Scratch

In this case I had to dynamically choose the page to branch to and set 2 parameters dynamically...

You will need to update the variables for your particular application, but this includes all the placeholders for the different sections of the URL. Use the "Branch To Function Returning URL" type of branch and modify the following code to suit your application:

DECLARE
  my_url VARCHAR2(256) := 'f?';
BEGIN
  -- Application
  my_url := my_url || 'p='||v('APP_ID') ||':';
  -- Page
  my_url := my_url || :P_TARGET_PAGE || ':';
  -- Session
  my_url := my_url || v('APP_SESSION') ||':';
  -- Request
  my_url := my_url || v('REQUEST') || ':';
  -- Debug
  my_url := my_url || v('DEBUG') || ':';
  -- ClearCache
  my_url := my_url || ':';
  -- itemNames
  my_url := my_url || 'P'||:P_TARGET_PAGE||'_SELECT_START,';
  my_url := my_url || 'P'||:P_TARGET_PAGE||'_SELECT_END:';
  -- ItemValues
  my_url := my_url || :P_SELECT_START||','||:P_SELECT_END;

  return my_url;
END;

PL/SQL Rest APIs - Best Practices

Resource Handler PL/SQL

  • Create a simple handler with 2 parameters, :id and :value.
  • Here is standard code with error handling that returns HTTP return codes to API caller.
DECLARE
    retval integer := 1;
BEGIN

    retval := UPDATEPROC(:id, :value);

    IF retval = 0 THEN
      -- No errors
      COMMIT;
      :status_code := 200;
    ELSE
      -- Error of some type that we detected in UPDATEPROC
      :string_out := 'An error occurred on the server side: ' || SQLERRM;
      :status_code := 500;
    END IF;


EXCEPTION
    WHEN OTHERS
    THEN
        -- Error detected via PL/SQL Exception
        :string_out := 'An error occurred during processing: ' || SQLERRM;
        :status_code := 500;
END;

GET PL/SQL Example (Retrieve)

Description : Basic GET example with option for subsstring search
Method : GET
Source Type : PL/SQL
Returns : 200 for normal completion, ORDS generated messages if error

DECLARE
    c sys_refcursor;
BEGIN
  IF :SEARCH_NAME IS NOT NULL THEN
    -- Return Matching ID
    OPEN c FOR SELECT *
                 FROM EMP 
                WHERE UPPER(TRIM(EMP.ENAME)) LIKE '%'||UPPER(TRIM(:SEARCH_NAME))||'%';
    apex_json.write(c);
  ELSE
    -- No Search Criteria, Return All
    OPEN c FOR SELECT *
                 FROM EMP;
    apex_json.write(c);
  END IF;
END;

Testing

GET https://test.com/ords/apxdev/inventory/test/demo
[
  {
    "EMPNO": 7698,
    "ENAME": "BLAKE",
    "JOB": "MANAGER",
    "MGR": 7839,
    "HIREDATE": "1981-05-01T00:00:00Z",
    "SAL": 2850,
    "DEPTNO": 30
  },
  {
    "EMPNO": 7839,
    "ENAME": "KING",
    "JOB": "PRESIDENT",
    "HIREDATE": "1981-11-17T00:00:00Z",
    "SAL": 5000,
    "DEPTNO": 10
  }
]


GET https://test.com/ords/apxdev/inventory/test/demo?SEARCH_NAME=KING
[
  {
    "EMPNO": 7839,
    "ENAME": "KING",
    "JOB": "PRESIDENT",
    "HIREDATE": "1981-11-17T00:00:00Z",
    "SAL": 5000,
    "DEPTNO": 10
  }
]


GET https://test.com/ords/apxdev/inventory/test/demo?SEARCH_NAME=JUNKSTRING
[
]

POST PL/SQL Example (Creation)

Description : Basic POST creation example
Method : POST
Source Type : PL/SQL
Returns : 201 for normal creation, 400 for caught exceptions, ORDS generated messages if other error

-- POST : Create New Emp
DECLARE
  MY_NEW_ID NUMBER;
  c sys_refcursor;
BEGIN

  SELECT MAX(EMPNO)+1 INTO MY_NEW_ID FROM EMP;

  INSERT INTO EMP  (
    EMPNO,
    ENAME,
    JOB,
    MGR,
    HIREDATE,
    SAL,
    COMM,
    DEPTNO
  ) VALUES (
    MY_NEW_ID, 
    :ENAME,
    :JOB,
    :MGR,
    :HIREDATE,
    :SAL,
    :COMM,
    :DEPTNO
  );

  COMMIT;
  :STATUS_CODE:=201;

  -- Return Matching ID
  OPEN c FOR SELECT * 
        FROM EMP 
       WHERE EMPNO = MY_NEW_ID;
    apex_json.write(c);
  EXCEPTION
    WHEN OTHERS THEN 
      :STATUS_CODE := 400;
      :ERRMSG := SQLERRM;
END;

Testing

POST https://test.com/ords/apxdev/inventory/test/demo?ENAME=David&JOB=Test Job&MGR=7698&HIREDATE=01-JAN-2024&SAL=1000&COMM=100&DEPTNO=10

[ { "EMPNO":7840 ,"ENAME":"David" ,"JOB":"Test Job" ,"MGR":7698 ,"HIREDATE":"2024-01-01T00:00:00Z" ,"SAL":1000 ,"COMM":100 ,"DEPTNO":10 } ]

PUT PL/SQL Example (Update)

Description : Basic PUT Update Example
Method : PUT
Source Type : PL/SQL
Returns : 200 for normal update, 400 for caught exceptions, ORDS generated messages if other error

-- PUT : Update Employee Data
DECLARE
  c sys_refcursor;
BEGIN

  IF (:EMPNO IS NULL) THEN
    :STATUS_CODE:=400;
    :ERRMSG := 'Required value is missing (EMPNO)';

  ELSE

--    UPDATE EMP SET ENAME = :ENAME WHERE EMPNO = :EMPNO;
    UPDATE EMP SET ENAME = :ENAME , MGR=:MGR, HIREDATE=:HIREDATE,SAL=:SAL,COMM=:COMM,DEPTNO=:DEPTNO
    WHERE EMPNO = :EMPNO;

    COMMIT;
    :STATUS_CODE:=200;
    -- Return Updated Values for Confirmation
    OPEN c FOR SELECT * 
                 FROM EMP
                WHERE EMPNO = :EMPNO;
    apex_json.write(c);
  END IF;
  EXCEPTION
    WHEN OTHERS THEN 
      :STATUS_CODE := 400;
      :ERRMSG := SQLERRM;
END;

Testing

PUT https://test.com/ords/apxdev/inventory/test/demo?ENAME=Jonx3&JOB=Test Job&MGR=7698&HIREDATE=01-JAN-2024&SAL=1000&COMM=100&DEPTNO=20&EMPNO=7840

[
    {
        "EMPNO": 7840,
        "ENAME": "Jonx3",
        "JOB": "Test Job",
        "MGR": 7698,
        "HIREDATE": "2024-01-01T00:00:00Z",
        "SAL": 1000,
        "COMM": 100,
        "DEPTNO": 20
    }
]

Rendering and Decoding Checkboxes in an Apex Page

Purpose
A quick example of how to render and decode checkboxes in an Apex page.
Example Objects
EMP table from Scott example schema.
Set up the interface
Use the APEX_ITEM.CHECKBOX function to render checkboxes in a report.

An example query:

SELECT ENAME, 
       APEX_ITEM.CHECKBOX(1,empno, Selected) as CommissionAllowed
  FROM ( select emp.*, 
                (SELECT 'CHECKED' FROM DUAL WHERE comm IS NOT NULL) as Selected 
           FROM EMP )
 ORDER BY 1;

This will produce output that will render checkboxes. The checkbox will be selected if the EMP. COMM field is not null. Sort of a useless example, but you can see what we're getting at.

ENAME	COMMISSIONALLOWED

ADAMS	<input type="checkbox" name="f01" value="7876"  />
ALLEN	<input type="checkbox" name="f01" value="7499" CHECKED />
BLAKE	<input type="checkbox" name="f01" value="7698"  />
CLARK	<input type="checkbox" name="f01" value="7782"  />
FORD	<input type="checkbox" name="f01" value="7902"  />
...

Set up the processing code

Now once your page is submitted you want to review the submitted items and act upon them.

Create a Page Process after submit. Make sure to use the Conditional Processing section to attach the process to a button press.

Note that after the page submit we will only be notified which checkboxes have 'CHECKED' selected. If you need to find the difference between before and after states you may need to do some fancy logic. Here I am just deleting all the records from COMM_ALLOWED and repopulating. Again, maybe a useless example, but you can see how we get the data out of the interface and work with it in PL/SQL.

DELETE FROM COMM_ALLOWED;

FOR I in 1..APEX_APPLICATION.G_F01.COUNT LOOP
    INSERT INTO COMM_ALLOWED (
        EMPNO
    ) VALUES (
        APEX_APPLICATION.G_F01(i)
    );

END LOOP;

Text Boxes

Force Uppercase
In HTML Form Element Attributes enter the following:

onChange="javascript:this.value=this.value.toUpperCase();"