Friendly URL structure

Oracle has updated apex.oracle.com to APEX 20.1 which includes among other features the new “Friendly URL” option. The legacy URL structure concatenated a string of parameters into a single “p” parameter, which works fine; but it can make it difficult to configure web server rules to match and rewrite URLs. Apart from the application ID or alias (the first part), all the parameters are optional; if all were specified the URL will be something like this (line breaks added for clarity):

f?p=SAMPLE_DB_APP:HOME:16801234560918:myrequest:mydebug
  :myclearcache:myitems:myvalues:myprinterfriendly
  &p_trace=mytrace
  &cs=19A56DBFDXXXE4DF293C96D786
  &c=jk64

In this example, the application alias is used (SAMPLE_DB_APP) and page alias (HOME) followed by the session ID etc. I’ve also specified the workspace (jk64) using the “c” query parameter.

In APEX 20.1 if you edit your Application Properties, you will see the new “Friendly URLs” setting.

With this setting turned on, URLs generated throughout the application will take this form (this is not exhaustive, there are other query parameters supported as well):

/pls/apex/jk64/r/sample_db_app/home
   ?myitems=myvalues
   &request=myrequest
   &clear=myclearcache
   &debug=mydebug
   &printerFriendly=myprinterfriendly
   &session=16801234560918
   &p_trace=mytrace
   &cs=19A56DBFDXXXE4DF293C96D786

When the documentation says the URLs should be “easier to read” I’m pretty sure they mean “by developers”, not end users. I suppose this means the URLs make more sense to developers of other web-based applications, because they conform better to REST URL conventions.

In its simplest form, the URL generated by APEX will include just the workspace path prefix, application, page, and session ID:

 /pls/apex/jk64/r/sample_db_app/home?session=16801234560918 

Calling APEX_PAGE.GET_URL generates the URLs correctly for the application according to whether the Friendly URL setting is on or not.

I noticed the following features of this new format:

  • The URL generated by APEX_PAGE.GET_URL now includes a full path (excluding the domain).
  • Instead of the “c” workspace query parameter, the application’s Path Prefix (which could be set to something other than the workspace name) is used (jk64 in my example). This is not the workspace name, although in most cases it usually will happen to be the same because it’s defaulted that way. This attribute is set at the workspace level, under Administration / Manage Service / Set Workspace Preferences / SQL Workshop.
  • If not specified, the application and page alias will be used rather than the application or page ID, which is nice.
  • Even if you specify the application or page alias in uppercase, APEX_PAGE.GET_URL returns them in all lowercase.
  • The more important attributes relevant to a user navigating the application are now further towards the start of the URL, such as page and item values, so they will be more likely to be noticed by the end user.
  • The “/r/” bit in the URL is just that. It’s just “r” and can’t be anything else, don’t ask me what it means. EDIT: apparently it stands for “router”

If your users have bookmarked your application using the legacy URL format, you can still safely upgrade your application to use Friendly URLs because both are still supported. This also means that if you have some old code that generates links programmatically they should still work the same (although it is best practice to call APEX_PAGE.GET_URL for this purpose).

In case you’re wondering, it is not possible to change the URL format when calling APEX_PAGE.GET_URL, it will follow your application’s Friendly URL setting. If you call APEX_PAGE.GET_URL for another application, it will return the correct format of URL for the target application. If you call APEX_PAGE.GET_URL for an application that does not exist, it will return the URL in the legacy format.

Existing applications after upgrading, or ones you import from an older version of APEX, will still use the legacy URL syntax. New applications will use the new Friendly URLs by default – but you can revert them to the legacy URLs if you wish.

On a side note, in earlier versions when you create a new application the application alias was set to the application ID by default. In APEX 20.1, a new application will have an application alias generated from the initial application name; when I tried it, it added a number as well for some reason.

For obvious reasons, existing code that parses the URL (e.g. in javascript on the client) will probably break. This is a fairly rare thing but does happen (such as in a plugin of mine which I’ll need to fix).

At this very early stage, the legacy URL format is still fully supported – I imagine it will eventually be deprecated, but not yet.

Finally, I’d like to point out some entries on the APEX Feature Requests site:

Our patience has been rewarded 🙂

Next/Previous Record: how APEX does it
Font Awesome v5 alongside Font APEX

Comments

  1. The constant “r” in the URL stands for “router”.

    The new trace parameter name is just “trace”, not “p_trace”.

    • Hi Morten,

      Thanks for that, very enlightening.

      With regards to the trace parameter, in my testing on apex.oracle.com the url generated produces “&p_trace=”, not “&trace=”. Perhaps this is a bug, as the documentation does indeed say we should expect it to be called “trace”.

      Jeff

  2. How we can use new format for PREPARE_URL with triggering element
    some cases like apex_util.prepare_url('f?p='||:APP_ID||':24:'||:APP_SESSION||'::NO::P24_CASE_ID:'|| :P21_ID , p_triggering_element => 'apex.jQuery(''#SAVEBUTTON'')' );

    • Jeffrey Kemp
      15 May 2020 - 2:46 pm

      Hi Inzy,

      I recommend switching to use APEX_PAGE.GET_URL instead, which should work with both legacy and friendly URLs depending on what your application uses, e.g.:

      APEX_PAGE.GET_URL (
          p_page               => 24,
          p_items              => 'P24_CASE_ID',
          p_values             => :P21_ID,
          p_triggering_element => q'[apex.jQuery('#SAVEBUTTON')]'
          );
      

      Jeff

  3. I’m one of the ugly guys who embed APEX applications in Confluence pages for end user convenience via iframes. For this to work I have to allow this in the security configuration of my APEX application of course. Worked fine, but …

    I found out that the use of the “userfriendly urls” in the iframe results in a denied access while the use of the “old” url format still works.
    Functional regression?

    And no .. I don’t need any iframe discussion at all ….

  4. Hi,
    I call a pdf report from apex page using url. It was working fine but after enabling the friendly url option, the url is converted from:
    f?p=&APP_ID.:0:&SESSION.:PRINT_REPORT=check_list_maintenance
    to:
    f?p=&APP_ID.:0:&SESSION.:PRINT_REPORT%253Dcheck_list_maintenance
    so the pdf cannot be generated anymore.
    Any idea about that?

    Thank you

    • Hi Issam,

      The new URL is not in “Friendly URL” form so I suspect you have some custom code in your application that is generating the URL directly (i.e. bypassing the APEX URL API). It is then getting encoded for some reason.

      I would examine the code that is generating this URL; you should be able to replace it to use the documented APEX_PAGE.GET_URL function which should generate the correct URL.

      Jeff

  5. Hi Jeffrey

    I have a small problem when switching to Apex 20.1
    Can you suggest a solution?

    https://community.oracle.com/thread/4336950

    • Jeffrey Kemp
      1 July 2020 - 5:01 pm

      Sorry, that link seems to be to an issue with uploading files; how is that related to the new URL structure?

  6. Hi Jefferey,

    l_url :=
    APEX_UTIL.prepare_url (
    p_url =>
    ‘f?p=’
    || :app_id
    || ‘:’
    || :app_page_id
    || ‘:’
    || :app_session);
    OWA_UTIL.redirect_url (l_url);

    Using normal URL, it works fine and redirects, but using friendly URL, it does nothing. Do you suspect any issue with OWA_UTIL?

    Thanks,
    Sunil Bhatia

  7. Hi Jeffrey,

    Can we generate the URLs using JS code. I have an application that determines which page to open based on the selections the user has made. Now I have to make an AJAX call to get the URL from the back-end as the pages are modal and the checksum has to be supplied by the back-end.
    Is there any front-end JS API to generate URLs for modal pages?

    Thanks!
    Arijit

    • Hi Arijit,

      If the page you are linking to requires a checksum, it MUST be generated on your server. If it were possible to generate the checksum on the user’s client machine, that would defeat the purpose of using checksums for security.

      Therefore, if you need to generate a URL on the client, you will need to switch off the checksum requirement on the target page. You will, however, need to consider the security implications of this in the context of your application.

      I hope this helps.

      Jeff

  8. Hi Jeff , how can I make my URL like those in Universal Theme sample app. I mean without sesison state and session id in the URL.

    Ejemple: https://apps.<redacted>.com/ords/r/reflexdevelopment/ut/content-modifiers

    • Hi Alix,

      Any page with authentication set to Page is Public will not add a session ID to the URL.

      Jeff

  9. Hi,

    When workspace is isolated with domain entered in Allow Hostnames, there is no Path Prefix value in the friendly url, when running the app, and application is not available because of this.

    BR

  10. Not sure if this is a bug or expected yet strange behavior. 21.2.1

    Calling apex_mail.send changes the behavior of get url radically.

    SQL>
    SQL> set echo on
    SQL>
    SQL> select apex_page.get_url (
    2 p_application=>100,
    3 p_page=>6,
    4 p_items=>’foo,bar’,
    5 p_values=>’123,test’) from dual;

    APEX_PAGE.GET_URL(P_APPLICATION=>100,P_PAGE=>6,P_ITEMS=>’FOO,BAR’,P_VALUES=>’123,TEST’)
    ————————————————————————————————————————————————————————
    f?p=100:6:::::foo,bar:123,test

    SQL>
    SQL>
    SQL> begin
    2 apex_mail.send(
    3 p_to=>’post.ethan@gmail.com’,
    4 p_from=>’ethan@arclogicsoftware.com’,
    5 p_subj=>’test’,
    6 p_body=>’test’
    7 );
    8 — apex_mail.push_queue;
    9 end;
    10 /

    PL/SQL procedure successfully completed.

    SQL>
    SQL>
    SQL> select apex_page.get_url (
    2 p_application=>100,
    3 p_page=>6,
    4 p_items=>’foo,bar’,
    5 p_values=>’123,test’) from dual;

    APEX_PAGE.GET_URL(P_APPLICATION=>100,P_PAGE=>6,P_ITEMS=>’FOO,BAR’,P_VALUES=>’123,TEST’)
    ————————————————————————————————————————————————————————
    https://k2.maxapex.net/apex/app/r/sldev/submit_weight?foo=123&bar=test

    • Hi Ethan,

      Interesting – I’ve reproduced it as well in 21.2.3. It’s due to the way that apex_page.get_url works in a database session that has not yet been set up as an APEX session. After calling the apex mail API, the session has now been set up as an APEX session so it can now see the application definition and it knows it accepts friendly URLs.

      Before an APEX session is set up, the API has no way of knowing whether the application will accept friendly URLs or not (it cannot see the application definition), so it errs on the side of caution and creates a legacy-style URL which will work either way.

      If you call apex_session.create_session before calling apex_page.get_url, you will get a friendly url as well (although note that in this case, the session query parameter will also be added).

      Jeff

  11. Jeff,
    Great but how do you determine the checksum value for your friendly URL?

    regards

    • Hi Scott, the checksum is calculated by APEX itself, so if your page requires a checksum you must call APEX_PAGE.GET_URL or APEX_UTIL.PREPARE_URL.

Leave a Reply

Your email address will not be published / Required fields are marked *