Skip to content
    SeaCode
    Learning tracksCode ArenaWorkshops & EventsInstructors
    Log inSign up
    NODENode.js

    Runtime and core tooling

    • What is Node.js?
    • CommonJS and ES modules
    • npm and package.json
    • process and command-line apps

    Async I/O and events

    • Event loop: callbacks to async/await
    • Files and paths with fs/promises
    • EventEmitter
    • Streams and backpressure

    HTTP and APIs

    • Your first HTTP server
    • Routing and JSON bodies
    • Build a tiny router and middleware chain
    • REST: resources and status codes
    • Validation and error handling

    Production: security, testing and deployment

    • Authentication basics with crypto
    • Configuration and environment secrets
    • Testing with assert and node:test
    • API security fundamentals
    • Project: tasks REST API and deployment
    Node.js

    Production: security, testing and deployment · Lesson 18 of 18

    Project: tasks REST API and deployment

    Combine server, routing, validation and tests, then prepare it for Render or Vercel.

    18 minutes2 games

    The capstone is a small in-memory API with GET /tasks and POST /tasks. We separate the handler from listen so tests use a temporary port, validate titles, return correct JSON and statuses, then close the server. Production would replace the array with a database.

    Client

    Router + validation

    Task service

    Database later

    Tests + deploy

    Node.js
    const http = require("node:http")
    const assert = require("node:assert/strict")
    const tasks = []
    const server = http.createServer((req, res) => {
      res.setHeader("content-type", "application/json")
      if (req.method === "GET" && req.url === "/tasks") return res.end(JSON.stringify(tasks))
      if (req.method === "POST" && req.url === "/tasks") {
        let raw = ""
        req.on("data", (chunk) => { raw += chunk })
        req.on("end", () => {
          const body = JSON.parse(raw)
          if (typeof body.title !== "string" || !body.title.trim()) {
            res.statusCode = 422
            return res.end(JSON.stringify({ error: "title required" }))
          }
          const task = { id: tasks.length + 1, title: body.title.trim(), done: false }
          tasks.push(task)
          res.statusCode = 201
          res.end(JSON.stringify(task))
        })
        return
      }
      res.statusCode = 404
      res.end(JSON.stringify({ error: "not found" }))
    })
    server.listen(0, async () => {
      const base = "http://127.0.0.1:" + server.address().port
      const created = await fetch(base + "/tasks", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ title: "Learn Node" }) })
      assert.equal(created.status, 201)
      const listed = await fetch(base + "/tasks")
      assert.deepEqual(await listed.json(), [{ id: 1, title: "Learn Node", done: false }])
      console.log("all tests passed")
      server.close()
    })

    Render runs a long-lived Node service: bind to 0.0.0.0 and process.env.PORT, and configure a health check. Vercel serverless suits short stateless handlers; never call listen inside the function. Both need dashboard-managed environment variables, logs, timeouts and storage beyond process memory.

    Terminal
    # Typical long-running service
    npm ci
    npm test
    PORT=3000 node server.js
    
    # On SIGTERM: stop accepting traffic, finish requests, close DB, then exit
    # Platform settings hold secrets; never commit .env

    Important

    The array disappears on restart and fails across multiple instances. Before real traffic add a database and migrations, auth and authorization, body limits, rate limiting, structured logs, metrics, graceful shutdown, backups and rollback. Deployment is not the end of testing.

    Quick question

    Why are in-memory tasks unsuitable for production?

    Interview question

    How do you gracefully shut down a Node API?

    Exercise

    Complete a store: create(title) adds a task with an increasing id and list() returns a copy. Test it and print all tests passed.

    Expected output: all tests passed

    Node.js
    const assert = require("node:assert/strict")
    function makeStore() {
      const tasks = []
      return {
        create(title) {
    
        },
        list() {
    
        }
      }
    }
    const store = makeStore()
    store.create("Learn Node")
    assert.deepEqual(store.list(), [{ id: 1, title: "Learn Node", done: false }])
    console.log("all tests passed")

    Learn more from

    • Render Docs: Deploy Node Express apprender.com
    • Vercel Docs: Node.js runtimevercel.com
    • Node.js: HTTPnodejs.org

    Played 0 of 2 games

    Sign in to save your progress and earn XP.

    PreviousAPI security fundamentals🎉 خلّصت Node.js!
    SeaCode

    Learn to code for real, online or at our branch in front of Cairo University, Giza.

    Learn

    • All courses
    • Interactive tutorials
    • Interview practice problems
    • Mock interview
    • Learning tracks
    • Code Arena
    • Workshops & Events
    • Knowledge library
    • Team projects

    Your account

    • Log in
    • Sign up
    • Learning plan
    • Certificates
    • Site map

    Contact us

    • WhatsApp
    • 010 9094 1104
    • In front of Cairo University, Giza

    © 2026 SeaCode. All rights reserved.