Invocar Web Services desde PL/SQL en Oracle

El problema

Muchas veces nos vemos en la necesidad de invocar un Web Service directamente desde la base de datos.

La utilización de Java dentro de la base de datos no siempre es una opción disponible, así que tuve que buscar una solución que sólo utilizara código PL/SQL.

La solución

Podemos utilizar el package UTL_HTTP para hacer los request SOAP directamente al servidor destino, esto si bien es más complicado que utilizar las clases proxy, nos evita tener que cargar Java en la base de datos.

La forma de invocar el package UTL_HTTP es la siguiente:

DECLARE
 
    req   UTL_HTTP.req := NULL;
    resp  UTL_HTTP.resp := NULL;
    respVal VARCHAR2(32000);
    reqXML VARCHAR2(32760);
 
BEGIN
 
/*Generamos un Request a la URL destino, el método debe ser POST */
    req := UTL_HTTP.begin_request('http://servidor/ConsultaClientes', 'POST');
 
/*Creamos un mensaje SOAP tal cual se define en el WSDL*/
 
reqXML := '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:m0="ConsultaClientes">
      <SOAP-ENV:Body>
            <m:ConsultaClientes xmlns:m="http://servidor/ConsultaClientes">
                  <m0:mensaje>
                        <m0:idcliente>C123452</m0:idcliente>
                  </m0:mensaje>
            </m:ConsultaClientes>
      </SOAP-ENV:Body>
</SOAP-ENV:Envelope>';
 
/*El contenido que enviamos es XML: */
    UTL_HTTP.set_header(req, 'Content-Type', 'text/xml');
 
/*Establecemos el SOAPAction a invocar: */
    UTL_HTTP.set_header(req, 'SOAPAction', '"rpc/http://servidor/ConsultaClientes"');
 
/*Indicamos en el header el tamańo del mensaje enviado: */
    UTL_HTTP.set_header(req, 'Content-Length', LENGTH(xml));
 
/*Escribimos el body del request */
    UTL_HTTP.write_text(req, xml);
 
/*Obtenemos la respuesta */
    resp := UTL_HTTP.get_response(req);
 
/*Cargamos en la variable respVal la devolución del servidor */
    UTL_HTTP.read_text(resp, respVal);
 
/*Finalizamos la conexión HTTP */
    UTL_HTTP.end_response(resp);
 
EXCEPTION
    WHEN UTL_HTTP.end_of_body THEN
      UTL_HTTP.end_response(resp);
END;
 
/

Conclusion

De esta manera rápida pudimos invocar un Web Service remoto utilizando PL/SQL, a partir de allí es posible convertir lo recibido en la variable respVal a un XMLTYPE para un mejor manejo.

Espero que les haya servido!!

Esta entrada fue publicada en Oracle y etiquetada , . Guarda el enlace permanente.

53 respuestas a Invocar Web Services desde PL/SQL en Oracle

  1. Adsoa dijo:

    Gran código que me viene de perlas. Muchas gracias, voy a probarlo ahora mismo.

  2. guido dijo:

    buenas, muy bueno el aporte. Yo necesito bajar un archivo (es un certificado de banco) con un webservice.. como podria hacer? gracias

  3. HLE dijo:

    Gracias por el aporte, este ejemplo funciona muy bien, sin embargo tengo que utilizarlo para consumir un web service donde los parametros (que son bastantes) vienen conformados en un documento xml con varios niveles de anidamiento, si mando un simple string con un valor me funciona pero si le envio el xml complejo el servidor me devuelve un “BAD REQUEST”(ya comprobe que el XML este bien formado). Probe hacer el consumo en visual basic y en menos de 15 minutos ya me estaba funcionando pero necesito hacerlo desde la base de datos. Alguna idea…

  4. Omar dijo:

    Hola, gracias por el codigo. Al generar el request al servidor destino aparece error ORA-12535 TNS:Operation timed out.

  5. Juan Carlos dijo:

    Debo hacer el consumo de un web service que, la estructura del xml tiene un nivel de complejidad mas alto que este ejemplo, por ejemplo tiene que ir un tipo de dato lista o tabla y de igual el xml que responde este web service es complejo y también trae un tipo de dato lista o tabla, como hago que se genere este xml que voy a enviar y como hago para luego recuperar, especialmente ese tipo de dato lista o tabla.

    Gracias por su ayuda.

  6. Rocio dijo:

    Hola gracias por la información publicada, ya he implementado el consumo desde BD de un WS pero al tratar de consumir con valores que tienen tildes me sale un error.

    Gracias por tu ayuda,

  7. Roberto dijo:

    Hola Sebas, tengo una pregunta ojala puedas ayudarme
    Lo de invocar un ws funciona perfecto. Ahora estoy trabajando con servicios wcf a los cuales es posible configurar el binding o comportamiento entre aquellos que se conectan.
    Entiendo que el cliente debe enviar su configuracion de binding el servicio para por ejemplo acordar con tiempo de respuesta, timeout, timeclosed, etc.
    Es este binding que no sé donde configurarlo en la libreria utl_http. Deseo indicar al servicio que me espere por mas de 60 segudos porque me vota por timeout. Dentro del packege controlo esta excepcion pero quiero que no se produzca.

    Eso..espero tus comentarios.

    Roberto

  8. Mario Garcia dijo:

    Hola gusto de saludarte me podrias ayucar en consumir un servicio realizado en php, al seguir el ejemplo y sustituir por el que tengo me da el error del buffer porque lo que me devuelve es grandisimo, en espera de tu comentario muchas gracias

    • Sebas dijo:

      Mario, deberías usar un CLOB temporal e ir leyendo de a 32767 bytes. Por cada “readtext” haces un append al CLOB creado temporalmente.

      Fijate que en esta página (en inglés) tenes una posible solución.

      Saludos!!

  9. Mario Daniel Alexander dijo:

    Hola buena tarde gusto de saludarte, con un favor fijate que tengo un problema en el envio del mensaje el web service lo tengo en realizado en php, en espera te tu comentario muchas gracias

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos necesarios están marcados *

*

Puedes usar las siguientes etiquetas y atributos HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>