A minimal clone of the public‑apis list using Python, FastAPI, and SQLite
Welcome to another official UVF IT guide! In this quick build you’ll create a tiny web service that serves a curated list of public APIs, inspired by the massive public‑apis repository. We’ll use FastAPI for the HTTP layer and SQLite for storage – all free and runnable on your laptop in under an hour.
The end result is a searchable JSON endpoint (/apis) that mimics the core experience of the original directory without any paid keys or external services. Perfect for learning REST basics, ORMs, and rapid prototyping.
git installed; older versions may miss type hints used by FastAPI.uvicorn extra flags for reloading; the commands below work on macOS/Linux as shown.Create a fresh directory for the clone, spin up an isolated Python virtual environment, and pull in the three core libraries: FastAPI for routing, Uvicorn as the ASGI server, and SQLModel to talk to SQLite. This gives us a clean, reproducible starting point.
All commands are written for Unix‑like shells; Windows users can run them in PowerShell with minor path tweaks.
mkdir public_api_clone && cd public_api_clone
python3 -m venv venv
source venv/bin/activate
pip install --upgrade pip
pip install fastapi uvicorn sqlmodelWe declare an API table using SQLModel, which blends Pydantic validation with SQLAlchemy ORM features. The model captures the fields we care about: name, description, auth method, HTTPS support, and a link.
After defining the table we create the SQLite file (if it doesn’t exist) and insert a handful of sample entries so the /apis endpoint has data to return immediately.
models.py
from sqlmodel import SQLModel, Field, create_engine, Session
class API(SQLModel, table=True):
id: int = Field(default=None, primary_key=True)
name: str
description: str
auth: str | None = None
https: bool = False
link: str
engine = create_engine("sqlite:///apis.db")
SQLModel.metadata.create_all(engine)
def seed_db():
sample = [
API(name="Cat Facts", description="Random cat facts", auth=None, https=True, link="https://catfact.ninja"),
API(name="Dog CEO", description="Random dog images", auth=None, https=True, link="https://dog.ceo/api/breeds/image/random"),
API(name="OpenWeather", description="Weather data", auth="apiKey", https=True, link="https://api.openweathermap.org")
]
with Session(engine) as session:
for api in sample:
session.add(api)
session.commit()
if __name__ == "__main__":
seed_db()In this step we wire up the HTTP layer that will serve our stored API entries. We'll create a single GET endpoint that returns every record, and optionally narrows the list when a category query parameter is supplied. FastAPI makes request parsing and response serialization effortless, so the code stays tiny and readable.
The endpoint pulls data from the SQLite database using SQLModel's session helpers. If a category is provided we add a simple filter clause; otherwise we fetch all rows. The result is automatically turned into JSON thanks to FastAPI's built‑in Pydantic models.
main.py
from fastapi import FastAPI, Query
from sqlmodel import Field, Session, SQLModel, create_engine, select
class ApiEntry(SQLModel, table=True):
id: int = Field(default=None, primary_key=True)
name: str
description: str
auth: str | None = None
https: bool = False
cors: str | None = None
link: str
category: str
engine = create_engine("sqlite:///apis.db")
SQLModel.metadata.create_all(engine)
app = FastAPI(title="Simple Public API Directory")
@app.get("/apis")
def read_apis(category: str | None = Query(default=None, description="Filter by category")):
with Session(engine) as session:
stmt = select(ApiEntry)
if category:
stmt = stmt.where(ApiEntry.category == category)
results = session.exec(stmt).all()
return resultsNow that the API code is ready, we launch the development server so we can interact with it in a browser or via curl. Uvicorn is the recommended ASGI server for FastAPI and provides hot‑reload, which is handy while we iterate.
After the server starts, visiting http://127.0.0.1:8000/apis should return a JSON array of the seed entries we inserted earlier. If everything looks good, we can move on to verifying the optional filter.
uvicorn main:app --reloadWith the server running, we confirm that the endpoint returns the expected data. A quick curl request (or opening the URL in a browser) should display a JSON list containing the two sample APIs we seeded.
Next, we test the category filter by adding ?category=Weather to the query string. Only entries whose category matches the supplied value should appear, proving that our filtering logic works. From here you can add more records, expand the schema, or create POST/PUT endpoints for full CRUD support.
# Verify all entries
curl http://127.0.0.1:8000/apis
# Verify category filter (example: Weather)
curl "http://127.0.0.1:8000/apis?category=Weather"| Check | Command / Why it matters |
|---|---|
| Dependencies install without errors | pip install fastapi uvicorn[standard] sqlmodel → no traceback |
| Server starts | uvicorn main:app --reload → prints Uvicorn running on http://127.0.0.1:8000 |
| /apis returns JSON array | curl http://127.0.0.1:8000/apis → shows two objects |
| Category filter works | curl 'http://127.0.0.1:8000/apis?category=Weather' → only OpenWeather entry |
Your tiny public‑API directory is live locally. Push the folder to GitHub, share the URL, or deploy to a free host like Railway or Render for the world to explore.