Nova postagem

Pesquisar

Artigo
· Fev. 11 8min de leitura

Utilizando o Gateway SQL com Python, Vector Search e Interoperabilidade no InterSystems Iris - Parte 3 – REST e Interoperabilidade

Utilizando o Gateway SQL com Python, Vector Search e Interoperabilidade no InterSystems Iris

Parte 3 – REST e Interoperabilidade

Agora que finalizamos a configuração do Gateway SQL e conseguimos acessar os dados do banco externo via python, e montamos nossa base vetorizada, podemos realizar algumas consultas. Para isso nessa parte do artigo vamos utilizar uma aplicação que desenvolvida com CSP, HTML e Javascript que acessará uma integração no Iris, que então realiza a pesquisa por similaridade dos dados, faz o envio para a LLM e por fim devolve o SQL gerado. A página CSP chama uma API no Iris que recebe os dados a serem utilizados na consulta, chamando a integração. Para mais informações sobre REST nop Iris veja a documentação disponível em https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls...

A seguir o código da API REST criada:

Class Rest.Vector Extends %CSP.REST
{

XData UrlMap
{
<Routes>
        <Route Url="/buscar" Method="GET" Call="Buscar"  Cors="true"/>
    </Routes>
}

ClassMethod Buscar() As %Status
{
    set arg1 = %request.Get("arg1")
    set sessionID = %request.Get("sessionID")
    Set saida = {}
    Set obj=##Class(ws.rag.msg.Request).%New()
    Set obj.question=arg1
    Set obj.sessionId=sessionID
    Set tSC=##Class(Ens.Director).CreateBusinessService("ws.rag.bs.Service",.tService)
    If tSC
    {
                  Set resp=tService.entrada(obj)
    } Else {
                  Set resp=##Class(ws.rag.msg.Response).%New()
                  Set resp.resposta=$SYSTEM.Status.GetErrorText(tSC)
    }
    Set saida = {}
    Set saida.resposta=resp.resposta
    Set saida.sessionId=sessionID // Devolve o SessionId que chegou
    //
    Write saida.%ToJSON()
    Quit $$$OK
}

}

Uma vez criado o código da API REST precisamos criar a configuração da aplicação no Portal de Administração->Administração do Sistema->Segurança->Aplicações Web:

Na aplicação CSP, em Javascript, temos então a chamada da API:

...

async function chamaAPI(url, sessionID)

    var div = document.getElementById('loader');
    div.style.opacity=1;
    fetch(url)
         .then(response => {
               if (!response.ok) {
                     throw new Error('Erro na resposta da API');
               }
              return response.json();
         })
        .then(data => {
               incluiDIVRobot(data.resposta, data.sessionID);
        })
       .catch(error => {
               incluiDIVRobot('Erro na chamada da API:: ' + error, sessionID);
       });
 }

//

 const url = 'http://' + 'localhost' + '/api/vector/buscar?arg1=' + texto + '&sessionID=' + sessionID;
 chamaAPI(url, sessionID);

...

A aplicação CSP então recebe como entrada a solicitação do usuário (por exemplo: “qual a menor temperatura registrada?”) e chama a API REST.

 

A API REST por sua vez chama uma integração no Iris composta de Service, Process e Operation. Na camada de Operation temos a chamada a LLM, que é feita por um método em python de uma classe. Vendo o trace da integração podemos verificar o processo todo ocorrendo.

Para mais informações sobre o uso de produções no Iris veja a documentação disponível em https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls...

Abaixo os códigos utilizados nas camadas de BS, BP e BO:

A seguir o código do BS (Service):

Class ws.rag.bs.Service Extends Ens.BusinessService
{

Parameter SERVICENAME = "entrada";

Method entrada(pInput As ws.rag.msg.Request) As ws.rag.msg.Response [ WebMethod ]
{
              Set tSC=..SendRequestSync("bpRag",pInput,.tResponse)
              Quit tResponse
}

}

E o código do BP (Process)

Class ws.rag.bp.Process Extends Ens.BusinessProcessBPL [ ClassType = persistent, ProcedureBlock ]
{

/// BPL Definition
XData BPL [ XMLNamespace = "http://www.intersystems.com/bpl" ]
{
<process language='objectscript' request='ws.rag.msg.Request' response='ws.rag.msg.Response' height='2000' width='2000' >
<sequence xend='200' yend='350' >
<call name='boRag' target='boRag' async='0' xpos='200' ypos='250' >
<request type='ws.rag.msg.Request' >
<assign property="callrequest" value="request" action="set" languageOverride="" />
</request>
<response type='ws.rag.msg.Response' >
<assign property="response" value="callresponse" action="set" languageOverride="" />
</response>
</call>
</sequence>
</process>
}

Storage Default
{
<Type>%Storage.Persistent</Type>
}

}

 

E o código do BO (Operation):

 

Class ws.rag.bo.Operation Extends Ens.BusinessOperation [ ProcedureBlock ]
{

Method retrieve(pRequest As ws.rag.msg.Request, Output pResponse As ws.rag.msg.Response) As %Library.Status
{
 Set pResponse=##Class(ws.rag.msg.Response).%New()
 Set pResponse.status=1
 Set pResponse.mensagem=”OK”
 Set pResponse.sessionId=..%SessionId
 Set st=##Class(Vector.Util).RetrieveRelacional(“odbc_work”,pRequest.question,pRequest.sessionId)
 Set pResponse.resposta=st
 Quit $$$OK
}

XData MessageMap
{
<MapItems>
<MapItem MessageType=”ws.rag.msg.Request”>
 <Method>retrieve</Method>
 </MapItem>
</MapItems>
}

}

 

Na sequencia, as classes de Request e Response da integração:


Request:

 

Class ws.rag.msg.Request Extends Ens.Request
{

Property collectionName As %String;

Property question As %String(MAXLEN = "");

Property sessionId As %String;

}

 

Response:

 

Class ws.rag.msg.Response Extends Ens.Response
{

Property resposta As %String(MAXLEN = "");

Property status As %Boolean;

Property mensagem As %String(MAXLEN = "");

Property sessionId As %Integer;

 

}

 

E a classe da Production:

Class ws.rag.Production Extends Ens.Production
{

XData ProductionDefinition
{
<Production Name="ws.rag.Production" LogGeneralTraceEvents="false">
  <Description>Produção do Rag DEMO</Description>
  <ActorPoolSize>2</ActorPoolSize>
  <Item Name="ws.rag.bs.Service" Category="rag" ClassName="ws.rag.bs.Service" PoolSize="0" Enabled="true" Foreground="false" Comment="" LogTraceEvents="false" Schedule="">
  </Item>
  <Item Name="bpRag" Category="rag" ClassName="ws.rag.bp.Process" PoolSize="1" Enabled="true" Foreground="false" Comment="" LogTraceEvents="false" Schedule="">
  </Item>
  <Item Name="boRag" Category="rag" ClassName="ws.rag.bo.Operation" PoolSize="1" Enabled="true" Foreground="false" Comment="" LogTraceEvents="false" Schedule="">
  </Item>
</Production>
}

}

 

 

 

 

Ao ser executada a integração mantém os Requests e Responses armazenados permitindo a rastreabilidade no barramento, conforme vemos no trace a seguir:

 

Podemos ver no trace, por exemplo, que o tempo que a chamada a LLM levou para enviar os dados e devolver o SQL solicitado foi de aproximadamente 10s:

Podemos ver o retorno do BO após tratar a resposta da LLM no código python, para o nosso questionamento:

Assim, através da rastreabilidade da camada de interoperabilidade do Iris, podemos ver todo o fluxo de informação trafegado, os tempos decorridos, eventuais falhas e se for o caso, reprocessar alguma chamada, caso necessário.

A chamada do BO ao método em python passa a solicitação feita pelo usuário. O código em python através da busca vetorial encontra os registros mais semelhantes e os envia a LLM junto com a solicitação do usuário (no caso o modelo da nossa tabela), o histórico de conversa (se existir) e o prompt que são as orientações para balizar a atuação da LLM.

A LLM então gera o SQL que é devolvido ao método em python. O código então executa o SQL e formata a resposta para o padrão esperado, criando as listas de apresentação, gráficos ou downloads de acordo com o retorno aguardado pelo usuário.

Assim, através da aplicação CSP criada, podemos solicitar várias informações, como por exemplo, tabelas de respostas:

Ou gráficos:

Ou ainda, o download de informações:

Para o download, baixando e abrindo o arquivo temos os dados solicitados:

Estes exemplos mostram a leitura dos dados da tabela externa com o Gateway SQL do Iris e o seu uso com código escrito em python. Desta forma podemos utilizar todo o potencial dos dados, que não precisam estar armazenados dentro do Iris. Imagine poder montar uma estação de análise que colete dados de diversos sistemas e dê como resposta informações para tomada de decisão.

Podemos, por exemplo, ter dashboards visualizando dados dos diversos ambientes que compõem o ecossistema de uma empresa, previsões baseadas em algoritmos de ML, RAG para facilitar o levantamento de dados e muito mais.

O Iris pode ser o responsável por acessar, tratar e disponibilizar os dados dos diversos ambientes, com controle, segurança e rastreabilidade, graças às características de interoperabilidade, podendo utilizar código em COS e python, e ser acessado através de códigos em R, C, Java e muito mais. E tudo isso dentro do mesmo produto e sem a necessidade de duplicar ou mover dados entre ambientes.

Discussão (0)1
Entre ou crie uma conta para continuar
Artigo
· Fev. 11 7min de leitura

Utilizando o Gateway SQL com Python, Vector Search e Interoperabilidade no InterSystems Iris - Parte 2 – Python e Vector Search

Utilizando o Gateway SQL com Python, Vector Search e Interoperabilidade no InterSystems Iris

Parte 2 – Python e Vector Search

Uma vez que temos acesso aos dados da nossa tabela externa podemos utilizar tudo que o Iris tem de excelente com estes dados. Vamos, por exemplo, ler os dados da nossa tabela externa e gerar uma regressão polinomial com eles.

Para mais informações sobre o uso do python com o Iris veja a documentação disponível em https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=AFL_epython

Vamos agora então consumir os dados do banco externo para calcular uma regressão polinomial. Para isso vamos através de um código em python executar um SQL que lerá nossa tabela do MySQL e transformará ela em um dataframe pandas:

ClassMethod CalcularRegressaoPolinomialODBC() As %String [ Language = python ]
{
    import iris
    import json
    import pandas as pd
    from sklearn.preprocessing import PolynomialFeatures
    from sklearn.linear_model import LinearRegression
    from sklearn.metrics import mean_absolute_error
    import numpy as np
    import matplotlib
    import matplotlib.pyplot as plt
    matplotlib.use("Agg")

    # Define Grau 2 para a regressão
    grau = 2
    
    # Recupera dados da tabela remota via ODBC
    rs = iris.sql.exec("select venda as x, temperatura as y from estat.fabrica")
    df = rs.dataframe()
   
    # Reformatando x para uma matriz 2D exigida pelo scikit-learn
    X = df[['x']]
    y = df['y']
    
    # Transformação para incluir termos polinomiais
    poly = PolynomialFeatures(degree=grau)
    X_poly = poly.fit_transform(X)

    # Inicializa e ajusta o modelo de regressão polinomial
    model = LinearRegression()
    model.fit(X_poly, y)

    # Extrai os coeficientes do modelo ajustado
    coeficientes = model.coef_.tolist()  # Coeficientes polinomiais
    intercepto = model.intercept_       # Intercepto
    r_quadrado = model.score(X_poly, y) # R Quadrado

    # Previsão para a curva de regressão
    x_pred = np.linspace(df['x'].min(), df['x'].max(), 100).reshape(-1, 1)  # Valores para a curva de regressão
    x_pred_poly = poly.transform(x_pred)  # Transformando para base polinomial
    y_pred = model.predict(x_pred_poly)
    
    # Calcula Y_pred baseado no X
    Y_pred = model.predict(X_poly)
            
    # Calcula MAE
    MAE = mean_absolute_error(y, Y_pred)
    
    # Geração do gráfico da Regressão
    plt.figure(figsize=(8, 6))
    plt.scatter(df['x'], df['y'], color='blue', label='Dados Originais')
    plt.plot(df['x'], df['y'], color='black', label='Linha dos Dados Originais')
    plt.scatter(df['x'], Y_pred, color='green', label='Dados Previstos')
    plt.plot(x_pred, y_pred, color='red', label='Curva da Regressão Polinomial')
    plt.title(f'Regressão Polinomial (Grau {grau})')
    plt.xlabel('X')
    plt.ylabel('Y')
    plt.legend()
    plt.grid(True)

    # Salvando o gráfico como imagem
    caminho_arquivo = 'c:\\temp\\RegressaoPolinomialODBC.png'
    plt.savefig(caminho_arquivo, dpi=300, bbox_inches='tight')
    plt.close()
    
    resultado = {
        'coeficientes': coeficientes,
        'intercepto': intercepto,
        'r_quadrado': r_quadrado,
        'MAE': MAE
    }

    return json.dumps(resultado)
}

A primeira ação que realizamos no código é a leitura os dados da nossa tabela externa via SQL e então os transformamos em um dataframe Pandas. Sempre lembrando que os dados estão fisicamente armazenados no MySQL e são acessados via ODBC através do Gateway SQL configurado no Iris. Com isso podemos utilizar as bibliotecas do python para cálculo e gráfico, conforme vemos no código.

Executando nossa rotina temos as informações do modelo gerado:

Nossa rotina também gera um gráfico que nos dá um suporte visual para a regressão polinomial. Vamos ver como o gráfico ficou:

Outra ação que podemos realizar com os dados que agora estão disponíveis é o uso do Vector Search e RAG com o uso de uma LLM. Para isso vamos vetorizar o modelo da nossa tabela e a partir daí pedir algumas informações a LLM.

Para mais informações sobre o uso de Vector Search no Iris veja o texto disponível em https://www.intersystems.com/vectorsearch/

Primeiro vamos vetorizar o modelo da nossa tabela. Abaixo o código com o qual realizamos esta tarefa:

ClassMethod IngestRelacional() As %String [ Language = python ]
{

    import json
    from langchain_iris import IRISVector
    from langchain_openai import OpenAIEmbeddings
    from langchain_text_splitters import RecursiveCharacterTextSplitter
    import iris    

    try:
    
        apiKey = iris.cls("Vector.Util").apikey()
        collectionName = "odbc_work"

        metadados_tabelas = [
            "Tabela: estat.fabrica; Colunas: chave(INT), venda(INT), temperatura(INT)"
        ]
        
        text_splitter = RecursiveCharacterTextSplitter(chunk_size=2048, chunk_overlap=0)
        documents=text_splitter.create_documents(metadados_tabelas)
            
        # Vetorizar as definições das tabelas
        vectorstore = IRISVector.from_documents(
        documents=documents,
        embedding=OpenAIEmbeddings(openai_api_key=apiKey),
        dimension=1536,
        collection_name=collectionName
        )
        
        return json.dumps({"status": True})
    except Exception as err:
        return json.dumps({"error": str(err)})
}

 

Note que não passamos para o código de ingest o conteúdo da tabela, e sim seu modelo. Desta forma a LLM é capaz de, ao receber as colunas e suas propriedades, definir um SQL de acordo com nossa solicitação.

Este código de ingest cria a tabela odbc_work que será utilizada para fazer a busca por similaridade no modelo da tabela, e a seguir solicitar a LLM que devolva um SQL. Para isso criamos uma API KEY na OpenAI e utilizamos o langchain_iris como biblioteca python. Para mais detalhes sobre o langchain_iris veja o link https://github.com/caretdev/langchain-iris

Após realizar o ingest da definição da nossa tabela teremos a tabela odbc_work gerada:

Agora vamos a nossa terceira parte que é o acesso de uma API REST que vai consumir os dados que estão vetorizados para montar um RAG.

Até logo!

Discussão (0)1
Entre ou crie uma conta para continuar
Artigo
· Fev. 11 4min de leitura

Utilizando o Gateway SQL com Python, Vector Search e Interoperabilidade no InterSystems Iris - Parte 1 – Gateway SQL

Utilizando o Gateway SQL com Python, Vector Search e Interoperabilidade no InterSystems Iris

Parte 1 – Gateway SQL

Olá,

Neste artigo vamos ver o uso do Gateway SQL no Iris. O Gateway SQL permite que o Iris tenha acesso a tabelas de outros bancos (externos) via ODBC ou JDBC. Podemos acessar Tabelas ou Visões de diversos bancos, como Oracle, PostgreSQL, SQL Server, MySQL e outros.

Do ponto de vista de uso é como se a tabela estivesse local na nossa instância Iris, porém o armazenamento é realizado em um local externo.

Para maiores detalhes sobre este componente veja a documentação que está disponível em https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=BSQG_overview

Então vamos para as configurações necessárias:

Primeiro, para fazer a configuração do SQL Gateway no Iris vamos precisar configurar o acesso a um banco externo. Para nosso exemplo vamos utilizar uma instância MySQL sendo acessada via ODBC.

Instalamos então uma instância do MySQL em um servidor e nela criamos a tabela que será acessada no nosso exemplo:

 

 

 

 

 

 

Então populamos a tabela com informações. Abaixo um exemplo da tabela já com dados:

Agora vamos criar um DSN no Windows para realizar a conexão ao MySQL. Antes precisamos instalar o driver ODBC do MySQL no Windows. O driver pode ser facilmente obtido no site do próprio MySQL.

Após instalar o driver ODBC para o MySQL, abra o Gerenciador de Fonte de Dados ODBC no Windows:

 

Clique na aba “DSN de Sistema” e a seguir no botão Adicionar:

Selecione o driver MySQL ODBC ANSI e clique em Concluir.

 

Preencha a tela de configuração com nome do data source a ser criado, descrição, endereço IP e porta de comunicação do servidor do MySQL (padrão é a porta 3306 – verifique se sua instância MySQL está de fato utilizando esta porta de comunicação), o usuário e senha de acesso ao MySQL (crie no MySQL um usuário com permissão de acesso para as tabelas que deseja utilizar). Selecione o banco de dados a ser acessado:

 

Clique n botão de teste para verificar se a sua configuração está acessando a instancia do MySQL configurada no DSN:

 

Agora vamos fazer uma consulta via ODBC para verificar se tudo está OK na nossa estrutura. Vamos utilizar o Excel para isso. Abra o Excel, e vá em Dados->Obter Dados->De outras Fontes->Do ODBC:

Selecione o DSN que você criou para acessar o MySQL e a seguir selecione o esquema e a tabela que deseja verificar. No nosso caso vamos ver a tabela venda do esquema estat:

A seguir clique no botão Carregar e você verá os dados da sua tabela nas células do Excel:

 

Pronto. Já temos a nossa conexão ODBC criada e funcionando para realizar o acesso a nossa tabela remota. Agora vamos voltar ao Iris e realizar a configuração da conexão do SQL Gateway. Abra o Painel de Administração do Iris e vá em Administração do Sistema->Configuração->Conectividade->Conexões de SQL Gateway e clique no botão Criar Nova Conexão:

Informe os dados de acesso ao DSN conforme abaixo:

Tipo de Conexão

ODBC

Nome da Conexão

Informe um nome a seu critério

Selecione um DSN existente

Selecione o DSN criado para acesso ODBC ao MySQL

Usuário

Usuário de acesso (o mesmo do DSN)

Senha

Senha de acesso (a mesma que a do DSN)

 

Para o teste vamos deixar desmarcadas todas as opções da configuração, exceto a Não converter valores que não sejam caracteres:

Por fim clique em “Testar Conexão” para verificar se tudo está OK. Você verá o texto “Conexão teve sucesso.” caso tudo esteja configurado corretamente:

Uma vez criado o DSN e configurado o acesso do Gateway SQL podemos fazer a vinculação das tabelas para o Iris poder acessar os dados remotos. Para isso volte ao Portal de Administração e vá para Explorer do Sistema->SQL e mude para o namespace onde serão armazenadas as definições da classe que serão geradas:

Clique no link “Assistentes” e a seguir em “Vincular Tabela”. Você verá a tela do wizard de vinculação de tabelas do Iris:

Procure a conexão Gateway SQL que foi criada no passo anterior:

Selecione o esquema e a tabela que deseja vincular no Iris:

Clique em Avançar e selecione as colunas da tabela que deseja ter acesso:

Clique em Avançar e faça os ajustes de nomes e característica de leitura/gravação nos campos disponíveis:

Clique em Avançar e procure o campo que será a chave primária dos registros:

Selecione os campos que formam a chave primária do registro:

Clique em Salvar. Informe o nome da classe a ser criada e o nome da tabela SQL:

A seguir clique em Terminar.

A nossa classe no Iris foi criada. Abra o Studio e veja a classe:

Vamos testar o acesso aos dados fazendo uma consulta via SQL. Para isso vamos voltar ao Portal de Administração e vamos em Explorer do Sistema->SQL e vamos mudar para o namespace onde criamos nossa classe. Vamos então executar o SQL de consulta a nossa tabela vinculada:

Pronto! Já temos acesso aos dados de nossa tabela no MySQL. Lembrando que podemos realizar INSERT/UPDATE/DELETE ou então utilizar as sintaxes de manipulação de objetos do Iris agora que a tabela está vinculada, como vemos abaixo:

 

 

 

 

 

 

 

 

 

 

E usando a sintaxe de objetos do Iris:

 

Assim concluímos esta primeira parte já conseguindo acessar os dados do MySQL através do Iris utilizando o Gateway SQL.

Até a próxima parte do nosso artigo!

Discussão (0)1
Entre ou crie uma conta para continuar
Artigo
· Fev. 11 6min de leitura

Using REST API, Flask and IAM with InterSystems IRIS - Part 2 – Flask App

Using Flask, REST API, and IAM with InterSystems IRIS

Part 2 – Flask App

 

Flask is a web development microframework written in Python. It is known for being simple, flexible, and enabling rapid application development.

Installing Flask is very simple. Once you have python installed correctly on your operating system, we need to install the flask library with the pip command. For REST API consumption, it is advisable to use the requests library. The following link provides a guide to installing flask: https://flask.palletsprojects.com/en/stable/installation/

 Once the flask is installed, let's start with the structure of our application. Let's create the directories and sub-directories to accommodate our files:

 

/--+

   |

   +-- static

   |

   +-- template

 

So let's follow this definition. For example, in c:\temp we will create the flask directory and below we will create the static and template sub-directories.

Follow the installation documentation and install and configure the venv. Then install the flask library with the pip command. The flask documentation shows the command. Remember that you need to already have python installed.

After installing the flask library, install the requests library with pip, the same way you installed flask.

In the flask directory we will put our python application. The following is the application code:

from flask import Flask, render_template, request, redirect, url_for

import requests

from requests.auth import HTTPBasicAuth

 

app=Flask(__name__)

 

API_URL = "http://192.168.0.13/iris/rest/servico/cliente"

USERNAME="_SYSTEM"

PASSWD = "SYS"

 

# Route to List Records

@app.route('/')

def index():

 

    response = requests.get(API_URL, auth=HTTPBasicAuth(USERNAME, PASSWD))

    data = response.json()

    lista = data["clientes"]

    return render_template("index.html", registros=lista)

 

# Route to Display the Inclusion Form

@app.route('/include', methods=['GET'])

def include():

    return render_template("form.html", record={"id": "", "name": "", "age": ""}, action="Include")

 

# Route to Create a New Record

@app.route('/create', methods=['POST'])

def create():

    data = {

        "name": request.form["name"],

        "age": request.form["age"]

    }

    requests.post(API_URL, json=data, auth=HTTPBasicAuth(USERNAME, PASSWD))

    return redirect(url_for("index"))

 

# Route to Display the Edit Form

@app.route('/edit/<int:id>', methods=['GET'])

def edit(id):

    response = requests.get(f"{API_URL}/{id}", auth=HTTPBasicAuth(USERNAME, PASSWD))

    record = response.json() if response.status_code == 200 else {"id": "", "name": "", "age": ""}

    return render_template("form.html", record=record, action="Edit")

 

# Route to Update an Existing Record

@app.route('/update/<int:id>', methods=['POST'])

def update(id):

    data = {

        "name": request.form["name"],

        "age": request.form["age"]

    }

    requests.put(f"{API_URL}/{id}", json=data, auth=HTTPBasicAuth(USERNAME, PASSWD))

    return redirect(url_for("index"))

 

# Route to Deleting a Record

@app.route('/delete/<int:id>')

def delete(id):

    requests.delete(f"{API_URL}/{id}", auth=HTTPBasicAuth(USERNAME, PASSWD))

    return redirect(url_for("index"))

 

if __name__ == "__main__":

    app.run(debug=True)

 

The code is very simple, we have the inclusion, change, deletion routes, a route to list the existing records and give access to the maintenance options, and the inclusion and change forms.

Now let's go to the static subdirectory. In it we will put our CSS file style.css:

 

body {

;

text-align: center;

margin: 20px;

}

 

table {

width: 60%;

margin: auto;

border-collapse: collapse;

}

 

th, td {

border: 1px solid black;

padding: 8px;

}

 

a {

text-decoration: none;

color: blue;

}

 

And in the templates subdirectory we will put our HTML files index.html and form.html:

index.html

<! html DOCTYPE>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>CRUD Flask</title>

    <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">

</head>

<body>

    <h2>List of Records</h2>

    <a href="{{ url_for('include') }}">Add New</a>

    <table border="1">

        <tr>

            <th>ID</th>

            <th>Name</th>

            <th>age</th>

            <th>Stocks</th>

        </tr>

        {% for reg in records %}

        <tr>

            <td>{{ reg.id }}</td>

            <td>{{ reg.name }}</td>

            <td>{{ reg.age }}</td>

            <td>

                <a href="{{ url_for('edit', id=reg.id) }}">Edit</a> |

                <a href="{{ url_for('delete', id=reg.id) }}" onclick="return confirm('Are you sure?')" >Delete<>

            </TD>

        </tr>

        {% endfor %}

    </table>

</body>

</html>

 

form.html

 

<! html DOCTYPE>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>{{ action }} Record</title>

</head>

<body>

    <h2>{{ action }} Log</h2>

    <form method="POST" action="{{ url_for('create' if action == 'Include' else 'update', id=record.id) }}">

        <label>Name:</label>

        <input type="text" name="name" value="{{ record.name }}" required><br>

        <label>age:</label>

        <input type="text" name="age" value="{{ age.record }}" required><br>

        <button type="submit">{{ action }}</button>

    </form>

    <a href="{{ url_for('index') }}">Back</a>

</body>

</html>

 

To run the application just go to the directory where we are with our python application (in our case, c:\temp\flask), activate the venv (virtual environment) and run the application:

 

 

We can now access our application by accessing local port 5000 with a browser:

 

Clicking on the Add New link  we have the screen for adding records to our class:

 

Returning to the index screen, selecting Change on some record, we have the change screen:

 

And, again going back to the index screen, clicking on Delete , let's go to the confirmation of the deletion:

 

 

With that we end this part of the article. We already have our persistent class created, the REST API published, and a flask application consuming this API with the requests library to perform basic maintenance (CRUD)..

Discussão (0)1
Entre ou crie uma conta para continuar
Artigo
· Fev. 11 9min de leitura

Using REST API, Flask and IAM with InterSystems IRIS - Part 1 - REST API

Using Flask, REST API, and IAM with InterSystems IRIS

Part 1 - REST API

 

Hello

In this article we will see the implementation of a REST API to perform the maintenance of a CRUD, using Flask and IAM.

In this first part of the article we will see the construction and publication of the REST API in Iris.

First, let's create our persistent class to store the data. To do this, we go to Iris and create our class:

Class ERP. Client Extends (%Persistent, %Populate, %XML.Adaptor)

{

 

Property name As %String;

 

Property age As %Integer;

 

}

 

Ready. We already have our persistent class created and ready to receive data. Now let's create our REST API.

When we talk about REST, we are talking about the HTTP protocol and its verbs. HTTP verbs are methods that define the operation that the client wants to do. Some examples of HTTP verbs are:

  • GET: Requests a specific resource and returns only data. It is the standard for submitting data when submitting an HTTP form. 
  • POST: Submits data to a resource, changing states of a resource present on the server. It is used to send information to be processed, such as creating a product or a customer. 
  • HEAD: Similar to the GET method, however it does not require the body of the response.
  • PUT: Replaces all current renditions of the target resource with the request's data payload.
  • DELETE: Deletion.

As a response to the verbs we have, the status codes indicate the result of the request. For example, 200 indicates that the request was successful.

Iris implements REST in a very easy and robust way. The following documentation provides all the information you need to create a REST API: https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=GREST

Let's then assemble the code of our REST API to perform basic maintenance on our ERP class. Customer. for this we will create a class that extends from %CSP. REST:

Class Rest.Servico Extends %CSP. REST

{

 

XData UrlMap

{

<Routes>

        <route url="/customer" method="POST" call="include" cors="true"/>

        <Route Url="/customer/:key" Method="PUT" Call="Change" Cors="true"/>

        <Route Url="/client/:key" Method="DELETE" Call="Delete" Cors="true"/>

        <Route Url="/customer/:key" Method="GET" Call="Search" Cors="true"/>

        <Route Url="/client" Method="GET" Call="List" Cors="true"/>

    </Routes>

}

 

ClassMethod Include() The %Status

{

             

              From ##class(%REST. Impl).%SetContentType("application/json")

             

    Set payload = %request. Content.Read()

    Set objJSON=##Class(%DynamicAbstractObject).%FromJSON(payload)

       

    Set objCustomer=##Class(ERP. Client).%New()

    Set objClient.name=objJSON.name

    Set objClient.age=objJSON.age

    Set st=objClient.%Save()

    If 'st

    {

                  From ##class(%REST. Impl).%SetStatusCode("404") Quit $$$OK

 

    }

   

              From ##class(%REST. Impl).%SetStatusCode("200")

 

    return $$$OK

}

 

ClassMethod Change(key As %Integer) As %Status

{

             

              From ##class(%REST. Impl).%SetContentType("application/json")

 

    Set payload = %request. Content.Read()

    Set objJSON=##Class(%DynamicAbstractObject).%FromJSON(payload)

       

    Set objCustomer=##Class(ERP. Client).%OpenId(key)

    If '$IsObject(objClient)

    {

                  From ##class(%REST. Impl).%SetStatusCode("404") Quit $$$OK

 

    }    

   

    Set objClient.name=objJSON.name

    Set objClient.age=objJSON.age

    Set st=objClient.%Save()

    If 'st

    {

                  From ##class(%REST. Impl).%SetStatusCode("500") Quit $$$OK

 

    }   

   

              From ##class(%REST. Impl).%SetStatusCode("200")

 

    return $$$OK

}

 

ClassMethod Delete(key As %Integer) As %Status

{

              From ##class(%REST. Impl).%SetContentType("application/json")

       

    Set st=##Class(ERP. Client).%DeleteId(key)

    If 'st

    {

                  From ##class(%REST. Impl).%SetStatusCode("404") Quit $$$OK

 

    }   

   

              From ##class(%REST. Impl).%SetStatusCode("200")

 

    return $$$OK

}

 

ClassMethod Search(key As %Integer) As %Status

{

       

    From ##class(%REST. Impl).%SetContentType("application/json")

             

    Set objCustomer=##Class(ERP. Client).%OpenId(key)

    If '$IsObject(objClient)

    {

                  From ##class(%REST. Impl).%SetStatusCode("404") Quit $$$OK

 

    }

   

              From ##class(%REST. Impl).%SetStatusCode("200")   

   

    Set objJSON={}   

    Set objJSON.id=key

    Set objJSON.name=objectClient.name

    Set objJSON.age=objCustomer.age

             

              Write objJSON.%ToJSON() 

 

    return $$$OK

}

 

ClassMethod List() As %Status

{

              From ##class(%REST. Impl).%SetContentType("application/json")          

                                         

              Set result=##class(%ResultSet).%New("%DynamicQuery:SQL")

 

              Set st=result. Prepare("select id, name, age from ERP. Client")

    If 'st

    {

                  From ##class(%REST. Impl).%SetStatusCode("500") Quit $$$OK

 

    }        

              Set st=result. Execute()

   

    Set objJSON={}

    Set clients=[]

             

              While result. Next(.st) {

                           

                            Set objCliente={}

                            Set objClient.id=result.%Get("ID")                                          

                            Set objClient.name=result.%Get("name")             

                            Set objectCustomer.age=result.%Get("age")       

                            From Customers.%Push(objectCustomer)

              }

       

              From ##class(%REST. Impl).%SetStatusCode("200")

             

              Set outputa={}

              Set out.customers=customers

             

              Write output.%ToJSON()

 

    return $$$OK

}

 

}

Notice the part of the code that defines the URLs (UrlMap) where we have the URL called, the verb (Method) triggered, and the method of the code that should be called. It is very easy to understand each of the calls made and the association of the call with the HTTP verb.

Now that we've created our class, let's set up a web application in the iris so that this application does the REST service we want to provide. To do this, we go to the Administration->System Administration->Security->Applications->Web Applications Portal and we will create a new application:

 

Enter the name of the application (/rest/service), the Namespace where the REST class was created, check the Activate application box. Select the REST option and enter the Dispatch class. Check the Password option under Methods for Authentication and save the setting.

Our REST class is published and ready to be consumed. Simple as that!

We're going to use Postman to do some testing on our API. The first test is to see if we can retrieve the customer list.

Let's open Postman, and in the address bar we'll enter the URL of our API: http://<ip_addr>/<config_iris>/rest/service/customer. Enter the authentication data (username and password) to access the API in the Authorization tab:

 

 

Now select the desired verb, GET, and submit the request. This setting will trigger the List method. And then we have as a response an HTTP 200 status and the list of clients.

We can make an inclusion with the call using the POST verb and creating a body for our request. To do this, go to the Body tab and enter the payload that will be sent (in our example {"name":"Pierre", "age":"45"}). Click Send and see the response (HTTP status 200):

 

 

Now we have Pierre's record created in our class. We can fetch the record with the GET by passing the record ID number:

Note that now, in the URL, we enter the ID of the desired record. This causes our API to call the Search method.

So we have our persistent class created, our REST API developed and published in Iris, and it can be safely consumed.

In the next part of this article we will see how we can consume this API through a FLASK application.

Discussão (0)1
Entre ou crie uma conta para continuar