Consulta

93 views
Skip to first unread message

martin bonansea

unread,
Oct 6, 2023, 6:54:23 AM10/6/23
to acti...@googlegroups.com
Buenos días colegas, estoy trabado en este paso
Tengo el siguiente endpoint en el que mediante un post me envían el json y no logro poder parsear mediante las funciones de AVFP.
Mi deseo es pasar el json recibido a un cursor u objeto.
(Dejo el código comentado de mis pruebas)

PROCEDURE quetipo

This.OpenData()
oResponse.ContentType = "application/json;charset=utf-8"
lnByteCount = oRequest.oRequest.TotalBytes
lcStr = oRequest.oRequest.BinaryRead(lnBytecount)
*!* RETURN TRANSFORM(lcStr)
*!* lmartin = oAVFP.parseCursor(lcStr , pcAlias, pnDataSessionID)
*!* lmartin = oAVFP.parseCursor(pcJSONString, pcAlias, pnDataSessionID)
*!* RETURN lmartin  
lcStr = Strconv(lcStr,9)
lcStr2 = TRANSFORM(lcStr)
*!* RETURN TRANSFORM(lcStr2) &&aca devuelve json ok
lcCursor=oAVFP.oJson.parseCursor(lcStr2, "miCursorJson", 0)
*!* RETURN TRANSFORM(oAVFP.oJson.version)
*AVEvalJSON(lcStr2)
*!* SELECT miCursorJson
*!* COPY TO c:\temp\miCursorJson.dbf

*!* oObject = AVEvalJSON(lcStr2)
*!* lcCursor = AVEvalJSON(lcStr2)
RETURN (oAVFP.oJson.lastError)
*!* RETURN AVTojSon(oObject) &&asi sabemos como viene el json.
*!* RETURN "Su usuarios es " + ALLTRIM(oObject.usuario) + " y su password es " + ALLTRIM(oObject.contra)

*RETURN this.verb && TRANSFORM(lcStr)&&oObject

Endproc

Saludos cordiales.

Victor Espina

unread,
Oct 6, 2023, 4:26:39 PM10/6/23
to ActiveVFP
Lamentablemente no he trabajado mucho con la version std de ActiveVFP... pero la version extendida y la clase avfpRESTController, no necesitas hacer nada de eso;  cuando el request contiene el header Content-Type: application/json, la data es convertida automaticamente a un objeto JSON y puedes acceder a el con la propiedad THIS.DATA.

Si no estas trabajando con la version extendida, te recomiendo AMPLIAMENTE que la instales.  Puedes descargarla desde aqui:

Extraes el contenido y lo copias encima de tu instalacion normal de ActiveVFP 6 (recuerda respaldar primero y detener el IIS para que puedas reemplazar el activevfp.dll).  En la documentacion se explica como crear y usar los controladores REST o si tienes alguna duda, por aca te puedo ayudar.

Saludos

Victor Espina

martin bonansea

unread,
Oct 7, 2023, 8:45:29 AM10/7/23
to acti...@googlegroups.com
Hola Victor, mil gracias. Efectivamente estoy utilizando la versión extendida, pero evidentemente la documentación que tengo será distinta a la que mencionas porque solo poseo un archivo de referencia .txt ?

Entonces para resumir:
Al endpoint de mi apirest cuando recibo un json mediante el verbo post accedo al json mediante el valor en la propiedad This.Data ?

Saludos cordiales y gracias :)


--
Has recibido este mensaje porque estás suscrito al grupo "ActiveVFP" de Grupos de Google.
Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a activevfp+...@googlegroups.com.
Para ver esta conversación en el sitio web, visita https://groups.google.com/d/msgid/activevfp/406c4f17-46be-411b-9e8e-0ecda81ef4bcn%40googlegroups.com.

Victor Espina

unread,
Oct 8, 2023, 9:41:31 PM10/8/23
to ActiveVFP
Es correcto, siempre y cuando estas trabajando con un controlador REST, de los que van en PRG/REST.

Victor Espina

martin bonansea

unread,
Oct 10, 2023, 8:55:46 AM10/10/23
to acti...@googlegroups.com
Hola Victor, buenos días, gracias por tus respuestas.
Efectivamente no estaba utilizando la versión extendida de AVFP. Por este motivo no estaba pudiendo acceder a la información recibida en el endpoint.
Luego para las pruebas internas tuve que pelear un poco con la confección de json utilizando TEXT...ENDTEXT ya que al enviarlo al endpoint y luego de intentar leerlo recibía la respuesta de que estaba mal confeccionado. Así que opté por armar el json a enviar para test interno desde vfp con el seteo TEXT...ENDTEXT NOSHOW PRETEXT 7 sin tabular ni saltos de líneas.

Por si a alguien le sirve dejo el código que utilicé para hacer el POST al endpoint que tiene corriendo ACTIVEVFP en modo APIREST

codigo para hacer enviar datos a un endpoint :
LOCAL oHTTP, cURL, cResponse, cJsonData
SET SAFETY off
cJsonData = ""
TEXT TO cJsonData NOSHOW PRETEXT 7
{"number": "23232asadd","items": [{"product_id": "042","quantity_prepared": 5},{"product_id": "043","quantity_prepared": 12}],"observations": "Entregar solo viernes. Preparado 08-02", "bultos": 10, "depot_id": "001"}
ENDTEXT

oHTTP = CREATEOBJECT("Msxml2.ServerXMLHTTP.6.0") &&Crear el objeto  
cURL = "http://net14/apirest/obtenerPedidos" &&endpoint
oHTTP.open("POST", cURL, .F.) &&definir el verbo, direccion, síncronica o asíncronica .F. indica que la solicitud es asíncrona
oHTTP.setRequestHeader("Content-Type", "application/json") &&si se envia un json se debe indicar en la cabecera.
oHTTP.send(cJsonData) &&ejecutar el llamado pero enviando un json
IF oHTTP.status = 200  && Verificar si la solicitud fue exitosa (código de estado 200)
        cResponse = oHTTP.responseText
        ? cResponse  && Muestra la respuesta en la ventana de resultados
    ELSE
        ? "Error en la solicitud HTTP. Código de estado: " + TRANSFORM(oHTTP.status)
    ENDIF
cTempFile = SYS(2023) + ".txt"  && Nombre único para el archivo temporal

cJsonResponse = oHTTP.responseText  && Se asume que oHTTP es el objeto ServerXMLHTTP utilizado para la consulta GET

STRTOFILE(cJsonResponse, cTempFile)  && Guardar la respuesta en el archivo temporal

cJsonData = FILETOSTR(cTempFile)  && Leer el contenido del archivo en una variable de cadena
MODIFY COMMAND (cTempFile)
RELEASE oHTTP
RETURN


codigo del endpoint para leer la información recibida:

CASE UPPER(lctipo) = 'POST'

DO LocFile("C:\webservice\prg\JSONFox\JSONFox", "app")   &&cargar el objeto en _screen.json

IF TYPE('_screen.json') = 'U'

   RETURN ('No fue posible crear el objecto _screen.json')

ENDIF

* Deserialize and Indent
lcStrj1 = AVToJSON(This.data)
loObj = _Screen.Json.Parse(lcStrj1)
*Aqui accedemos a los valores fijos
lcNumber = TRANSFORM(loObj.number)
lcObservations = TRANSFORM(loObj.observations)
lcBultos = TRANSFORM(loObj.bultos)
lcDepot = TRANSFORM(loObj.depot_id)

* Make a copy of the internal array from obj.data
Acopy(loObj.items, aListadoArray)

* Now pass the aEmployeeList by reference with '@'
lcJsonArray = _Screen.Json.Encode(@aListadoArray)

* Convert the JSONArray into VFP CURSOR **(this is cool)**
lcCursor = 'obtenerPedidos_POST_' + SYS(2015)
lcDbfNew = 'C:\webservice\prg\rest\controllers\' + lcCursor + '.dbf' &&FULLPATH("") + lcCursor + '.dbf'

_Screen.Json.JSONToCursor(lcJsonArray, lcCursor)

SELECT  * FROM (lcCursor) INTO CURSOR _recibido

SELECT (lcCursor)
COPY TO (lcDbfNew)

*!* SELECT _recibido
SCAN
lccodigo = EVALUATE(FIELD(1)) &&_recibido.product_id
lncantidad = EVALUATE(FIELD(2)) &&_recibido.quantity_prepared

* lncantidad = EVAL(fields2)
IF !used('ob_pedidos')
SELECT 0
USE ob_pedidos
ENDIF
SELECT ob_pedidos
APPEND BLANK
replace numero   WITH VAL(lcNumber)
replace observa  WITH lcObservations
replace bultos   WITH VAL(lcBultos)
replace deposito WITH lcDepot
replace codigo   WITH lccodigo
replace cantidad WITH lncantidad
SELECT (lcCursor)

ENDSCAN

IF used('ob_pedidos')
USE IN ob_pedidos
ENDIF



saludos cordiales


Victor Espina

unread,
Oct 10, 2023, 2:05:24 PM10/10/23
to ActiveVFP
A veces usar el software adecuado te evita mucho trabajo.  Para consumir tu webservice facilmente, podrias usar mi libreria JSON y el codigo te quedaria asi:

DO JSON   && AL INICIO DEL PROGRAMA PRINCIPAL
...
LOCAL cJsonData
SET SAFETY off

TEXT TO cJsonData NOSHOW PRETEXT 7
{"number": "23232asadd","items": [{"product_id": "042","quantity_prepared": 5},{"product_id": "043","quantity_prepared": 12}],"observations": "Entregar solo viernes. Preparado 08-02", "bultos": 10, "depot_id": "001"}
ENDTEXT

LOCAL oResp,cUrl,cHeaders
cHeaders = "Content-Type: application/json"
oResp = JSON.httpPOST(cUrl, cJsonData, cHeaders)
IF oResp.hasError
  ?oResp.errorMsg
  RETURN
END
IF oResp.statusCode <> 200
   ? "Error en la solicitud HTTP. Código de estado: " + TRANSFORM(oResp.statusCode)
   RETURN
ENDIF

STRTOFILE(oResp.raw, cTempFile)  && Guardar la respuesta en el archivo temporal

** oResp.JSON contiene el string JSON recibido ya parseado en forma de un objeto.


cJsonData = FILETOSTR(cTempFile)  && Leer el contenido del archivo en una variable de cadena
MODIFY COMMAND (cTempFile)
RELEASE oHTTP
RETURN



Usando la version extendida de ActiveVFP,  puedes crear facilmente tu controller de esta forma:

* PRG/REST/obtenerpedidos.prg

DEFINE CLASE obtenerPedidos AS avfpRESTController

    * POST /obtenerPedidos
    PROCEDURE postItem

        *Aqui accedemos a los valores fijos
        lcNumber = TRANSFORM(THIS.data.number)
        lcObservations = TRANSFORM(THIS.data.observations)
        lcBultos = TRANSFORM(THIS.data.bultos)
        lcDepot = TRANSFORM(THIS.data.depot_id)


        * Convert the JSONArray into VFP CURSOR **(this is cool)**
        lcCursor = 'obtenerPedidos_POST_' + SYS(2015)
        lcDbfNew = 'C:\webservice\prg\rest\controllers\' + lcCursor + '.dbf' &&FULLPATH("") + lcCursor + '.dbf'
        AVArrayToCursor(THIS.Data.Items, lcCursor, SET("DATASESSION"))
        RETURN

ENDDEFINE



Saludos

Victor Espina

martin bonansea

unread,
Oct 10, 2023, 2:24:08 PM10/10/23
to acti...@googlegroups.com
Excelente Victor, así también queda como registro el código para consultar/resolver dudas futuras que surjan a otros colegas :-)
Honestamente debía resolver y no quería tener que enviarte correo tras correo molestando con consultas.
Mi principal piedra en el camino fue que el json no llegaba de manera correcta al endpoint, pero al verificar con editores de json en línea todos daban resultado correcto y me hacían perder.

Nuevamente muchas gracias por tu tiempo.
Saludos cordiales.



Reply all
Reply to author
Forward
0 new messages