Sitemap

Creating a Streamlit Data App With API Data

Ryan Day
5 min readApr 29, 2025

This is part 2 of a series of articles sharing lessons from my new book Hands-on APIs for AI and Data Science, an Amazon #1 New Release from O’Reilly Publishing.

Sample Streamlit plot and Python command to run it

Streamlit is a convenient Python framework for publishing data apps. It allows data scientists with experience in Python to share models, visualizations, and other insights from their data without needing to learn front-end programming.

In Part 1 of this series, I suggested that an effective way to learn about your API user needs is by creating a technical prototype.

A technical prototype is a simple project to explore a limited set of technical questions with a realistic set of tools.

If your users are data scientists, one of the major ways they’ll be using APIs is in data apps, dashboards, and other analytics products. A Streamlit data app is a quick method of using your API with standard Python tools.

Getting Started With Streamlit

Streamlit is one of several popular Python-based data app platforms, along with Gradio, Plotly Dash, and Shiny (which also supports the R language).

You can install Streamlit using pip install -r requirements.txt in your local Python environment. Here’s an example requirements.txt file with the Python you will use for this tutorial:

streamlit>=1.38.0
httpx>=0.27.0
nfl_data_py
matplotlib

Streamlit can create multi-page apps with navigation elements with a small number of Python commands. This diagram shows the components you will use in this tutorial:

Components in this tutorial

Creating an API Client

If the source API provides a software development kit (SDK), you would normally use that in a Python environment. In this tutorial, we’ll assume there is not one available, so you will create a simple client file to keep the API calling code separate from your UI code. You can create a file named simple_api_client.py with the following code:

import logging
import httpx

LIST_TEAMS_ENDPOINT = "/v0/teams/"

logger = logging.getLogger(__name__)

def call_api_endpoint(
base_url: str,
api_endpoint: str,
api_params: dict = None
) -> httpx.Response:

try:
with httpx.Client(base_url=base_url) as client:
logger.debug(f"base_url: {base_url}, api_endpoint: {api_endpoint}, api_params: {api_params}")
response = client.get(api_endpoint, params=api_params)
response.raise_for_status()
logger.debug(f"Response JSON: {response.json()}")
return response
except Exception as e:
logger.error(f"Unexpected error occurred: {str(e)}")
return httpx.Response(status_code=500, content=b"Unexpected error")

Creating the Streamlit Entrypoint Page

The minimal page you can create in a Streamlit app is the entrypoint page, which you’ll name streamlit_football_app.py with the following code (be sure to add the actual URL of the API):

import streamlit as st
import logging

if 'base_url' not in st.session_state:
st.session_state['base_url'] = '[Add API Base URL]'

logging.basicConfig(
filename='football_app.log',
level=logging.INFO,
)
st.set_page_config(page_title="Football App",
page_icon=":material/sports_football:")

page_1 = st.Page("page1.py", title="Team Rosters", icon=":material/trophy:")

page_2 = st.Page("page2.py", title="Team Stats", icon=":material/star_border:")

pg = st.navigation([page_1, page_2])
pg.run()

This will create two sub-pages and create a navigation bar. The Rosters sub-page (named page1.py ) makes the API call with the client, formats a Pandas DataFrame and stores it in the Streamlit session_state object where it can be used by all the sub-pages. A partial listing of the Rosters sub-page code is here (you can get the full code in the repo linked at the bottom):

import streamlit as st
import simple_api_client as swc
import pandas as pd
import logging

logger = logging.getLogger(__name__)

st.header("Streamlit Data App")
st.subheader("Team Rosters Page")

base_url = st.session_state['base_url']

try:
team_api_response = swc.call_api_endpoint(base_url,swc.LIST_TEAMS_ENDPOINT)

if team_api_response.status_code == 200:

team_data = team_api_response.json()

teams_df = pd.DataFrame.from_dict(team_data)

unique_leagues = teams_df['league_id'].unique()
unique_leagues = sorted(unique_leagues.astype(str))

if 'unique_leagues' not in st.session_state:
st.session_state['unique_leagues'] = unique_leagues

selected_league = st.sidebar.selectbox('Pick league ID',unique_leagues)

st.sidebar.divider()
st.sidebar.subheader(":blue[Data sources]")
st.sidebar.text("SportsWorldCentral")

You haven’t run the app yet, but here’s what the Roster sub-page will look like when run:

Navigation bar and Rosters sub-page.

The second sub-page will be named page2.py . It will retrieve the API data that was stored previously in session_state , reformat it, and then merge it with additional NFL data from the nfl_data_py library. Here is a partial code listing (the full code is in the repo below):

flat_team_df_ordered['league_id'] = flat_team_df_ordered[
'league_id'].astype(str)
flat_team_df_ordered = flat_team_df_ordered[
flat_team_df_ordered['league_id'] == selected_league]

nfl_data_2023_df = nfl.import_seasonal_data([2023], 'REG')
columns_to_select = [
'player_id', 'passing_tds', 'rushing_tds', 'receiving_tds']
nfl_data_2023_subset_df = nfl_data_2023_df[columns_to_select].copy()

nfl_data_2023_subset_df['total_tds'] = (
nfl_data_2023_subset_df['passing_tds'] +
nfl_data_2023_subset_df['rushing_tds'] +
nfl_data_2023_subset_df['receiving_tds']
)

merged_df = pd.merge(
flat_team_df_ordered,
nfl_data_2023_subset_df,
how='left',
left_on='gsis_id',
right_on='player_id'
)

grouped_df = merged_df.groupby('team_name')['total_tds'].sum()
fig, ax = plt.subplots()
grouped_df.plot(kind="barh", xlabel='Total TDs',
ylabel="Team Name", title="Total TDs", ax=ax)
st.pyplot(fig)

This code displays the results in a plot using the matplotlib library and Streamlit’s st.pyplot() command. You still haven’t run the app, but her’s what the Stats sub-page will look like when run:

Stats sub-page in Streamlit App

Running Your Streamlit App

The screenshots above show the running app. Here’s where you make that happen. The entrypoint file has the all-important pg.run() command, and here’s how you launch it from the command line:

streamlit run streamlit_football_app.py 

Collecting usage statistics. To deactivate, set browser.gatherUsageStats to false.


You can now view your Streamlit app in your browser.


Local URL: xxx
Network URL: xxx
External URL: xxx

Your app should be available at the addresses listed in the display. Open your web browser to that address, and you’ll see the Rosters sub-page first and the navigation bar to load the Stats sub-page.

Wrapping Up

This is a quick technical prototype that shows you how data scientists may learn to use your API. What did you learn from it? You can see the goals they have to create DataFrames for displaying data or charts and plots to give meaning to it.

You can see the tools they use to consume the API — their method of calling it is not very feature-rich and of course, didn’t address authentication or authorization in this simple demo. To add features like security, error handling, and retry logic, they would appreciate a full-featured SDK they could install along with their other Python libraries.

You can also see that they’re likely to combine with third-party data sources — in this case the nfl_data_py Python library. Providing standard identifiers will make this more practical for them, and will be a valued feature in your API design.

To see the full contents of the Streamlit app in this tutorial and the API it references, visit https://github.com/Ryandaydev/streamlit-data-app.

More articles in this series

Part 1 of this series was Create Technical Prototypes to Understand Your API Consumers. In Part 3, I will be demonstrating a technical prototype using APIs with AI.

For a deeper understanding of building and using APIs with AI and Data Science, please read my new book Hands-on APIs for AI and Data Science, an Amazon #1 New Release from O’Reilly Publishing.

--

--

Ryan Day
Ryan Day

Written by Ryan Day

Data scientist and author of the Amazon #1 new release "Hands-on APIs for AI and Data Science" from O'Reilly Publishing.

No responses yet