Code of the Day
IntermediateExternal Integrations

Lab: API report

Fetch all todos from a public API, aggregate them by user, and write a plain-text summary report — end-to-end practice for the external integrations module.

Lab · optionalWorkflowIntermediate30 min
By the end of this lesson you will be able to:
  • Fetch all items from a paginated public API endpoint
  • Aggregate results by a field (userId) in Python
  • Count completed vs incomplete items per user
  • Write a formatted plain-text summary report

This lab pulls together everything from the external integrations module: making HTTP requests, reading response data, and writing useful output. You will work with the JSONPlaceholder API — a free, public fake API designed for testing. No authentication required.

The endpoint you will use: GET /todos returns 200 todo items across 10 users. Each item looks like this:

{
  "userId": 1,
  "id": 1,
  "title": "delectus aut autem",
  "completed": false
}

Your goal: fetch all 200 items, count how many each user has and how many are completed, then write a formatted report.

Checkpoint 1: Fetch the data

JSONPlaceholder returns all 200 todos in one request — no pagination needed for this exercise. In a production script you would handle pagination (as covered in the previous lesson); here the focus is on the data processing pipeline.

Python — editable, runs in your browser

You should see 200 todos and the structure of the first item. If the count is wrong or the structure has changed, stop here and inspect the raw response before continuing.

Checkpoint 2: Aggregate by user

Now process the list. For each user, count total todos and completed todos:

Python — editable, runs in your browser

Each user has exactly 20 todos (200 total across 10 users). The completed counts will vary. If you see unexpected user IDs or totals, check that the aggregation key matches the field name exactly — "userId", not "user_id".

Checkpoint 3: Write the report

Format the aggregated data and write it to a file. The runner uses io.StringIO to simulate writing without a real filesystem:

Python — editable, runs in your browser

In a production script, replace the io.StringIO buffer with a real file path. The rest of the logic is identical — that is why StringIO is useful for testing the report format before committing to disk.

Putting it all together

Here is the complete script as it would look outside the browser, using requests and writing a real file:

import requests

def fetch_todos():
    response = requests.get("https://jsonplaceholder.typicode.com/todos")
    response.raise_for_status()
    return response.json()

def aggregate(todos):
    stats = {}
    for todo in todos:
        uid = todo["userId"]
        if uid not in stats:
            stats[uid] = {"total": 0, "completed": 0}
        stats[uid]["total"] += 1
        if todo["completed"]:
            stats[uid]["completed"] += 1
    return stats

def write_report(todos, stats, path="todo_report.txt"):
    with open(path, "w") as f:
        f.write("TODO SUMMARY REPORT\n")
        f.write("=" * 40 + "\n")
        f.write(f"Total todos: {len(todos)}\n")
        f.write(f"Users: {len(stats)}\n\n")
        for uid in sorted(stats):
            s = stats[uid]
            incomplete = s["total"] - s["completed"]
            pct = int(100 * s["completed"] / s["total"])
            f.write(f"User {uid:2d}: {s['completed']:2d}/{s['total']} done ({pct}%), {incomplete} remaining\n")
    print(f"Report written to {path}")

def main():
    todos = fetch_todos()
    stats = aggregate(todos)
    write_report(todos, stats)

if __name__ == "__main__":
    main()

Each function has one job. fetch_todos handles the network call. aggregate handles the counting. write_report handles the output. When something breaks — and it will — this structure makes it easy to isolate which step failed.

Where to go next

The next module covers shell and processes — running external commands from Python, capturing their output, and chaining them into pipelines. This is the other major integration surface for automation scripts: the programs already installed on the system.

Finished reading? Mark it complete to track your progress.

On this page