# Understanding HTTP Requests, Responses, and HTTP Methods using Node.js

When building backend applications, one of the most fundamental concepts to understand is **how clients communicate with servers**.

This communication happens using the **HTTP**.

In this blog, we will learn:

*   What **HTTP Request** is
    
*   What **HTTP Response** is
    
*   What **HTTP Methods** are
    
*   How to implement them using **Node.js**
    
*   How to test them using **Postman**
    

We will build a simple **Todo backend server** using the Node.js **http module**.

* * *

## <mark class="bg-yellow-200 dark:bg-yellow-500/30">1. Understanding HTTP Request</mark>

An **HTTP request** is sent by the **client (**(browser, mobile app, or tools like **Postman)** to the server asking it to perform some action.

A request contains:

| Component | Description |
| --- | --- |
| Method | Specifies the action to perform (GET, POST, DELETE, etc.) |
| URL | The resource or endpoint the client wants to access |
| Headers | Additional metadata about the request |
| Query Parameters | Extra data passed in the URL |
| Body | The main data sent to the server (mostly used in POST/PUT/PATCH requests) |

**1\. HTTP Method**

The **method** tells the server what operation the client wants to perform.

Example:

```javascript
GET /todos
POST /create/todo
DELETE /todo?id=1
```

Common HTTP methods include:

*   GET → Fetch data
    
*   POST → Create new data
    
*   PUT → Replace data
    
*   PATCH → Update part of data
    
*   DELETE → Remove data
    

These methods are part of the **HTTP**.

* * *

**2\. URL (Endpoint)**

The **URL** identifies the resource the client wants.

Example:

```javascript
http://localhost:3000/todos
```

Here:

*   `http` → protocol
    
*   `localhost:3000` → server
    
*   `/todos` → endpoint
    

* * *

**3\. Headers**

Headers provide **extra information about the request**.

Example headers:

```javascript
Content-Type: application/json
Authorization: Bearer token
User-Agent: PostmanRuntime
```

Common headers:

| Header | Purpose |
| --- | --- |
| Content-Type | Type of data sent |
| Authorization | Authentication token |
| Accept | Expected response format |

* * *

**4\. Query Parameters**

Query parameters send **additional information through the URL**.

Example:

```javascript
GET /todo?id=1
```

Here:

```javascript
id=1
```

is the query parameter.

In Node.js we read it like this:

```javascript
const urlData = url.parse(req.url, true);
const todoId = urlData.query.id;
```

* * *

**5\. Request Body**

The **body contains the main data sent by the client to the server**.

It is mostly used with:

*   POST
    
*   PUT
    
*   PATCH
    

Example JSON body:

```javascript
{
 "title": "Write Blog",
 "description": "Explain HTTP methods"
}
```

This data is used by the server to **create or update resources**.

In **Node.js**, the request body arrives as **chunks (streams)**, so we must collect them before converting them to JSON.

Example:

```plaintext
const bodyStream = [];

req.on("data", (chunk) => {
  bodyStream.push(chunk);
});

req.on("end", () => {
  const body = JSON.parse(Buffer.concat(bodyStream).toString());
});
```

* * *

## <mark class="bg-yellow-200 dark:bg-yellow-500/30">2. Understanding HTTP Response</mark>

An **HTTP response** is what the server sends back after processing the request.

A response tells the client:

*   Whether the request succeeded or failed
    
*   What data is being returned
    
*   Additional information about the response
    

A typical HTTP response contains the following components.

| Component | Description |
| --- | --- |
| Status Code | Indicates success or failure |
| Response Headers | Metadata about the response |
| Body | The actual data returned |

**1\. Status Code**

The **status code** tells the client whether the request succeeded or failed.

Common status codes:

| Code | Meaning |
| --- | --- |
| 200 | Request successful |
| 201 | Resource created |
| 400 | Bad request |
| 401 | Unauthorized |
| 404 | Resource not found |
| 500 | Internal server error |

Example in **Node.js**:

```plaintext
res.statusCode = 200;
```

* * *

**2\. Response Headers**

Response headers provide **extra information about the response**.

Example:

```plaintext
Content-Type: application/json
Content-Length: 120
Cache-Control: no-cache
```

Common response headers:

| Header | Purpose |
| --- | --- |
| Content-Type | Type of data returned |
| Content-Length | Size of response body |
| Cache-Control | Controls caching |
| Set-Cookie | Stores cookies in browser |

Example in Node.js:

```javascript
res.setHeader("Content-Type", "application/json");
```

* * *

**3\. Response Body**

The **response body** contains the actual data returned by the server.

Example JSON response:

```javascript
{
 "id": 1,
 "title": "Write Blog",
 "description": "Explain HTTP response"
}
```

Example in Node.js:

```javascript
res.end(JSON.stringify(data));
```

* * *

## <mark class="bg-yellow-200 dark:bg-yellow-500/30">3. HTTP Methods Explained</mark>

HTTP methods define **what operation the client wants to perform**.

The most common methods are:

| Method | Purpose |
| --- | --- |
| GET | Retrieve data |
| POST | Create new data |
| PUT | Replace existing data |
| PATCH | Update part of data |
| DELETE | Remove data |

* * *

## <mark class="bg-yellow-200 dark:bg-yellow-500/30">4. Setting Up the Node.js HTTP Server</mark>

We will use Node's built-in **http module**.

```javascript
const http = require("http");
const url = require("url");
```

* * *

## <mark class="bg-yellow-200 dark:bg-yellow-500/30">5. Creating the HTTP Server</mark>

```javascript
const server = http.createServer((req, res) => {

});
```

This callback receives two important objects:

| Object | Description |
| --- | --- |
| `req` | Represents the **HTTP request** sent by the client |
| `res` | Represents the **HTTP response** that the server will send back |

### `req` — Request Object

The `req` object contains all the information about the incoming request from the client.

Using this object, we can access:

*   The HTTP method (`req.method`)
    
*   The request URL (`req.url`)
    
*   Request headers (`req.headers`)
    
*   Request body (via stream events - I explained below)
    

### `res` — Response Object

The `res` object is used to send a response back to the client.

With this object we can:

*   Set the **status code**
    
*   Set **response headers**
    
*   Send the **response body**
    

Example:

```javascript
res.statusCode = 200;
res.setHeader("Content-Type", "text/plain");
res.end("Hello World");
```

Here:

*   `statusCode` tells the client whether the request was successful.
    
*   `setHeader()` sends metadata about the response.
    
*   `res.end()` sends the final response body and completes the request.
    

* * *

## <mark class="bg-yellow-200 dark:bg-yellow-500/30">6. GET Method Example</mark>

In HTTP, the **GET method** is used to **retrieve data from the server** without modifying anything on the server.

In this example, when a client sends a request to the **root route** `/`, the server returns a simple response: `"Hello World"`.

### Code Example

```javascript
const http = require("http");
const url = require("url");

const server = http.createServer((req, res) => {
  const urlData = url.parse(req.url, true);

  if (urlData.pathname === "/" && req.method === "GET") {
    res.statusCode = 200;
    res.setHeader("Content-Type", "text/plain");
    return res.end("Hello World");
  }
});
```

* * *

### Step-by-Step Explanation of Above Code

**1\. Importing Required Modules**

```javascript
const http = require("http");
const url = require("url");
```

Here we import two built-in modules from **Node.js**:

| Module | Purpose |
| --- | --- |
| `http` | Used to create the HTTP server |
| `url` | Helps parse the request URL and query parameters |

* * *

**2\. Creating the HTTP Server**

```javascript
const server = http.createServer((req, res) => {

});
```

`createServer()` creates a server that listens for incoming requests.

The callback function runs **every time a client sends a request**.

It receives two objects:

| Object | Description |
| --- | --- |
| `req` | Contains information about the incoming request |
| `res` | Used to send the response back to the client |

* * *

**3\. Parsing the Request URL**

```javascript
const urlData = url.parse(req.url, true);
```

Here we parse the request URL so we can easily access different parts of it.

Example request:

```javascript
http://localhost:3000/
```

After parsing:

| Property | Value |
| --- | --- |
| `urlData.pathname` | `/` |
| `urlData.query` | `{}` |

This helps us determine **which route the client is requesting**.

* * *

**4\. Checking Route and HTTP Method**

```javascript
if (urlData.pathname === "/" && req.method === "GET")
```

Here we check two things:

| Condition | Purpose |
| --- | --- |
| `urlData.pathname === "/"` | Client requested the root route |
| `req.method === "GET"` | Client used the GET HTTP method |

Both conditions must be true for this block to execute.

* * *

**5\. Setting the Status Code**

```javascript
res.statusCode = 200;
```

The **status code** `200` means:

> The request was successful.

* * *

**6\. Setting Response Headers**

```javascript
res.setHeader("Content-Type", "text/plain");
```

This header tells the client:

> The response body contains **plain text**.

* * *

**7\. Sending the Response**

```javascript
return res.end("Hello World");
```

`res.end()`:

*   Sends the response body
    
*   Ends the response
    

So the client receives:

```plaintext
Hello World
```

* * *

### Testing This Route

You can test this using **Postman**.

### Request

Method:

```javascript
GET
```

URL:

```javascript
http://localhost:3000/
```

### Response

```javascript
Hello World
```

Status Code:

```plaintext
200 OK
```

* * *

### Request–Response Flow

```plaintext
Client (Browser/Postman)
        │
        │  GET /
        ▼
Server
        │
        │  200 OK
        │  Hello World
        ▼
Client
```

* * *

## <mark class="bg-yellow-200 dark:bg-yellow-500/30">7. POST Method Example</mark>

```plaintext
POST /create/todo
```

The **POST method** is used to **send data from the client to the server in order to create a new resource**.

In this example, we will create a new **Todo item** by sending `title` and `description` in the request body.

* * *

### Code Example

```javascript
if (urlData.pathname === "/create/todo" && req.method === "POST") {
  const bodyStream = [];

  req.on("data", (chunk) => {
    bodyStream.push(chunk);
  });

  req.on("end", () => {
    let body;

    try {
      body = JSON.parse(Buffer.concat(bodyStream).toString());
    } catch {
      res.statusCode = 400;
      return res.end(JSON.stringify({ error: "Invalid JSON" }));
    }


    res.statusCode = 200;
    res.setHeader("Content-Type", "application/json");
    res.end(JSON.stringify(body));
  });
}
```

**1\. Checking Route and HTTP Method**

```javascript
if (urlData.pathname === "/create/todo" && req.method === "POST")
```

This ensures that the server processes the request **only when**:

*   The request is sent to the correct **endpoint**
    
*   The HTTP **method is POST**
    

This is important because the same server may handle **multiple routes and methods**.

* * *

**2\. Creating a Container for Request Body**

```javascript
const bodyStream = [];
```

In Node.js, the request body is received as a **stream of data**, not as a single object.

So we create an array to temporarily **store incoming chunks of data**.

* * *

**3\. Listening for Incoming Data**

```javascript
req.on("data", (chunk) => {
  bodyStream.push(chunk);
});
```

Here we listen for the `data` **event**.

Every time part of the request body arrives:

*   Node.js emits a **data event**
    
*   The `chunk` variable contains a **small piece of the request body**
    
*   We store each chunk inside the `bodyStream` array
    

This happens because request bodies are streamed for **better performance and memory usage**.

* * *

**4\. Detecting When the Request Body Is Complete**

```javascript
req.on("end", () => {
```

The `end` **event** is triggered when **all chunks of the request body have been received**.

Only after this event fires can we safely process the full request body.

* * *

**5\. Combining All Chunks**

```javascript
Buffer.concat(bodyStream).toString()
```

This step converts the collected chunks into a readable string.

Explanation:

| Step | Purpose |
| --- | --- |
| `Buffer.concat(bodyStream)` | Combines all chunks into a single buffer |
| `.toString()` | Converts the buffer into a readable string |

Example result:

```plaintext
{"title":"Write Blog","description":"Explain HTTP methods"}
```

* * *

**6\. Converting the String to JSON**

```javascript
body = JSON.parse(Buffer.concat(bodyStream).toString());
```

Most APIs send request bodies in **JSON format**, so we convert the string into a JavaScript object.

Example result:

```javascript
{
  title: "Write Blog",
  description: "Explain HTTP methods"
}
```

Now we can access values like:

```javascript
body.title
body.description
```

**7\. Handling Invalid JSON**

```javascript
try {
  body = JSON.parse(...)
} catch {
  res.statusCode = 400;
  return res.end(JSON.stringify({ error: "Invalid JSON" }));
}
```

If the client sends **invalid JSON**, `JSON.parse()` will throw an error.

Using `try...catch` prevents the server from crashing and returns a proper **400 Bad Request response**.

* * *

**8\. Sending the Response**

```javascript
res.statusCode = 200;
res.setHeader("Content-Type", "application/json");
res.end(JSON.stringify(body));
```

Here we send the response back to the client.

| Line | Purpose |
| --- | --- |
| `statusCode = 200` | Indicates request was successful |
| `Content-Type` | Specifies response format |
| `res.end()` | Sends the response and ends the request |

In this example, the server simply **returns the parsed request body**.

* * *

### Key Takeaway

When using the Node.js `http` module to handle POST requests, we must manually:

1.  Listen for incoming data chunks
    
2.  Store them in a container
    
3.  Detect when all data has arrived
    
4.  Combine the chunks
    
5.  Convert the body into JSON
    

Frameworks like **Express.js** handle these steps automatically, but understanding this process helps developers see **how HTTP body parsing works internally**.

* * *

## <mark class="bg-yellow-200 dark:bg-yellow-500/30">Let's Build a Complete Todo Backend (Node.js HTTP Module)</mark>

Now Let's Create a basic Todo backend server that can handle different HTTP methods and routes.

### **Requirements**

### 1\. `POST /create/todo`

*   Read JSON body containing:
    
    *   `title`
        
    *   `description`
        
*   Create a new Todo
    
*   Assign an **auto-incremented ID** (starting from 1)
    
*   Return the **updated list of all todos**
    

### 2\. `GET /todos`

*   Return all todos
    
*   Response should be in **JSON format**
    

### 3\. `GET /todo?id=XXX`

*   Return a **single todo** based on ID
    
*   If todo does not exist:
    
    *   Return `404`
        
    *   Response:
        

```json
{ "error": "Todo not found" }
```

### 4\. `DELETE /todo?id=XXX`

*   Delete a todo based on ID
    
*   If successful:
    
    *   Return `200`
        
*   If ID does not exist:
    
    *   Return `404`
        
    *   Response:
        

```json
{ "error": "Todo not found" }
```

## 📌 Full Implementation

```javascript
const http = require("http");
const url = require("url");

let todos = [];
let currentId = 1;

const server = http.createServer((req, res) => {
  const urlData = url.parse(req.url, true);
  const { pathname, query } = urlData;

  // Helper to send JSON response
  const sendJSON = (status, data) => {
    res.statusCode = status;
    res.setHeader("Content-Type", "application/json");
    res.end(JSON.stringify(data));
  };

  // Root Route
  if (pathname === "/" && req.method === "GET") {
    res.statusCode = 200;
    res.setHeader("Content-Type", "text/plain");
    return res.end("Hello World");
  }

  // Create Todo
  if (pathname === "/create/todo" && req.method === "POST") {
    const bodyStream = [];

    req.on("data", (chunk) => {
      bodyStream.push(chunk);
    });

    req.on("end", () => {
      let body;

      try {
        body = JSON.parse(Buffer.concat(bodyStream).toString());
      } catch {
        return sendJSON(400, { error: "Invalid JSON" });
      }

      const newTodo = {
        id: currentId++,
        title: body.title,
        description: body.description,
      };

      todos.push(newTodo);

      return sendJSON(200, todos);
    });

    return;
  }

  // Get All Todos
  if (pathname === "/todos" && req.method === "GET") {
    return sendJSON(200, todos);
  }

  // Get Single Todo
  if (pathname === "/todo" && req.method === "GET") {
    const id = parseInt(query.id);

    if (!id) {
      return sendJSON(404, { error: "Todo not found" });
    }

    const todo = todos.find((t) => t.id === id);

    if (!todo) {
      return sendJSON(404, { error: "Todo not found" });
    }

    return sendJSON(200, todo);
  }

  // Delete Todo
  if (pathname === "/todo" && req.method === "DELETE") {
    const id = parseInt(query.id);

    if (!id) {
      return sendJSON(404, { error: "Todo not found" });
    }

    const index = todos.findIndex((t) => t.id === id);

    if (index === -1) {
      return sendJSON(404, { error: "Todo not found" });
    }

    todos.splice(index, 1);

    return sendJSON(200, { message: "Todo deleted" });
  }

  // Handle Unknown Routes
  res.statusCode = 404;
  res.setHeader("Content-Type", "application/json");
  res.end(JSON.stringify({ error: "Route not found" }));
});

server.listen(3000, () => {
  console.log("Server running on port 3000");
});
```

* * *

## <mark class="bg-yellow-200 dark:bg-yellow-500/30">Final Thoughts</mark>

Understanding HTTP at this level helps developers understand **how frameworks like Express actually work internally**.

By building a server using the core **http module**, we gain a deeper understanding of:

*   Request streams
    
*   Response handling
    
*   Routing
    
*   HTTP methods
    

Once you understand this, frameworks like Express become much easier to work with.
