Nova postagem

Pesquisar

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
Pergunta
· Fev. 11

Intersystems Reports (Logi Reports) - Does it merge multiple PDFs?

We currently use a combination of Ghostscript and ImageMagick to accomplish our PDF requirements.  These products are ceating memory/cpu issues when merging large PDFS.  I am trying to find out if Intersystems Reports can handle our requirements (see below).

 

   

Magick 7.0.10 - Ghostscript 9.53.2
Magick 7.0.10 - Ghostscript 10.04
Does Not Work

Function

Image manipulation

Required Software

Create/print Requisition

PDFToPCL

Ghostscript + ImageMagick using convert command

Create/print Requisition

PDFToPCL

Ghostscript + ImageMagick using convert command

ConvertImgToPDF

 

Ghostscript + ImageMagick using convert command

ConvertPDFToPNG

 

Ghostscript

ConvertPDFToText

 

Ghostscript

MergePDFS

 

Ghostscript

PDFToPCL

 

Ghostscript + ImageMagick using convert command

PrintABN

s cmd="i:\pdfPrintX\PDFtoPrinter

PDFtoPrinter software locally installed

PrintPDFToDevice

PDFToPCL

Ghostscript + ImageMagick using convert command

CreatePDF

 

%Zen.Report

GetAllEncompassingPDF

CreatePDF + MergePDFS if they exist

Ghostscript during the merge

ABNPRINTNEW

PrintPDFToDevice (PCL)

Ghostscript + ImageMagick using convert command

PrintABNToScreen

ConvertPDFToText

Ghostscript

PRINTPDF

PDFToPCL

create txt file and then pdf to get embedded barcode

 

PDFTOPCL

Ghostscript + ImageMagick using convert command

 

PrintPDFToDevice

Ghostscript + ImageMagick using convert command

 

ConvertPDFToText if wanting to print to screen

GhostScript

PRINTPDFS

PDFToPCL

Ghostscript + ImageMagick using convert command

 

Does anyone have experience with Intersystems Reports and if so, can you give me some insights as to the functionality as a replacement for Ghostscript and ImageMagick for above functionality?

Thank you in advance for any help on this.

2 Comments
Discussão (2)2
Entre ou crie uma conta para continuar
Pergunta
· Fev. 11

VS CODE Search Options

Hi All,

In my DB, it has more than 10,000 files. I tried to search for a particular file (mac), but there is no search option to find it. Can you help me find that option to search for a file?

2 Comments
Discussão (2)2
Entre ou crie uma conta para continuar
Artigo
· Fev. 11 3min de leitura

Uma visão sobre Dynamic SQL e Embededd SQL

 

 

Ao contrário do filme, citado através da imagem (para quem não conhece, Matrix, 1999), a escolha entre Dynamic SQL e Embededd SQL, não é uma escolha entre a verdade e a fantasia, mas, mesmo assim é uma decisão a ser tomada. Abaixo, tentarei facilitar a escolha de vocês.

Caso sua necessidade seja interações entre o cliente e a aplicação (consequentemente o banco de dados), o Dynamic SQL pode ser mais apropriado, pois “molda-se” muito facilmente com estas alterações de consultas. Entretanto, este dinamismo tem um custo, a cada consulta nova, ela é remodelada, podendo ter um custo maior para a execução. Abaixo um exemplo simples de um trecho de código Python.

Exemplo de SQL Dynamic

Apenas com base na informação acima, o Embededd SQL é a melhor escolha? Depende. Pensando única e exclusivamente em agilidade na execução, poderíamos partir para esta escolha. Uma vez que as instruções SQL são inseridas diretamente no código de programação, utilizando-se de variáveis HOST para entrada e saída de dados. O objetivo também não é ensinar como utilizar uma ou outra opção, e sim abrir a mente para possibilidade, conhecendo um pouco sobre cada um.

Abaixo, temos algumas características relevantes e que devem ser levadas em consideração quando iniciar um desenvolvimento que exija uma consulta SQL:

 Como já mencionado, o Embededd SQL é várias lembrado pelo seu desempenho, mas, isto não é uma corrida e nem só de velocidade se vive. Sua integração com diversas linguagens de alto nível, fazem com que os desenvolvedores possam utilizar os recursos de melhor forma, isto dá-se devido ao fato de não precisarem de tantas buscas em arquivos externos ou scripts separados, tornando o código mais limpo e sustentável.

É notado também pela sua consistência, afinal, alterações no banco de dados podem ser espelhadas no código SQL, evitando assim possíveis inconsistências nos dados. E por final, porém não menos importante, o fato das consultas estarem dentro do código, torna-o mais seguro, pois podem ser implementados controles de acesso diretamente no aplicativo, evitando assim acessos não autorizados e consultas indevidas.

Bom, agora podemos ver o que sustenta o Dynamic SQL. Este dinamismo é facilmente notado em sua flexibilidade, isto é, tudo é moldado enquanto está acontecendo, consultas, condições e até nomes de tabelas ou campos, beneficiando assim o cliente, o usuário. É marcado também pela facilidade de administração, uma vez que os DBAs conseguem realizar manutenções nos dados e bancos, conferindo em tempo real o impacto causado, evitando assim maiores problemas de compilação.

O resumo de toda esta informação, com mais teoria e pouca “prática” é que não há um lado certo ou um lado errado, até mesmo um vilão ou um mocinho, o fato é que o conhecimento sobre o que será desenvolvido, uma análise profunda das necessidades, levará a uma escolha...

De qual lado da força você estará?

2 Comments
Discussão (2)3
Entre ou crie uma conta para continuar