¿Cómo instalar y utilizar el API cliente de Python?

¿Cómo instalar y utilizar el API cliente de Python?

 

Última versión 1.4.15

El 8 de abril de 2025 se lanzó la versión 1.4.15 de la librería cliente de Python en PyPi:

https://pypi.org/project/onesaitplatform-client-services/#history

 

En este tutorial se muestra la instalación del cliente REST de Python para OnesaitPlatform, además de algunos casos de uso.

Introducción

Esta librería cliente de la plataforma contiene varias clases que implementan las funcionalidades de diferentes clientes de la plataforma:

  • Cliente Iot-Broker: Queries e inserciones de datos de ontologías/entidades.

  • Cliente Api-Manager: Gestión de APIs REST y llamadas.

  • Cliente File-Manager: Subida y bajada de archivos binarios.

  • Cliente MQTT: Queries e inserciones de datos de ontologías mediante protocolo MQTT.

Con estos clientes se establece una comunicación sencilla con la plataforma desde cualquier entorno Python.

Estas mismas funcionalidades se establecen también desde el Digital Broker o Control Panel, a través de sus distintos paths.

Instalación de la librería desde pypi:

La forma más sencilla de instalar la librería es mediante el repositorio pypi y el uso de pip. Para instalarlo, basta con ejecutar el comando:

>> pip install onesaitplatform-client-services

Se recomienda utilizar el flag de upgrade para actualizar las dependencias en caso de que ya estén instaladas (recomendado para todas las instalaciones).

>> pip install --upgrade onesaitplatform-client-services

Ejemplos de uso del cliente

Se pueden encontrar notebooks de ejemplos en la carpeta /examples/*.ipynb de instalación de la librería.

NOTA: Es muy importante que por cada cliente DigitalClient, siempre se haga un join() al principio para abrir la conexión y un leave() al final para cerrarla.

Digital Client

Create Client

Para crear un Digital Client, se requiere una configuración de conexión, a continuación se explican la forma de establecer los parámetros adecuadamente.

Si el cliente se conecta desde dentro de la red de la plataforma (desde notebooks de plataforma o microservicios internos) la configuración para conectar con el Digital Broker (Iot Broker) es la siguiente:

%python from onesaitplatform.iotbroker import DigitalClient HOST = "iotbrokerservice" PORT = 19000 IOT_CLIENT = "<digital client name>" IOT_CLIENT_TOKEN = "<digital client token>" PROTOCOL = "http" AVOID_SLL_CERTIFICATE = False client = DigitalClient(host=HOST, port=PORT, iot_client=IOT_CLIENT, iot_client_token=IOT_CLIENT_TOKEN) client.protocol = PROTOCOL client.avoid_ssl_certificate = AVOID_SSL_CERTIFICATE

En cambio, si el cliente se utiliza desde una red externa de plataforma (pc local y otras ubicaciones en la red), la configuración es la siguiente:

El parámetro está redirigido automáticamente por lo que no es necesario, pero se puede establecer PORT = 443 (puerto https por defecto).

El parámetro PROTOCOL está puesto por defecto a "https", pero se puede establecer a PROTOCOL = "https".

El parámetro AVOID_SSL_CERTIFICATE está puesto por defecto a True, pero se puede establecer a AVOID_SSL_CERTIFICATE = True.

import json from onesaitplatform.iotbroker import DigitalClient HOST = "development.onesaitplatform.com" IOT_CLIENT = "RestaurantTestClient" IOT_CLIENT_TOKEN = "bd3c00d85a784392bdd87830244d0b7e" client = DigitalClient( host=HOST, iot_client=IOT_CLIENT, iot_client_token=IOT_CLIENT_TOKEN) client.avoid_ssl_certificate = True

 

Join / Leave

Para iniciar una conexión, se requiere de hacer un join() o connect(), que utiliza las credenciales iot_client y iot_client_token. Al finalizar se debe usar siempre leave() o disconnect().

client.join() client.leave()

 

Query

Los formatos de query admitidos son "SQL" y "NATIVE" para sintaxis SQL y MongoDB respectivamente.

query = "select * from Restaurants limit 3" ok_query, results_query = client.query(ontology="Restaurants", query=query, query_type="SQL") query = "db.Restaurants.find().limit(3)" ok_query, results_query = client.query(ontology="Restaurants", query=query, query_type="NATIVE")

 

Query batch

Esta query realiza sucesivas peticiones de menor tamaño, óptima para cuando se quieren pedir muchos datos. Se construye con query + "offset N limit batch_size" o query + .skip(N)-limit(batch_size)" para SQL y MongoDB respectivamente.

query_batch = "select c from Restaurants as c" ok_query, results_query = client.query_batch(ontology="Restaurants", query=query_batch, query_type="SQL", batch_size=50) query_batch = "db.Restaurants.find()" ok_query, results_query = client.query_batch(ontology="Restaurants", query=query_batch, query_type="NATIVE", batch_size=50)

 

Queries sobre RealTimeDB mapeadas a fichero

Una entidad sobre la Real Time DB puede almacenar una gran cantidad de información, dependiendo del propósito de dicha entidad. Por ejemplo, supongamos una entidad que recibe eventos de una red compuesta por cientos de dispositivos.

Para evitar problemas de colapso de memoria con consultas que no aplican criterios de límite sobre entidades con un gran número de registros, se configura a nivel de instalación el número máximo de registros que devolverán dichas consultas. Por ejemplo, en una instalación típica con los valores por defecto, la siguiente sentencia:

select * from MiEntidad;

Devolverá como mucho 2000 registros, independientemente de si la entidad tiene millones de registros.

Para facilitar el tratamiento de este tipo de sentencias en los proyectos, se incluye una función para la ejecución de sentencias sin cláusulas de límite o con límites muy altos, cuyo resultado se volca en un archivo que está a disposición de los usuarios. En el Digital Broker, sería la correspondiente al path: /rest/ontology/{ontology}/file.

Se utilizará la función query_file(), que requiere cuatro parámetros:

  • ontology : entidad sobre la que se realiza la operación.

  • query: sentencia a ejecutar.

  • queryType: tipo de query (SQL o NATIVA).

  • responseType: destino del fichero a generar, puede ser de tres tipos:

    • DISK: el fichero se generará en un directorio configurable por instalación dentro del contenedor del Semantic Inf Broker, que se podrá mapear a un volumen compartido para que el fichero quede disponible para otros módulos, como por ejemplo Dataflow, Notebooks….

    • S3_MINIO: el fichero se genera en el bucket de MinIO del propietario del Digital Client.

    • URL: el fichero se genera en un directorio mapeado en una carpeta compartida en el loadbalancer de plataforma, lo que permite descargarlo mediante una URL.

query = "SELECT c.ejemplo_smrg AS ejemplo_smrg FROM ejemplo_smrg AS c" ok_query, result_query = client.query_file(ontology="ejemplo_smrg", query=query, query_type="SQL", responseType="S3_MINIO") print(f"ok_query_file: {ok_query}") print(f"result_query_file: {result_query}")

Esto nos devolverá un JSON con la información donde localizar el fichero, dependiendo del responseType:

  • DISK:

image-20250212-085941.png
  • URL:

image-20250212-090031.png
  • S3_MINIO:

image-20250212-085818.png

Utilizando el S3_MINIO el fichero estará accesible en el bucket del usuario.

image-20250212-112817.png

La respuesta del servicio es asíncrona, ya que, en consultas sobre entidades grandes, el tiempo de consulta puede ser elevado. Para ello, en el JSON de respuesta se incluye un identificador que permite consultar el estado de ejecución de la sentencia, el cual puede estar:

  • IN_PROGRESS: la sentencia se está ejecutando.

  • FINISHED: la sentencia ha terminado y su resultado se ha volcado por completo al fichero.

La operación que permite consultar el estado está disponible en el Digital Broker en el path /rest/ontology/file/{queryId}/status, en Python se haría de la siguiente manera:

Necesitamos tener acceso al ‘query_id’ del archivo cuyo estado queremos consultar. Este ‘query_id’ se puede obtener directamente del JSON que nos devolvió la solicitud o, si es un archivo creado previamente, introducirlo manualmente:

query_id = result_query['queryId'] query_id = "9c699b1c-3fb1-4075-a60a-fd982fbd39b7"

A continuación, se llamará a la función que nos devolverá el estado. Si el estado es 'IN_PROGRESS', se esperarán 5 segundos correspondientes al 'timesleep' antes de realizar nuevamente la solicitud para verificar si ya ha cambiado a 'FINISHED'. La función tendrá un timeout preestablecido de 60 segundos para esperar a que cambie a 'FINISHED', pero, al igual que el 'timesleep', son parámetros que se pueden modificar.

status_query = client.query_file_status(queryId=query_id) status_query = client.query_file_status(queryId=query_id, timeout=10, sleep_time=1)

 

Insert

new_restaurant = { 'Restaurant': { 'address': { 'building': '2780', 'coord': [-73.98241999999999, 40.579505], 'street': 'Stillwell Avenue', 'zipcode': '11224' }, 'borough': 'Brooklyn', 'cuisine': 'American', 'grades': [ {'date': '2014-06-10T00:00:00Z', 'grade': 'A', 'score': 5} ], 'name': 'Riviera Caterer 18', 'restaurant_id': '40356118' } } new_restaurant_str = json.dumps(new_restaurant) new_restaurants = [new_restaurant] ok_insert, res_insert = client.insert("Restaurants", new_restaurants)

 

Api-Manager Client

Create Client

Para crear la instancia del Api-Manager, se necesita el Host y el Token del usuario cuya información queremos obtener.

from onesaitplatform.apimanager import ApiManagerClient HOST = "www.onesaitplatform.com" TOKEN = "b32522cd73e84ddda519f1dff9627f40" client = ApiManagerClient(host=HOST) client.setToken(TOKEN)

 

Find APIs

Al utilizar el método find(), podemos localizar una API específica, el cual devuelve la información de la API en formato JSON, donde se pueden observar sus endpoints, entre otros detalles. Para ello, es necesario pasar dos parámetros:

  • identification: que corresponde con el nombre de la API.

  • version: que corresponde a la versión de la API.

ok_find, res_find = client.find(identification=apiManger_test, version=1)

 

List APIs

Este método lista todas las APIs del usuario y las públicas si no se pasa el usuario, y si se pasa el usuario, solo se listan las APIs del usuario.

ok_list, res_list = client.list() ok_list, res_list = client.list(user="smartinroldang")

 

Make API request

Con este método puedes realizar llamadas a la API que desees, especificando:

  • method: el tipo de método HTTP.

  • name: la query que deseas realizar.

  • version: la versión de la API.

  • body: la información necesaria para la llamada, si es requerida.

ok_request, res_request = client.request(method="GET", name="RestaurantsAPI/67893fd43a5b302736e9f37a", version=1, body=None)

 

Create API

Podemos crear una API pasándole un objeto JSON con este formato.

json_obj = { "id": "b7b40435-ea1b-11ef-93e4-0240aebb2666", "identification": "apiManger_smrg", "version": 1, "type": "INTERNAL_ONTOLOGY", "isPublic": True, "category": "ALL", "externalApi": False, "ontologyId": "prueba_smrg", "apiLimit":0, "apiCacheTimeout": 0, "endpoint": "https://lab.onesaitplatform.com/api-manager/server/api/v1/apiManger_ smrg ", "endpointExt": "", "description": "test codigo python", "metainf": "test, python", "imageType": None, "status": "CREATED", "creationDate": "Thu Feb 14 15:03:43 GMT 2025", "userId": "smartinroldang", "swaggerJson": "", "operations": [ { "identification": "apiManger_ smrg _GET", "id": "b7b965b3-ea1b-11ef-93e4-0240aebb2666", "description": "query all", "operation": "GET", "endpoint": None, "path": "/{id}", "queryParams": [ { "name": "id", "dataType": "STRING", "description": "", "value": None, "headerType": "PATH", "condition": None } ], "postProcess": None } ], "authentications": [], "publishInGravitee": False, "graviteeJWTPlan": False, "graviteeId": None, "jwtClientId": None }

Luego, podemos llamar al método create() con el parámetro json_obj, y si todo sale como se espera, habremos creado una nueva API.

ok_create, res_create = client.create(json_obj=json_obj)

 

Delete API

Otro de los métodos que realiza esta librería es eliminar APIs. Para ello, debemos pasarle a la función dos parametros:

  • indentification: que corresponde con el nombre de la API.

  • version: que corresponde a la versión de la API.

ok_delete, res_delete = client.delete(identification="prueba_smrg", version="v1")

 

File-Manager Client

Create Client

Cuando se crea el cliente, se puede utilizar el Bearer token (APIs) o el user token (My APIs>user tokens)

import json from onesaitplatform.files import FileManager HOST = "www.lab.onesaitplatform.com" USER_TOKEN = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwcmluY2lwYWwiOiJianJhbWlyZXoiLCJjbGllbnRJZCI6Im9uZXNhaXRwbGF0Zm9ybSIsInVzZXJfbmFtZSI6ImJqcmFtaXJleiIsInNjb3BlIjpbIm9wZW5pZCJdLCJuYW1lIjoiYmpyYW1pcmV6IiwiZXhwIjoxNjE3ODI2NjkzLCJncmFudFR5cGUiOiJwYXNzd29yZCIsInBhcmFtZXRlcnMiOnsidmVydGljYWwiOm51bGwsImdyYW50X3R5cGUiOiJwYXNzd29yZCIsInVzZXJuYW1lIjoiYmpyYW1pcmV6In0sImF1dGhvcml0aWVzIjpbIlJPTEVfREFUQVNDSUVOVElTVCJdLCJqdGkiOiJmNGM2NDUzZC0xYTEyLTRkMGUtYTVlNy05ZmNlMDY4OTY1NDYiLCJjbGllbnRfaWQiOiJvbmVzYWl0cGxhdGZvcm0ifQ.Nz5cDvMjh361z4r6MMD2jUOpYSmUKVLkMThHDK0sg6o" file_manager = FileManager(host=HOST, user_token=USER_TOKEN) file_manager.protocol = "https"

 

Upload file

uploaded, info = file_manager.upload_file("dummy_file.txt", "./dummy_file.txt")

 

Download file

downloaded, info = file_manager.download_file("5ccc4b34f2df81000b8f49a")

 

Download file MinIO

Una vez creado el archivo con S3_MINIO, vemos cómo recuperarlo desde Python y cómo generar un dataframe de Pandas a partir de él.
Para recuperar el archivo, primero creamos una instancia de la clase FileManager, por tanto, importamos dicha librería. Además, para trabajar con el dataframe, importamos la librería pandas. Comencemos por hacer estas importaciones:

from onesaitplatform.files import FileManager import pandas as pd

A continuación, realizamos la instancia de FileManager como se explicó anteriormente. Una vez creada la instancia, procedemos a descargar el archivo utilizando la función download_file_minio(). Esta función requiere la ruta al archivo, la cual nos fue proporcionada por la solicitud anterior hacia S3_MINIO. La ruta tiene una estructura similar a esta: 'smartinroldangbucket/s3_queries/prueba_smrg_2025-01-24_12:45:48.046.json' (usamos esta ruta para el ejemplo). La función nos devuelve un objeto de tipo FileManager, por lo que, para obtener únicamente la información del archivo, agregamos .json_data al final, de modo que la expresión queda de la siguiente forma:

data = file_manager.download_file_minio(filepath="smartinroldangbucket/s3_queries/prueba_smrg_2025-01-24_12:45:48.046.json").json_data

Para que el dataframe se visualice de la manera más adecuada, es necesario 'aplanar' los datos. Para ello, utilizamos la función .to_pandasdataframe(), que podemos usar de dos formas: pasándole directamente la 'data' que nos devolvió la función anterior o encadenando las funciones. Estas son ambas formas:

  • Pasandole la ‘data’:

data = file_manager.to_pandasdataframe(data)
  • Encadenando las funciones:

data = file_manager.download_file_minio(filepath="smartinroldangbucket/s3_queries/prueba_smrg_2025-01-24_12:45:48.046.json").to_pandasdataframe()

Si no se añade ningún separador, el valor predeterminado es el punto ('.'). Sin embargo, se puede especificar el separador que se desee utilizando el parámetro 'sep'. Por ejemplo, para cambiarlo a un guión ('-'), se hace de la siguiente manera:

data = file_manager.to_pandasdataframe(data, "-") data = file_manager.download_file_minio(filepath="smartinroldangbucket/s3_queries/prueba_smrg_2025-01-24_12:45:48.046.json").to_pandasdataframe(sep="-")

En este punto, ya tenemos la información estructurada de manera adecuada para que el dataframe se vea correctamente. Ahora, si lo ejecutamos:

df = pd.DataFrame(data) print(df)

Lo que se imprime en pantalla sería algo así:

image-20250212-130403.png