Fetch paginated JSON, clean it with pandas, write Parquet and query it with DuckDB, a project you can build in a day. 120 of 122 rows kept, 19.0 KB of JSON down to 5.6 KB of Parquet, and 99 paid vs 21 refunded with no database server.
python3 --version.pip install "pandas>=2.2"pip install "pyarrow>=15"pip install "duckdb>=1.0"git clone https://github.com/DayanEbrar0X/data-anatomy.ai.git cd data-anatomy.ai
python3 -m venv .venv source .venv/bin/activate
pip install -r requirements.txt # or just this lesson: pip install "pandas>=2.2" "pyarrow>=15" "duckdb>=1.0"
cd data-engineering/build-lab-01-api-to-parquet cd orders_pipeline python3 main.py
import duckdb
from pathlib import Path
from fetch import fetch_orders
from transform import clean
PQ = "data/orders.parquet"
rows = fetch_orders()
df = clean(rows)
df.to_parquet(PQ, index=False)
kb = lambda p: Path(p).stat().st_size / 1024
j = sum(kb(p) for p in Path("api").glob("*"))
print(len(rows), "rows fetched,", len(df), "kept")
print(f"JSON {j:.1f} KB -> Parquet {kb(PQ):.1f} KB")
sql = f"SELECT status, count(*) FROM '{PQ}'"
sql += " GROUP BY 1 ORDER BY 1"
print(duckdb.sql(sql).fetchall())This tiny pipeline turns messy API data into a file three times smaller, and instantly queryable. Here's a project you can build in a day. Let's build it. Fetch, clean, write.
Three files. Our source is an orders API. It sends results in pages, forty orders at a time. File one: fetch.
py. We start a list for the rows, and begin on page one. While there's a page, we read it. Here it's a recorded response, so every run is repeatable.
In production, this line is one requests.get call. We add each page's orders, and follow next page until there isn't one. File two: transform.
py. Pandas turns the rows into a table. The API sends amounts as text, so we make them numbers, and timestamps become real dates. The API repeated two orders between pages, so we drop duplicates by order ID.
File three: main.py ties it together. Fetch, clean, and write it as Parquet. Then compare file sizes, and ask DuckDB a question, straight from the file.
Let's run it. 122 rows fetched, 120 kept. 19 KB of JSON became 5.6 KB of Parquet.
Over three times smaller. And DuckDB counts 99 paid and 21 refunded, with no database server. Why Parquet? It stores each column together, typed and compressed.
So Spark, your warehouse, pandas, and DuckDB read only the columns they need. Fetch, clean, write. A real data pipeline, in three files.
Read the lesson on GitHub →