have you ever had a messy Jupyter Notebook stuffed with copy-pasted code simply to re-use some data wrangling logic? Whether you do it for passion or for work, for those who code so much, you then’ve probably answered something like “way too many”.
You’re not alone.
Possibly you tried to share data with colleagues or plugging your latest ML model right into a slick dashboard, but sending CSVs or rebuilding the dashboard from scratch doesn’t feel correct.
Here’s today’s fix (and topic): construct yourself a private API.
On this post, I’ll show you tips on how to arrange a light-weight, powerful FastAPI service to reveal your datasets or models and give your data projects the modularity they deserve.
Whether you’re a solo Data Science enthusiast, a student with side projects, or a seasoned ML engineer, that is for you.
And no, I’m not being paid to advertise this service. It’d be good, but the fact is much from that. I just occur to enjoy using it and I believed it was value being shared.
Let’s review today’s table of contents:
- What’s a private API? (And why do you have to care?)
- Some use cases
- Setting it up with Fastapi
- Conclusion
What Is a Personal API? (And Why Should You Care?)
99% of individuals reading it will already be accustomed to the API concept. But for that 1%, here’s a temporary intro that might be complemented with code in the following sections:
An API (Application Programming Interface) is a algorithm and tools that enables different software applications to speak with one another. It defines what you may ask a program to do, corresponding to “give me the weather forecast” or “send a message.” And that program handles the request behind the scenes and returns the result.
So, what’s a personal API? It’s essentially a small web service that exposes your data or logic in a structured, reusable way. Consider it like a mini app that responds to HTTP requests with JSON versions of your data.
Why would that be idea? For my part, it has different benefits:
- As already mentioned, reusability. We will use it from our Notebooks, dashboards or scripts without having to rewrite the identical code several times.
- Collaboration: your teammates can easily access your data through the API endpoints while not having to duplicate your code or download the identical datasets of their machines.
- Portability: You possibly can deploy it anywhere—locally, on the cloud, in a container, and even on a Raspberry Pi.
- Testing: Have to test a brand new feature or model update? Push it to your API and immediately test across all clients (notebooks, apps, dashboards).
- Encapsulation and Versioning: You possibly can version your logic (v1, v2, etc.) and separate raw data from processed logic cleanly. That’s an enormous plus for maintainability.
And FastAPI is ideal for this. But let’s see some real use cases where anyone such as you and me would profit from a private API.
Some Use Cases
Whether you’re an information scientist, analyst, ML engineer, or simply constructing cool stuff on weekends, a private API can change into your secret productivity weapon. Listed below are three examples:
- Model-as-a-service (MASS): train an ML model locally and expose it to your public through an endpoint like
/predict
. And options from listed here are countless: rapid prototyping, integrating it on a frontend… - Dashboard-ready data: Serve preprocessed, clean, and filtered datasets to BI tools or custom dashboards. You possibly can centralize logic in your API, so the dashboard stays lightweight and doesn’t re-implement filtering or aggregation.
- Reusable data access layer: When working on a project that comprises multiple Notebooks, has it ever happened to you that the primary cells on all of them contain all the time the identical code? Well, what for those who centralized all that code into your API and got it done from a single request? Yes, you would modularize it as well and call a function to do the identical, but creating the API permits you to go one step further, having the ability to use it easily from anywhere (not only locally).
I hope you get the purpose. Options are countless, similar to its usefulness.
But let’s get to the interesting part: constructing the API.
Setting it up with FastAPI
As all the time, start by organising the environment along with your favorite env tool (venv, pipenv…). Then, install fastapi and uvicorn with pip install fastapi uvicorn
. Let’s understand what they do:
- FastAPI[1]: it’s the library that may allow us to develop the API, essentially.
- Uvicorn[2]: it’s what is going to allow us to run the online server.
Once installed, we only need one file. For simplicity, we’ll call it .
Let’s now put some context into what we’ll do: Imagine we’re constructing a sensible irrigation system for our vegetable garden at home. The irrigation system is sort of easy: we now have a moisture sensor that reads the soil moisture with certain frequency, and we would like to activate the system when it’s below 30%.
In fact we would like to automate it locally, so when it hits the brink it starts dropping water. But we’re also serious about having the ability to access the system remotely, possibly reading the present value and even triggering the water pump if we would like to. That’s when the non-public API can turn out to be useful.
Here’s the fundamental code that may allow us to do exactly that (note that I’m using one other library, duckdb[3], because that’s where I might store the info — but you would just use sqlite3, pandas, or whatever you want):
import datetime
from fastapi import FastAPI, Query
import duckdb
app = FastAPI()
conn = duckdb.connect("moisture_data.db")
@app.get("/last_moisture")
def get_last_moisture():
query = "SELECT * FROM moisture_reads ORDER BY day DESC, time DESC LIMIT 1"
return conn.execute(query).df().to_dict(orient="records")
@app.get("/moisture_reads/{day}")
def get_moisture_reads(day: datetime.date, time: datetime.time = Query(None)):
query = "SELECT * FROM moisture_reads WHERE day = ?"
args = [day]
if time:
query += " AND time = ?"
args.append(time)
return conn.execute(query, args).df().to_dict(orient="records")
@app.get("/trigger_irrigation")
def trigger_irrigation():
# This can be a placeholder for the actual irrigation trigger logic
# In a real-world scenario, you'd integrate along with your irrigation system here
return {"message": "Irrigation triggered"}
Reading vertically, this code separates three primary blocks:
- Imports
- Establishing the app object and the DB connection
- Creating the API endpoints
1 and a couple of are pretty straightforward, so we’ll concentrate on the third one. What I did here was create 3 endpoints with their very own functions:
/last_moisture
shows the last sensor value (essentially the most recent one)./moisture_reads/{day}
is helpful to see the sensor reads from a single day. For instance, if I wanted to match moisture levels in winter with those in summer, I might check what’s in/moisture_reads/2024-01-01
and observe the differences with/moisture_reads/2024-08-01
.
But I’ve also made it capable of read GET parameters if I’m serious about checking a particular time. For instance:/moisture_reads/2024-01-01?time=10:00
/trigger_irrigation
would do what the name suggests.
So we’re only missing one part, starting the server. See how easy it’s to run it locally:
uvicorn app:app --reload
Now I could visit:
However it doesn’t end here. FastAPI provides one other endpoint which is present in http://localhost:8000/docs that shows autogenerated interactive documentation for our API. In our case:
It’s extremely useful when the API is collaborative, because we don’t need to envision the code to find a way to see all of the endpoints we now have access to!
And with just a couple of lines of code, only a few in truth, we’ve been capable of construct our personal API. It could possibly obviously get so much more complicated (and doubtless should) but that wasn’t today’s purpose.
Conclusion
With just a couple of lines of Python and the facility of FastAPI, you’ve now seen how easy it’s to reveal your data or logic through a private API. Whether you’re constructing a sensible irrigation system, exposing a machine learning model, or simply uninterested in rewriting the identical wrangling logic across notebooks—this approach brings modularity, collaboration, and scalability to your projects.
And that is only the start. You possibly can:
- Add authentication and versioning
- Deploy to the cloud or a Raspberry Pi
- Chain it to a frontend or a Telegram bot
- Turn your portfolio right into a living, respiratory project hub
When you’ve ever wanted your data work to like an actual product—that is your gateway.
Let me know for those who construct something cool with it. And even higher, send me the URL to your /predict
, /last_moisture
, or whatever API you’ve made. I’d like to see what you provide you with.
Resources
[1] Ramírez, S. (2018). (Version 0.109.2) [Computer software]. https://fastapi.tiangolo.com
[2] Encode. (2018). (Version 0.27.0) [Computer software]. https://www.uvicorn.org
[3] Mühleisen, H., Raasveldt, M., & DuckDB Contributors. (2019). (Version 0.10.2) [Computer software]. https://duckdb.org