05 — Async seed with fetch
Goal
Add seedTodos — an async function that fetches three sample todos from a public API using Node's built-in global fetch (available since Node 18, so Node 26 already has it). No package installs needed.
The public API
JSONPlaceholder is a free, keyless, read-only REST API for testing. The endpoint:
https://jsonplaceholder.typicode.com/todos?_limit=3returns an array like:
json
[
{ "userId": 1, "id": 1, "title": "delectus aut autem", "completed": false },
{ "userId": 1, "id": 2, "title": "quis ut nam facilis ...", "completed": false },
{ "userId": 1, "id": 3, "title": "fugiat veniam minus", "completed": false }
]Add seedTodos
js
// todo.js — add below pendingTodos (Node 18+/26 has a global fetch)
async function seedTodos() {
const res = await fetch(
"https://jsonplaceholder.typicode.com/todos?_limit=3",
);
const data = await res.json();
return data.map((d) => ({ text: d.title, done: d.completed }));
}Two await calls:
await fetch(url)— waits for the HTTP response headers.await res.json()— waits for the body to be fully read and parsed as JSON.
The .map reshapes each item to the todo shape { text, done } the rest of the module expects.
Updated module.exports
js
module.exports = {
readTodos, writeTodos, addTodo, completeTodo, removeTodo, pendingTodos,
seedTodos, formatList,
};Checkpoint
bash
node -e "require('./todo').seedTodos().then(t => console.log(t.length))"Expected output: 3
(Requires a live internet connection. JSONPlaceholder is always available.)
How async/await works here
seedTodos is marked async, so it always returns a Promise. Callers use .then() or await to get the resolved value:
js
// .then() style (used in cli.js)
seedTodos().then((seeded) => {
writeTodos(FILE, seeded);
console.log(`Seeded ${seeded.length} todos`);
});
// await style (inside another async function)
const seeded = await seedTodos();Both do the same thing; the CLI uses .then() so it doesn't need a top-level async wrapper.