JavaScript + Node.js
Node.js is V8 plus a standard library for servers: files, networking, processes, streams. The mental model from Module 06 is the whole story — one thread, an event loop, never block. A Node HTTP server is twelve lines, and every framework (Express, Fastify, Next.js) is a layer over exactly this.
A JSON API with nothing but Node
The request handler runs for every request on the same thread; anything slow must be async. Note the three things every server does: parse the URL, branch on method + path, and write a status, headers and body.
import { createServer } from "node:http"
import { readFile } from "node:fs/promises"
const tasks = [{ id: 1, text: "learn node", done: false }]
const server = createServer(async (req, res) => {
const url = new URL(req.url, `http://${req.headers.host}`)
const json = (status, body) => {
res.writeHead(status, { "Content-Type": "application/json" })
res.end(JSON.stringify(body))
}
if (req.method === "GET" && url.pathname === "/api/tasks") return json(200, tasks)
if (req.method === "POST" && url.pathname === "/api/tasks") {
let body = ""
for await (const chunk of req) body += chunk // the body is a stream
const { text } = JSON.parse(body)
const task = { id: tasks.length + 1, text, done: false }
tasks.push(task)
return json(201, task)
}
if (req.method === "GET" && url.pathname === "/") {
res.writeHead(200, { "Content-Type": "text/html" })
return res.end(await readFile("index.html"))
}
json(404, { error: "not found" })
})
server.listen(3000, () => console.log("http://localhost:3000"))
// node --watch server.js restarts on change
// curl -X POST localhost:3000/api/tasks -H "content-type: application/json" -d '{"text":"ship"}'