Step 8: Test it
Tests prove that the API behaves, and keep proving it as the code changes. Each test makes a request and uses assert to check the status and body. This runnable example tests a tiny API; in your project, put the same checks in todos.test.js and run them with node --test.
const assert = require("assert");
const http = require("http");
// the app under test: a tiny in-memory counter API
const items = [];
const server = http.createServer((req, res) => {
if (req.method === "POST" && req.url === "/items") {
let raw = "";
req.on("data", (c) => (raw += c));
req.on("end", () => {
const body = JSON.parse(raw);
if (!body.name) {
res.writeHead(400);
return res.end(JSON.stringify({ error: "name is required" }));
}
items.push(body.name);
res.writeHead(201);
res.end(JSON.stringify({ count: items.length }));
});
} else {
res.writeHead(404);
res.end("{}");
}
});
const tests = [];
const test = (name, fn) => tests.push({ name, fn });
test("creating an item returns 201 and the new count", async (base) => {
const res = await fetch(base + "/items", { method: "POST", body: JSON.stringify({ name: "a" }) });
assert.strictEqual(res.status, 201);
assert.deepStrictEqual(await res.json(), { count: 1 });
});
test("a missing name is rejected with 400", async (base) => {
const res = await fetch(base + "/items", { method: "POST", body: JSON.stringify({}) });
assert.strictEqual(res.status, 400);
});
test("unknown routes give 404", async (base) => {
const res = await fetch(base + "/nope");
assert.strictEqual(res.status, 404);
});
server.listen(0, async () => {
const base = `http://localhost:${server.address().port}`;
let failed = 0;
for (const t of tests) {
try {
await t.fn(base);
console.log("ok ", t.name);
} catch (err) {
failed++;
console.log("FAIL", t.name, "-", err.message);
}
}
console.log(failed === 0 ? "all tests passed" : failed + " failed");
server.close();
});ok creating an item returns 201 and the new count ok a missing name is rejected with 400 ok unknown routes give 404 all tests passed
The three kinds of test above are the ones to write first for any endpoint: the happy path (it works), bad input (it refuses politely) and not found (unknown things give 404).
You have built a complete REST API: planned routes, JSON bodies, validation, status codes, persistence, a database design and tests. Where next: add authentication (a login route that returns a token), use the express package to cut boilerplate, and deploy it to a hosting service.
Which three cases should you test first for an endpoint?
Finish the quick check (and any code exercise) to complete this lesson, or mark it done yourself.
Tip: use the left and right arrow keys to move between lessons.