JavaScript Handler Functions in ORDS: Pay Attention to Data Types

In the past few weeks, I have written several articles covering JavaScript handlers in Oracle REST Data Services (ORDS). In a nutshell you can write your GET, POST, PUT and DELETE handlers in JavaScript, powered by Multilingual Engine (MLE). I think this is a nice feature.

Recently I ran into a situation where I’m using a GET handler to retrieve data from my application. The ORDS handler is defined like so:

declare
...
begin
...

    ords.define_handler(
        p_module_name => c_module_name,
        p_pattern => 'items/:id',
        p_method => 'GET',
        p_source_type => 'mle/javascript',
        p_mle_env_name => 'DEFAULT_ENV',
        p_items_per_page => 25,
        p_mimes_allowed => null,
        p_comments => 'get a single item',
        p_source => q'~
(req, resp) => {

    const { getObject } = await import('default');
    getObject(req.uri_parameters.id); 
}
        ~'
    );
...
end;
/

Translated into plain English, the handler function (p_source) grabs the ID from the pattern and passes it to the JavaScript code. In my case, however, I got a runtime error in getObject():

Caused by: java.sql.SQLException: MLE user defined resource error.
at ORA-04161: Error: you must provide a numeric ID to getObject().(Unknown Source)
at getObject(default):-78:11.(Unknown Source)
at :=>(<dyn-src-js>):5:5.(Unknown Source)

Here’s the part of the function that throws this exception:

export function getObject(id: number, resp: any): void {

    if (! id || typeof id !== 'number' || ! Number.isFinite(id)) {
        throw new Error('you must provide a numeric ID to getObject()');
    }

    // more code not relevant to this example...
}

Technically, this is TypeScript, but that doesn’t matter here. I’m simply testing if the ID is a number and throw an error if not. Because it’s got to be a number later on, when I select from the database.

Where is the problem? And how can you fix it?

So, where’s the problem? Long story short, the URI parameters are always strings, and passing these to the function causes the error.

Now how can you address this problem? There are 2 possibilities:

  • Convert the string in the ORDS handler
  • Convert the string to a number in getObject()

I personally prefer to keep the logic in the ORDS handlers to a minimum and therefore went with the second option:

export function getObject(id: string, resp: any): void {

    if (! id || typeof id !== 'string') {
        throw new Error('getObject() requires the ID to be a string');
    }

    const numericId = Number(id.trim());

    if (! Number.isSafeInteger(numericId) || numericId <= 0) {
        throw new Error('you must provide an ID greater than 0 to getObject()');
    }

    // more code ...

This fixed my error

Summary

When using MLE/JavaScript handlers in ORDS, it’s a great idea to double- and triple-check input, especially with regards to users with potentially malicious intent. Knowing how data types are passed around, and using type-safe languages, is a step in the right direction, but there is obviously much more to consider. Since this post isn’t about security, these aspects have been deliberately left out but must be at the top of your agenda.

Have fun!