The http Module

Reviewed & published by Brayan K

The http module is Node's built-in toolkit for working with the HyperText Transfer Protocol — it can both make outgoing requests and provide the building blocks (request and response objects, status codes, headers) for receiving them.

Part of the free Node.js course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

This lesson focuses on understanding HTTP and making requests, which is what you'll do most often. We'll keep server creation light and end with a tiny preview, because the very next lesson builds a real server from the ground up.

What You'll Learn in This Lesson

1️⃣ What HTTP Actually Is

HTTP (HyperText Transfer Protocol) is the language clients and servers use to talk over the web. Every interaction is one round trip: a client sends a request, the server sends back a response. Three pieces of vocabulary describe almost everything that happens:

The little script below isn't a network call yet — it just turns that vocabulary into data you can see, so the terms stick before we make a real request.

// HTTP is built from a few simple ideas. Here they are as plain data,
// so the vocabulary sticks before we make any real network calls.

// 1) METHODS describe the *intent* of a request.
const methods = ["GET", "POST", "PUT", "DELETE"];
console.log("Methods:", methods.join(", "));   // -> GET, POST, PUT, DELETE

// 2) STATUS CODES describe how a request *turned out*.
const statuses = { ok: 200, created: 201, notFound: 404, serverError: 500 };
console.log("200 means:", "OK");                // success
console.log("404 means:", "Not Found");         // the resource is missing
console.log("500 means:", "Server Error");      // something broke server-side

// 3) HEADERS are key/value metadata that travel with the request/response.
const headers = { "Content-Type": "application/json" };
console.log("Header:", `Content-Type: ${headers["Content-Type"]}`);

// The full cycle: client SENDS a request (method + path + headers),
// the server SENDS BACK a response (status + headers + body).
console.log(`Cycle: GET /users -> ${statuses.ok} OK`);

2️⃣ Making a Request with fetch

Since Node 18, a global fetch() is built in — the same one you may know from the browser, with no import and no install. It's the modern, recommended way to make outgoing requests. Because the network takes time, fetch returns a Promise, so you await it inside an async function.

There are two awaits, and beginners trip on the second one: await fetch(...) gives you a Response object (status, headers, ok), and a separate await res.json() reads and parses the body. Read the comments closely.

// In Node 18+ a global fetch() is built in — no import, no install.
// fetch returns a Promise, so we await it inside an async function.

async function getUser() {
  // 1) Send the request and wait for the response object.
  const res = await fetch("https://api.example.com/users/1");

  // 2) res.ok is true for 200–299. Always check it before trusting the body.
  if (!res.ok) {
    throw new Error(`Request failed: ${res.status}`);
  }

  // 3) res.json() reads the body stream and parses it — also a Promise.
  const data = await res.json();

  console.log("Status:", res.status);   // -> Status: 200
  console.log("Name:", data.name);      // -> Name: Ada Lovelace

  // For reference, the whole parsed body this example assumes:
  //   { "id": 1, "name": "Ada Lovelace",
  //     "email": "ada@example.com", "active": true }
  // Only the two lines above are printed — the object itself is not, which
  // is why it belongs in a comment rather than in the output panel.
  return data;
}

getUser();

Before fetch existed, you used the http module's own lower-level helpers — http.get(url, cb) for simple GETs and http.request(options, cb) for everything else. They're event-based: you listen for "data" chunks and an "end" event, then assemble the body yourself. They still work and give you fine control, but fetch is far less code for everyday use, so we'll favor it here.

Your turn. The program below works once you fill in the two blanks marked ___. Follow the 👉 hints, then run it and compare with the expected output.

// 🎯 YOUR TURN — replace each ___ then run it (Node 18+).

async function checkStatus() {
  // 1) Send a request to this real, free test endpoint.
  //    fetch returns a Promise, so don't forget to ___ it!
  const res = ___ fetch("https://jsonplaceholder.typicode.com/todos/1");

  // 2) Log the numeric status code the server sent back.
  console.log("Status:", res.___);   // 👉 the property holding 200, 404, etc.

  // ✅ Expected output:
  //    Status: 200
}

checkStatus();

3️⃣ A Tiny Server Preview

The same http module can also receive requests by creating a server. http.createServer(fn) takes a callback that runs once per incoming request, handing you a request object (req) and a response object (res) you write the reply into. This is just a teaser — the next lesson is dedicated to building servers properly.

// A taste of the next lesson: the http module can also CREATE a server.
// createServer takes a callback that runs for every incoming request,
// giving you a request object (req) and a response object (res).
const http = require("node:http");

const server = http.createServer((req, res) => {
  // Set the status code and a header, then end the response with a body.
  res.statusCode = 200;
  res.setHeader("Content-Type", "text/plain");
  res.end("Hello\n");
});

// Start listening on port 3000. We'll go much deeper next lesson.
server.listen(3000, () => {
  console.log("Server running at http://localhost:3000/");
});

Run it, then hit it from another terminal to see the response come back:

# Save the code as server.js and start it:
node server.js
# -> Server running at http://localhost:3000/

# In a second terminal, send it a request with curl:
curl http://localhost:3000/
# -> Hello

Mini-Challenge: Fetch and Report

No blanks this time — just a brief and an outline to keep you on track. Write it yourself, run it on Node 18+, and check your output against the example in the comments. This is the everyday pattern you'll use constantly.

// 🎯 MINI-CHALLENGE: fetch and report
// 1. Write an async function called getTitle().
// 2. await fetch() this URL:
//      https://jsonplaceholder.typicode.com/posts/1
// 3. Check res.ok — if it's false, log "Request failed" and stop.
// 4. Parse the body with await res.json().
// 5. Log the post's title (the data.title field).
//
// ✅ Example output:
//    Status: 200
//    Title: sunt aut facere repellat provident occaecati...

async function getTitle() {
  // your code here
}

getTitle();

Common Errors (and the fix)

Pro Tips

📋 Quick Reference — http & fetch

TaskNode Syntax
Make a requestawait fetch(url)
Parse JSON bodyawait res.json()
Status coderes.status
Succeeded? (2xx)res.ok
Create a serverhttp.createServer(fn)
Low-level GEThttp.get(url, cb)

🎉 Lesson Complete!

Practice quiz

Which HTTP method is typically used to fetch data without changing it?

  • GET
  • POST
  • DELETE
  • PUT

Answer: GET. GET expresses the intent to read or fetch a resource.

What does the HTTP status code 404 mean?

  • OK
  • Server Error
  • Not Found
  • Created

Answer: Not Found. 404 means the requested resource could not be found.

Which status code means a successful request (OK)?

  • 500
  • 404
  • 201
  • 200

Answer: 200. 200 is the standard success status code (OK).

What does res.ok evaluate to for the fetch API?

  • True only for 200 exactly
  • True for status codes 200 through 299
  • True for any response
  • True only for 404

Answer: True for status codes 200 through 299. res.ok is true for any status in the 200-299 range.

In Node 18+, how do you make an HTTP request with the built-in fetch?

  • require('fetch')
  • import fetch from 'node-fetch'
  • fetch is a global — call it directly, no import
  • http.fetch()

Answer: fetch is a global — call it directly, no import. A global fetch() is built in from Node 18+, with no import or install.

Since fetch returns a Promise, how do you get the response inside an async function?

  • You await it
  • You loop over it
  • You call .then().then()
  • You ignore the Promise

Answer: You await it. await pauses for the Promise to resolve to the response object.

Which method parses a JSON response body (and returns a Promise)?

  • res.text()
  • res.json()
  • res.parse()
  • JSON.body()

Answer: res.json(). res.json() reads the body stream and parses it as JSON.

Which call creates an HTTP server from the http module?

  • http.listen()
  • http.newServer()
  • http.serve()
  • http.createServer()

Answer: http.createServer(). http.createServer(callback) returns a server you then call .listen() on.

Inside the createServer callback, what are the two objects you receive?

  • The request (req) and response (res)
  • url and method
  • headers and body
  • socket and port

Answer: The request (req) and response (res). The callback runs per request with (req, res): the request and response objects.

Which method ends a response and sends its body in the http module?

  • res.close()
  • res.write() only
  • res.end()
  • res.send()

Answer: res.end(). res.end(body) finishes the response; res.send() is Express, not core http.

Continue this course

Frequently asked questions

Should I use the built-in fetch or the http module to make requests in Node?

For making outgoing requests, prefer the global fetch() available in Node 18 and later — it's promise-based, concise, and matches the API you already know from the browser. The lower-level http.request and http.get still work and give you fine-grained control over streaming and connection settings, but they use callbacks and events, which are more verbose. Reach for the http module directly when you need to build a server or need that low-level control; otherwise fetch is the simpler choice.

Do I need to install anything to use fetch in Node?

No. Since Node 18, fetch() is a global, just like in the browser — there's no import and no npm install. Check your version with node --version. On Node 16 or older you'd need a package like node-fetch, but on any modern Node you can call fetch() directly.

Why does my fetch return a Response object instead of the data?

fetch resolves to a Response object that describes the reply (its status, headers, and ok flag) but does not yet contain the parsed body. The body arrives as a stream, so you take a second step: await res.json() for JSON, or await res.text() for plain text. Forgetting that second await — or logging res directly — is the most common beginner surprise.

Do I have to worry about CORS in Node like I do in the browser?

No. CORS (Cross-Origin Resource Sharing) is a security rule enforced by web browsers to protect users, not a rule of the HTTP protocol itself. Node is a server-side runtime with no browser sandbox, so fetch() in Node can call any URL without CORS errors. You only deal with CORS when browser JavaScript calls your Node server — and then you configure it on the server's response headers.