22 de noviembre de 2011

Consumir cualquier Web Service con Visual FoxPro

Este artículo es para mostrarles como podemos invocar cualquier Web Services desde Visual FoxPro.

Primero quisiera comentar, que NO soy un experto en ésto de los WEB services, pero he tomado algo de experiencia en el uso de los mismos. En éste artículo trataré de explicarlo con palabras simples.

Es importante leer al respecto, siempre es sencillo encontrar información en Wikipedia.

Vamos comenzando por la lógica de "ejecución" de un web service:

1. Creamos la petición de ejecución de una función del Web Service, ésto se llama XML REQUEST.
2. Enviamos el REQUEST al web service, la cual es una URL que termina con wsdl.
3. Obtenemos un XML RESPONSE, que es el resultado de haber invocado la función específica del WS.

Vamos por partes:

Para saber como es el REQUEST, utilizo una aplicación Open Source llamada soapUI, la cual pueden descargar desde: http://www.soapui.org/

Lo descargamos, al abrir el soapUI vemos ésto:

Image Hosted by ImageShack.us

La URL del web service es: http://www.webservicex.net/globalweather.asmx?WSDL

Image Hosted by ImageShack.us

Con ésto, soapUI interperta las funciones que existen en ése WebService, y nos crea un ejemplo de REQUEST por cada una de ellas, en éste caso observaremos como el REQUEST de la función GetWeather:

Image Hosted by ImageShack.us

Hasta aquí, tenemos cubierto el paso 1 de la ejecución de un Web Service, el dos es simple.. damos clic en el botón de "PLAY" y se cumple el segundo paso, al mismo tiempo que obtenemos el XML RESPONSE:



Image Hosted by ImageShack.us

Bien, como hacemos ésto con FoxPRO:

Al ya conocer la estructura del XML Request, pues lo creamos con FoxPRO, usen el método que a ustedes les parezca mejor, en lo personal me agrada la utileria Free de Chilkat, pero para el ejemplo crearé el Request con TEXT.. ENDTEXT

He creado una clase para consumir WS, en ella muestro el ejemplo anterior en código, está comentada por lo que creo no es necesario hablar más al respecto.

Va el código:

oWS = CREATEOBJECT( "VFP_WebService","http://www.webservicex.net/globalweather.asmx?WSDL") 
lcRespuesta = oWS.GetWeather("Torreon, Coah.","Mexico")
IF oWS.iStatus != 0
 MESSAGEBOX(oWS.sError,16,"Error al ejecutar WS")
ELSE
 MESSAGEBOX(lcRespuesta,64,"EjecutandoWS desde VFP - PortalFOX")
ENDIF  

DEFINE CLASS VFP_WebService AS CUSTOM

 * --- Definimos las propiedades ---
 sError = ""
 iStatus = 0 
 sURL_WS = ""

 * --- Definimos la función del WebService ---
 FUNCTION GetWeather (tcCiudad, tcPais)

  * --- Paso 1. Creo el XML Request ---
  sXMLRequest = this.CreaRequest(tcCiudad, tcPais)
    
  pXMLResponse = ADDBS(SYS(2023)) + SYS(2015) + [.xml]
  
  * --- Paso 2. Ejecuto el WS | Paso 3. Obtengo el Response ---
  this.iStatus =  this.EjecutaWS( this.sURL_WS, sXMLRequest , pXMLResponse )

  IF this.iStatus != 0  && Ocurrió un error el cual está especificado en sError.
   RETURN ""
  ENDIF 

  sXMLResponse = FILETOSTR(pXMLResponse)
  * --- Parseamos el XML Response ---
  * --- Para el ejemplo está así, manejando texto, ustedes deben manejar XML (falta de tiempo, perdón) ---

  sRespuestaWS = "Location:"+CHR(9)+ STREXTRACT(sXMLResponse,'<Location>','</Location>')+CHR(13)+CHR(10)
  sRespuestaWS = sRespuestaWS +"Time:"+CHR(9)+ STREXTRACT(sXMLResponse,'<Time>','</Time>')+CHR(13)+CHR(10)
  sRespuestaWS = sRespuestaWS +"Wind:"+CHR(9)+ STREXTRACT(sXMLResponse,'<Wind>','</Wind>')+CHR(13)+CHR(10)
  sRespuestaWS = sRespuestaWS +"Visibility:"+CHR(9)+ STREXTRACT(sXMLResponse,'<Visibility>','</Visibility>')+CHR(13)+CHR(10)
  sRespuestaWS = sRespuestaWS +"SkyConditions:"+CHR(9)+ STREXTRACT(sXMLResponse,'<SkyConditions>','</SkyConditions>')+CHR(13)+CHR(10)
  sRespuestaWS = sRespuestaWS +"Temperature:"+CHR(9)+ STREXTRACT(sXMLResponse,'<Temperature>','</Temperature>')+CHR(13)+CHR(10)
  sRespuestaWS = sRespuestaWS +"DewPoint:"+CHR(9)+ STREXTRACT(sXMLResponse,'<DewPoint>','</DewPoint>')+CHR(13)+CHR(10)
  sRespuestaWS = sRespuestaWS +"RelativeHumidity:"+CHR(9)+ STREXTRACT(sXMLResponse,'<RelativeHumidity>','</RelativeHumidity>')+CHR(13)+CHR(10)
  sRespuestaWS = sRespuestaWS +"Pressure:"+CHR(9)+ STREXTRACT(sXMLResponse,'<Pressure>','</Pressure>')
  
  this.borraArchivo(pXMLResponse)
  
  RETURN sRespuestaWS
 
 ENDFUNC 
 
 *---------------------------------------------------
 FUNCTION EjecutaWS(pURL_WSDL, pFileRequest , pFileResponse )
 *---------------------------------------------------
    TRY 
     oHTTP = CREATEOBJECT('Msxml2.ServerXMLHTTP.6.0')
     oHTTP.OPEN("POST", pURL_WSDL, .F.)
     oHTTP.setRequestHeader("User-Agent", "EjecutandoWS desde VFP - PortalFOX")
     oHTTP.setRequestHeader("Content-Type", "text/xml;charset=utf-8")
     oHTTP.SEND(pFileRequest)
    CATCH TO loErr
      this.sError = "Error: " + TRANSFORM(loErr.ErrorNo) +  " Mensaje: " + loErr.Message
      this.iStatus = -1      
    ENDTRY 
    IF this.iStatus != 0
     RETURN -1
    ENDIF 
     * --- Si el status es diferente a 200, ocurrió algún error de conectividad con el WS ---
     IF oHTTP.STATUS = 200
         RespuestaWS = oHTTP.responseText
      * --- Se genera el XML del response | Este es el paso 3!! ---
      STRTOFILE(STRCONV(RespuestaWS,9),pXMLResponse)
      this.iStatus = 0
      this.sError = ""
      RETURN 0
     ELSE
         this.sError = "Error: No se logró la conexión con el Web Service."
         this.iStatus = -1
   RETURN -1
     ENDIF
 ENDFUNC 
 *---------------------------------------------------

 *---------------------------------------------------
 FUNCTION CreaRequest(tcCiudad, tcPais)
 *---------------------------------------------------
TEXT TO sXMLRequest TEXTMERGE NOSHOW 
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://www.webserviceX.NET">
   <soapenv:Header/>
   <soapenv:Body>
      <web:GetWeather>
         <web:CityName><<tcCiudad>></web:CityName>
         <web:CountryName><<tcPais>></web:CountryName>
      </web:GetWeather>
   </soapenv:Body>
</soapenv:Envelope>
ENDTEXT 
  RETURN sXMLRequest
 ENDFUNC  
 *---------------------------------------------------

 *---------------------------------------------------
 FUNCTION BorraArchivo(pFile)
 *---------------------------------------------------
  IF FILE(pFile)
   DELETE FILE (pFile)
  ENDIF 
 ENDFUNC 
 *---------------------------------------------------

 *---------------------------------------------------
 * Evento constructor
 PROCEDURE Init
 *---------------------------------------------------
  LPARAMETERS tcURLWS
        this.sURL_WS = tcURLWS
        this.iStatus = 0
        this.sError = ""
 ENDPROC
 *---------------------------------------------------

ENDDEFINE 

Pueden descargar el código desde aquí.

Suerte con sus Web Services!!

Baltazar Moreno
http://disxii.com
VFP9SP2 - Win7
Guadalajara, Jalisco, México

4 comentarios :

  1. He actualizado éste artículo en:

    https://bmorenoj.blogspot.com/2011/11/consumir-cualquier-web-service-con.html

    ¡Saludos!

    ResponderBorrar
  2. Hola Baltazar, una pregunta:
    ¿utilizando el código que pones de ejemplo cómo puedo indicar firma electrónica?...

    Gracias

    ResponderBorrar
  3. Hola Baltazar.

    Eres un genio amigo, no sabes como me sirvió tú código, saludos!

    ResponderBorrar

Los comentarios son moderados, por lo que pueden demorar varias horas para su publicación.