Skip to main content

Command Palette

Search for a command to run...

Clonado de endpoints en ORDS para versionado de APIs (cuando la consola no es suficiente)

Updated
5 min read
Clonado de endpoints en ORDS para versionado de APIs (cuando la consola no es suficiente)

Uno de los escenarios más habituales al trabajar con Oracle REST Data Services (ORDS) es el versionado de APIs.

Antes de entender qué hace el script de clonado, es importante comprender cómo modela ORDS una API internamente.

ORDS no trabaja con “endpoints sueltos”, sino con una jerarquía bien definida.

El diagrama resume esta estructura:

Módulo
 └── Template (ruta)
      └── Handler (método HTTP)
           └── Parámetros

Por ejemplo:

/JsonConsulta/v1
/JsonConsulta/v2

El nombre del API y del recurso se mantiene, y lo único que queremos cambiar es la versión (v1, v2, etc.) en nuestro caso.

El problema es que ORDS no permite clonar un endpoint desde la consola web.

Cuando un endpoint tiene:

  • SQL complejo

  • Múltiples parámetros

  • Lógica probada en producción

Copiarlo a mano para una nueva versión es lento y propenso a errores.

Para resolver esto, se puede clonar directamente el endpoint desde el diccionario de ORDS, usando PL/SQL.

Objetivo del script

Este procedimiento:

  • Clona un endpoint ORDS existente (v1) a una nueva versión (v2) o simplemente copiarlo con un nombre nuevo.

  • Mantiene el mismo módulo

  • Copia handlers, SQL y parámetros

  • Evita duplicados (puede ejecutarse más de una vez sin romper nada)

Está pensado especialmente para entornos donde se quiere evolucionar una API sin tocar la versión anterior.

Script completo de clonado de endpoint ORDS

Para tener el proceso controlado conectamos con el propietario del esquema ORDS.

Variables principales

v_module_name := 'nombremodulo'; 
v_template_src := 'nombretemplateorigen/vx';
v_template_dst := 'nombretemplatedestino/vx';
  • Módulo ORDS donde existe el API

  • Template origen (endpoint actual)

  • Template destino (nueva versión)

SET SERVEROUTPUT ON

DECLARE
    v_module_id       NUMBER;
    v_template_exists NUMBER;
    v_handler_exists  NUMBER;
    v_param_exists    NUMBER;

    -- Nombre lógico del módulo
    v_module_name     VARCHAR2(100) := 'nombremodulo';

    -- Template origen y template destino (clonado)
    v_template_src    VARCHAR2(100) := 'JsonConsulta/v1';
    v_template_dst    VARCHAR2(100) := 'JsonConsulta/v2';

BEGIN
    -- Obtener el ID del módulo ORDS
    SELECT id
    INTO v_module_id
    FROM user_ords_modules
    WHERE name = v_module_name;

    -- Crear el template destino si no existe
    SELECT COUNT(*)
    INTO v_template_exists
    FROM user_ords_templates
    WHERE module_id = v_module_id
      AND uri_template = v_template_dst;

    IF v_template_exists = 0 THEN
        ORDS.DEFINE_TEMPLATE(
            p_module_name => v_module_name,
            p_pattern     => v_template_dst,
            p_priority    => 0,
            p_etag_type   => 'HASH',
            p_comments    => 'Clonado desde ' || v_template_src
        );
        DBMS_OUTPUT.PUT_LINE('Template ' || v_template_dst || ' creado.');
    ELSE
        DBMS_OUTPUT.PUT_LINE('Template ' || v_template_dst || ' ya existe.');
    END IF;

    -- Clonar todos los handlers (GET, POST, etc.)
    FOR src_handler IN (
        SELECT h.method,
               h.source_type,
               h.source,
               h.items_per_page,
               h.mimes_allowed,
               h.comments
        FROM user_ords_handlers h
        JOIN user_ords_templates t ON h.template_id = t.id
        WHERE t.module_id = v_module_id
          AND t.uri_template = v_template_src
        ORDER BY h.id
    ) LOOP
        SELECT COUNT(*)
        INTO v_handler_exists
        FROM user_ords_handlers h
        JOIN user_ords_templates t ON h.template_id = t.id
        WHERE t.module_id = v_module_id
          AND t.uri_template = v_template_dst
          AND h.method = src_handler.method;

        IF v_handler_exists = 0 THEN
            ORDS.DEFINE_HANDLER(
                p_module_name    => v_module_name,
                p_pattern        => v_template_dst,
                p_method         => src_handler.method,
                p_source_type    => src_handler.source_type,
                p_items_per_page => src_handler.items_per_page,
                p_mimes_allowed  => src_handler.mimes_allowed,
                p_comments       => 'Clonado desde ' || v_template_src,
                p_source         => src_handler.source
            );
            DBMS_OUTPUT.PUT_LINE(
                'Handler ' || src_handler.method || ' creado.'
            );
        ELSE
            DBMS_OUTPUT.PUT_LINE(
                'Handler ' || src_handler.method || ' ya existe.'
            );
        END IF;
    END LOOP;

    -- Clonar los parámetros de cada handler
    FOR src_param IN (
        SELECT p.name,
               p.bind_variable_name,
               p.source_type,
               p.param_type,
               p.access_method,
               p.comments,
               h.method
        FROM user_ords_parameters p
        JOIN user_ords_handlers h ON p.handler_id = h.id
        JOIN user_ords_templates t ON h.template_id = t.id
        WHERE t.module_id = v_module_id
          AND t.uri_template = v_template_src
        ORDER BY h.method, p.name
    ) LOOP
        SELECT COUNT(*)
        INTO v_param_exists
        FROM user_ords_parameters p
        JOIN user_ords_handlers h ON p.handler_id = h.id
        JOIN user_ords_templates t ON h.template_id = t.id
        WHERE t.module_id = v_module_id
          AND t.uri_template = v_template_dst
          AND p.name = src_param.name
          AND h.method = src_param.method;

        IF v_param_exists = 0 THEN
            ORDS.DEFINE_PARAMETER(
                p_module_name        => v_module_name,
                p_pattern            => v_template_dst,
                p_method             => src_param.method,
                p_name               => src_param.name,
                p_bind_variable_name => src_param.bind_variable_name,
                p_source_type        => src_param.source_type,
                p_param_type         => src_param.param_type,
                p_access_method      => src_param.access_method,
                p_comments           => src_param.comments
            );
            DBMS_OUTPUT.PUT_LINE(
                'Parámetro ' || src_param.name ||
                ' (' || src_param.method || ') creado.'
            );
        ELSE
            DBMS_OUTPUT.PUT_LINE(
                'Parámetro ' || src_param.name ||
                ' (' || src_param.method || ') ya existe.'
            );
        END IF;
    END LOOP;

    COMMIT;
    DBMS_OUTPUT.PUT_LINE('Clonación del endpoint completada.');

END;
/

Ejemplo salida:

Template JsonConsulta/v2 creado. 
Handler JsonConsulta/v2 [GET] creado. 
Parametro parm1 para método GET creado. 
Parametro parm2 para método GET creado. 
Parametro parm3 para método GET creado. 
Parametro parm4 para método GET creado. 
Parametro parm5 para método GET creado.
Parametro parm6 para método GET creado. 
Parametro parm7 para método GET creado. 
Parametro parm8 para método GET creado. 
Parametro parm9 para método GET creado. 
Parametro parm10 para método GET creado. 
Parametro parm11 para método GET creado. 
Clonación completada exitosamente. 
PL/SQL procedure successfully completed.

¿Qué hace realmente este script?

A alto nivel, el procedimiento reproduce internamente lo que haríamos a mano en ORDS, pero de forma segura:

  • Usa las vistas USER_ORDS_* para leer la definición actual del API

  • Replica exactamente:

    • La ruta del endpoint (solo cambia la versión/nombre)

    • Los métodos HTTP

    • El SQL asociado

    • Todos los parámetros y binds

  • Comprueba siempre si algo ya existe antes de crearlo

Esto permite ejecutar el script varias veces sin riesgo y mantener un versionado limpio y controlado.

¿Por qué hacerlo así y no a mano?

✔ Evita errores copiando SQL
✔ Permite versionado limpio de APIs
✔ Es repetible y controlado
✔ Suple una limitación real de la consola ORDS

Especialmente útil en:

  • Entornos de pruebas

  • Versionado de APIs

  • Cambios controlados antes de producción

Conclusión

Aunque ORDS es una herramienta potente, no todo se puede hacer desde la consola web.

Conociendo su diccionario interno y las APIs PL/SQL (ORDS.DEFINE_*), es posible automatizar tareas avanzadas como el clonado completo de endpoints.

Este procedimiento convierte una tarea manual y propensa a errores en un proceso seguro y limpio.

Y como refrexión personal, poner botón para clonar un endpoint desde la consola web por lo que vemos no debería ser tan complejo implementarlo.

More from this blog