Build an RESTful Application with Flask
In the previous exercise, you learned how to build an interactive application using Streamlit. This section introduces how to use Flask to expose InterSystems IRIS data via RESTful APIs.
Building RESTful Flask Applications with InterSystems IRIS
Flask is a lightweight and flexible Python web framework, ideal for developing REST APIs and back-end services. When paired with SQLAlchemy and InterSystmes IRIS, Flask makes it easy to expose InterSystems IRIS data to front-end applications, services, and other consumers. This guide focuses on the InterSystems IRIS-specific setup steps so that you can get started quickly, and then proceed as with any other Flask app.
Prerequisites
Before starting this exercise, make sure that you have installed SQLAlchemy and DB-API using the following command:
pip install sqlalchemy-intersystems-iris
See the DB-API exercise for a brief description of these tools.
You also need to install Flask:
pip install flask
You should also have access to a running InterSystems IRIS instance and valid connection credentials (host, port, username, password, namespace).
What You Will Learn
-
How to set up a basic Flask application.
-
How to connect Flask to InterSystems IRIS using SQLAlchemy.
-
How to use HTML templates and render data from InterSystems IRIS.
What You Will Build
By the end of this documentation, you will have a Flask web application that allows you to view your data in InterSystems IRIS through a clean user interface in the web browser.

Creating Your First Flask App
To get started with Flask, you will create a minimal web application that returns a simple message in the browser.
First, create a new folder for your project (my_flask). Inside it, create a file named app.py with the following content:
from flask import Flask, render_template
app = Flask(__name__)
@app.route("/")
def hello_world():
return "<p>Hello World!</p>"
if __name__ == '__main__':
app.run(debug=True)
In the code above:
-
Flask(__name__) creates the Flask application instance.
-
@app.route("/") decorator defines the route for the rool URL (/).
-
hello_world() is the view function returning a simple HTML message.
-
app.run(debug=True) starts the local development server with debugging enabled.
In Flask, routings map URLs to their respective functions (as defined by @app.route("<URL>")). Accessing these URLs triggers their associated functions. The / URL calls the home function (typically at http://127:0.0.1:5000/). To call other functions via other URLs (defined by @app.route("<URL>")), open http://127:0.0.1:5000/<URL> on your browser.
Do not name your application as flask.py for doing so creates a conflict with Flask itself.
Running the Flask Application
From the folder containing app.py, run the following in the command line:
python app.py
This starts the server, and you can now access your app at http://127:0.0.1:5000/.
Using HTML Templates
Web applications typically use HTML for rendering pages. Flask integrates the Jinja2 templating engine to separate your Python logic from HTML code. This separation improves code readability, maintainability, and reusability.
Understanding the detailed syntax and structure of HTML, CSS, and JavaScript is out of scope for this guide. Just know that you can use them within your Flask app to build dynamic, styled, and interactive webpages.
To implement an HTML template, follow these steps:
-
Create a folder named templates the same directory as app.py.
-
Inside templates, create a filed named index.html with this content:
<!DOCTYPE html> <html> <body> <h1>My First Heading</h1> <p>My First Paragraph</p> </body> <html> -
Modify app.py to render the template.
from flask import Flask app = Flask(__name__) @app.route("/") def hello_world(): return render_template('index.html') if __name__ == '__main__': app.run(debug=True)The following happens in the code above:
-
When a user accesses the root URL (/), Flask triggers the hello_world() function.
-
This function calls render_template('index.html'), which tells Flask to load and return the HTML from the templates/directory.
-
The templates/ folder is Flask’s default location for all HTML templates. Flask separates the front end (HTML/CSS/JS) from the back end (Python), making your codebase cleaner and easier to manage. This modular approach also makes it easier to scale your application as you add more pages and templates.
Folder Structure
This is a typical minimal Flask application layout. Each file and folder serve a specific role to separate the different parts of the application code and keep the project organized and maintainable.

What Each Folder Component Is
-
app.py
This is the entry point of the Flask application. It contains the route definitions, application configuration, and logic to start the server. It typically handles request routing and renders templates.
-
models.py
Contains the SQLAlchemy model definitions, which map Python classes to database tables. This helps abstract and manage database interactions cleanly.
Note:While models.py is not strictly required, it helps organize your Object Relational Mapping logic in a clean and modular way.
-
templates/
Flask uses Jinja2 templating and all HTML files go in this folder. The framework automatically looks for templates here when rendering views using render_template().
-
index.html
A specific HTML file inside the templates folder, typically used as the home page or main data table view. This is where your front end DataTable integration (like in render_template()) would live.
-
static/
Optional but useful for storing static files like custom CSS, JavaScript, images, or fonts. Flask will serve these files from the static/URL path automatically.
Flask intentionally does not enforce strict structures, so while this layout is clean and scalable, you are free to adapt it based on your application’s needs.
Connecting to InterSystems IRIS
To connect to InterSystems IRIS using SQLAlchemy, define a connection string and create an engine. This engine object will be reused throughout the app to run queries and insert data and acts like a persistent, reusable pipeline to your database.
from sqlalchemy import create_engine, text
# Replace with your credentials and connection information
username = "_SYSTEM"
password = "SYS"
namespace = "USER"
DATABASE_URL = f"iris://{username}:{password}@localhost:1972/{namespace}"
engine = create_engine(DATABASE_URL, echo=True) # Set echo=True to see the SQL queries being excuted in the terminal
For more documentation on using SQLAlchemy with InterSystems IRIS, see InterSystems IRIS and SQLAlchemy.
Transferring Data from InterSystems IRIS to Flask and Displaying it
tables.html
The following provides the web page structure for viewing the InterSystems IRIS data. It utilizes jQuery DataTablesOpens in a new tab, a popular JavaScript library used to create dynamic, interactive tables with features like pagination, sorting, searching, and responsive layouts. It also incorporates BootstrapOpens in a new tab, a modern CSS framework that provides a responsive grid system, pre-styled UI components, and utility classes. Bootstrap is used here to style the table and layout elements (such as spacing and table orders), ensuring the table looks clean and is mobile-responsive.
<!DOCTYPE html>
<html>
<head>
<title>Display InterSystems IRIS Data with DataTables</title>
<!-- Bootstrap 5 for styling -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- jQuery (required by DataTables) -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<!-- DataTables + Bootstrap 5 integration -->
<link rel="stylesheet" href="https://cdn.datatables.net/1.13.5/css/dataTables.bootstrap5.min.css">
<script src="https://cdn.datatables.net/1.13.5/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/1.13.5/js/dataTables.bootstrap5.min.js"></script>
</head>
<body class="container py-4">
<h2 class="mb-4">InterSystems IRIS Data Table</h2>
<!-- HTML table to be populated dynamically -->
<table id="myTable" class="table table-bordered table-striped table-hover"></table>
<script>
$(document).ready(function () {
// Convert server-passed JSON strings into JavaScript objects
let my_data = JSON.parse('{{ my_data | tojson | safe }}');
let my_cols = JSON.parse('{{ my_cols | tojson | safe }}');
// Initialize DataTable with server data and column definitions
$('#myTable').DataTable({
data: my_data,
columns: my_cols,
responsive: true,
lengthMenu: [5, 10, 25, 50],
pageLength: 10,
language: {
search: "_INPUT_",
searchPlaceholder: "Search records"
}
});
});
</script>
</body>
</html>
Just like with index.html, understanding the code above is not within the scope of this documentation. The takeaway here is that you can integrate these tools into your Flask application. Refer to the official documentation of these libraries to learn more about them.
app.py
Create a dynamic view into your InterSystems IRIS data through the /table/ URL route. Using a connection via the SQLAlchemy engine to your InterSystems IRIS database, query data from the specified table and populate it into your Flask app. Pass the resulting data to the HTML template from above to create a clean and structured display of it in the web page.
You can specify which table to query directly through the URL. For example, to view data from a table called Bank.Account, open http://127:0.0.1:5000/table/Bank.Account on your browser.
The app will:
-
Parse the table name (optionally including the schema).
-
Execute a SELECT * FROM table ORDER BY 1 query.
-
Convert the results into a list of dictionaries.
-
Dynamically extract column names.
-
Render the tables.html template with your data and columns.
@app.route("/table/<path:table_name>")
def show_table(table_name):
# table_name could be "Schema.Table" or just "Table"
try:
# Validate and split schema/table if schema is provided
if '.' in table_name:
schema, table = table_name.split('.')
full_table = f"{schema}.{table}"
else:
schema = None
table = table_name
full_table = table
# Query to get data from the specified table
query = f"SELECT * FROM {full_table} ORDER BY 1"
with engine.connect() as conn:
result = conn.execute(text(query))
keys = result.keys() # get column names
rows = [dict(zip(keys, row)) for row in result]
if not rows:
return f"No data found in table {full_table}", 404
# Extract columns dynamically from first row keys
columns = [{"data": col, "title": col.capitalize()} for col in rows[0].keys()]
return render_template("tables.html", my_data=rows, my_cols=columns)
except Exception as e:
return f"Error: {str(e)}", 500
In the code above:
-
<path:table_name> defines a Flask route where table_name can include dots (for example, Bank.Account), The :path converter allows such values to be passed as arguments into the view function.
-
Flask uses the Jinja2 templating engine, which allows you to pass arguments (like rows and columns) from your view function into your HTML templates. These variables can be inserted dynamically using the syntax {{variable}} (see tables.html as an example).
-
if '.' in table_name splits the table into schema and table components when the format includes a dot.
-
rows = [dict(zip(keys,row) for row in result] passes both the row data and column definitions into the HTML template, enabling a dynamic and responsive table view.
Note:The result returned by conn.execute() is not a dictionary. Instead, it is an iterable of row tuples or RowProxy objects. To make data easier to work with in Jinja2 templates, the code converts each row to a dictionary by pairing column names with values using zip().
This application enables you to quickly browse and visualize any table in your InterSystems IRIS database by simply modifying the URL. It dynamically pulls and formats tables using SQLAlchemy, then renders it in a styled HTML table using Jinja2. The use of dynamic route arguments and template variables makes it flexible for inspecting a wide range of tables without modifying the back-end logic.
This documentation only touches the surface of Flask. Now that you know how to get started creating a Flask application with InterSystems IRIS, you can fully utilize all of Flask’s features just as with any other Flask application.
To dive deeper into Flask, visit the official Flask documentationOpens in a new tab.
Complete Flask Code
The following is the code for the Flask application built. Be aware of the file structure required to have the application running smoothly.
#app.py
from flask import Flask, render_template
from sqlalchemy import create_engine, text
# Replace with your credentials and connection information
username = "_SYSTEM"
password = "SYS"
namespace = "USER"
DATABASE_URL = f"iris://{username}:{password}@localhost:1972/{namespace}"
engine = create_engine(DATABASE_URL, echo=True) # Set echo=True to see the SQL queries being excuted in the terminal
app = Flask(__name__)
# ---------- ROUTES ----------
@app.route("/")
def hello_world():
# main index page
return render_template("index.html")
@app.route("/table/<path:table_name>")
def show_table(table_name):
# table_name could be "Schema.Table" or just "Table"
try:
# Validate and split schema/table if schema is provided
if '.' in table_name:
schema, table = table_name.split('.')
full_table = f"{schema}.{table}"
else:
schema = None
table = table_name
full_table = table
# Query to get data from the specified table
query = f"SELECT * FROM {full_table} ORDER BY 1"
with engine.connect() as conn:
result = conn.execute(text(query))
keys = result.keys() # get column names
rows = [dict(zip(keys, row)) for row in result]
if not rows:
return f"No data found in table {full_table}", 404
# Extract columns dynamically from first row keys
columns = [{"data": col, "title": col.capitalize()} for col in rows[0].keys()]
return render_template("tables.html", my_data=rows, my_cols=columns)
except Exception as e:
return f"Error: {str(e)}", 500
<!-- index.html -->
<!DOCTYPE html>
<html>
<body>
<h1>My First Heading</h1>
<p>My First Paragraph</p>
</body>
<html>
<!-- tables.html -->
<!DOCTYPE html>
<html>
<head>
<title>Display IRIS Data with DataTables</title>
<!-- Bootstrap 5 for styling -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- jQuery (required by DataTables) -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<!-- DataTables + Bootstrap 5 integration -->
<link rel="stylesheet" href="https://cdn.datatables.net/1.13.5/css/dataTables.bootstrap5.min.css">
<script src="https://cdn.datatables.net/1.13.5/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/1.13.5/js/dataTables.bootstrap5.min.js"></script>
</head>
<body class="container py-4">
<h2 class="mb-4">IRIS Data Table</h2>
<!-- HTML table to be populated dynamically -->
<table id="myTable" class="table table-bordered table-striped table-hover"></table>
<script>
$(document).ready(function () {
// Convert server-passed JSON strings into JavaScript objects
let my_data = JSON.parse('{{ my_data | tojson | safe }}');
let my_cols = JSON.parse('{{ my_cols | tojson | safe }}');
// Initialize DataTable with server data and column definitions
$('#myTable').DataTable({
data: my_data,
columns: my_cols,
responsive: true,
lengthMenu: [5, 10, 25, 50],
pageLength: 10,
language: {
search: "_INPUT_",
searchPlaceholder: "Search records"
}
});
});
</script>
</body>
</html>