Skip to main content

Command Palette

Search for a command to run...

Creating Routes and Handling Requests with Express

Updated
8 min read
Creating Routes and Handling Requests with Express
H
CS undergrad | Tech enthusiast | Focusing on Web Dev • DSA • ML | Building skills for real-world impact

Raw Node.js HTTP servers work, but they're verbose. You spend time parsing URLs and handling different HTTP methods instead of building your app. Express removes that noise.

This is about how Express simplifies server building and lets you focus on routes and logic.


What Express.js Is

Express is a framework for building web servers in Node.js. It handles routing, middleware, and request/response management so you don't have to.

Without Express (Raw Node.js)

const http = require("http");

const server = http.createServer((req, res) => {
  if (req.method === "GET" && req.url === "/") {
    res.writeHead(200, { "Content-Type": "text/plain" });
    res.end("Home page");
  } else if (req.method === "GET" && req.url === "/about") {
    res.writeHead(200, { "Content-Type": "text/plain" });
    res.end("About page");
  } else {
    res.writeHead(404, { "Content-Type": "text/plain" });
    res.end("Not found");
  }
});

server.listen(3000);

Lots of boilerplate for just two routes.

With Express

const express = require("express");
const app = express();

app.get("/", (req, res) => {
  res.send("Home page");
});

app.get("/about", (req, res) => {
  res.send("About page");
});

app.listen(3000);

Same functionality, much cleaner.


Why Express Simplifies Node.js Development

1. Routing Is Built-In

Express makes routing straightforward:

app.get("/users", (req, res) => {
  // Handle GET /users
});

app.post("/users", (req, res) => {
  // Handle POST /users
});

app.delete("/users/:id", (req, res) => {
  // Handle DELETE /users/123
});

Raw Node.js requires manual URL parsing.

2. Request/Response Helpers

Express provides convenience methods:

res.json({ data: "value" });      // Send JSON
res.send("text response");        // Send text
res.status(404).send("Not found"); // Set status

Raw Node.js requires manual header management.

3. URL Parameters and Query Strings

Automatic parsing:

app.get("/users/:id", (req, res) => {
  const userId = req.params.id;  // From /users/123
});

app.get("/search", (req, res) => {
  const query = req.query.q;  // From /search?q=hello
});

Raw Node.js requires string parsing.


Creating Your First Express Server

Step 1: Install Express

npm install express

Step 2: Create the Server

const express = require("express");
const app = express();

// Your routes here

app.listen(3000, () => {
  console.log("Server running on http://localhost:3000");
});

That's the minimal setup. Just a few lines.

Step 3: Add Routes

const express = require("express");
const app = express();

app.get("/", (req, res) => {
  res.send("Hello, World!");
});

app.listen(3000, () => {
  console.log("Server running on http://localhost:3000");
});

Now your server responds to GET requests at the root path.

Test It

node server.js
# Server running on http://localhost:3000

# In another terminal
curl http://localhost:3000
# Hello, World!

It works immediately.


Request → Route Handler → Response Flow

Browser sends request
  |
  v
Express receives request
  |
  v
Matches URL to a route
  |
  v
Route handler function called
  |
  ├─ req: request object (data from browser)
  └─ res: response object (send data back)
  |
  v
Handler uses res.send() or res.json()
  |
  v
Response sent back to browser
  |
  v
Browser displays it

Each request goes through this cycle.


Handling GET Requests

GET requests retrieve data. They're read-only.

Basic GET Route

app.get("/", (req, res) => {
  res.send("Home page");
});

Visiting the root URL triggers this handler.

GET With URL Parameters

app.get("/users/:id", (req, res) => {
  const userId = req.params.id;
  res.send(`User ID: ${userId}`);
});

// /users/5 → "User ID: 5"
// /users/123 → "User ID: 123"

The :id is a variable in the URL.

GET With Query Strings

app.get("/search", (req, res) => {
  const query = req.query.q;
  res.send(`Searching for: ${query}`);
});

// /search?q=javascript → "Searching for: javascript"

Query strings come after the ?.

Real Example: User Endpoint

const users = [
  { id: 1, name: "Alice" },
  { id: 2, name: "Bob" }
];

app.get("/users", (req, res) => {
  res.json(users);
});

app.get("/users/:id", (req, res) => {
  const user = users.find(u => u.id == req.params.id);
  if (user) {
    res.json(user);
  } else {
    res.status(404).send("User not found");
  }
});

Requests:

  • GET /users → all users
  • GET /users/1 → user 1
  • GET /users/999 → 404

Handling POST Requests

POST requests send data to the server.

Basic POST Route

app.post("/users", (req, res) => {
  res.send("User created");
});

A POST to /users triggers this handler.

POST With Data

Add middleware to parse the body:

const express = require("express");
const app = express();

app.use(express.json());

app.post("/users", (req, res) => {
  const name = req.body.name;
  res.json({ message: "User created", name });
});

Now req.body contains the request data.

Real Example: Creating a Resource

const express = require("express");
const app = express();

app.use(express.json());

let users = [{ id: 1, name: "Alice" }];

app.post("/users", (req, res) => {
  const newUser = {
    id: users.length + 1,
    name: req.body.name
  };
  users.push(newUser);
  res.status(201).json(newUser);
});

Test it:

curl -X POST http://localhost:3000/users \
  -H "Content-Type: application/json" \
  -d '{"name":"David"}'

# Response: {"id":2,"name":"David"}

Sending Responses

Express provides multiple ways to send responses back.

Plain Text

app.get("/text", (req, res) => {
  res.send("Plain text response");
});

JSON

app.get("/json", (req, res) => {
  res.json({ message: "Hello", value: 42 });
});

HTML

app.get("/html", (req, res) => {
  res.send("<h1>Hello World</h1>");
});

With Status Code

app.post("/created", (req, res) => {
  res.status(201).json({ id: 1 });
});

app.get("/not-found", (req, res) => {
  res.status(404).send("Not found");
});

app.get("/error", (req, res) => {
  res.status(500).send("Server error");
});

Status codes tell the browser what happened:

  • 200: OK
  • 201: Created
  • 404: Not found
  • 500: Server error

Redirect

app.get("/old-page", (req, res) => {
  res.redirect("/new-page");
});

Complete Example: Simple API

const express = require("express");
const app = express();

app.use(express.json());

// In-memory data store
let posts = [
  { id: 1, title: "First Post", body: "Hello" },
  { id: 2, title: "Second Post", body: "World" }
];

// GET all posts
app.get("/posts", (req, res) => {
  res.json(posts);
});

// GET one post
app.get("/posts/:id", (req, res) => {
  const post = posts.find(p => p.id == req.params.id);
  if (post) {
    res.json(post);
  } else {
    res.status(404).json({ error: "Post not found" });
  }
});

// CREATE a post
app.post("/posts", (req, res) => {
  const newPost = {
    id: posts.length + 1,
    title: req.body.title,
    body: req.body.body
  };
  posts.push(newPost);
  res.status(201).json(newPost);
});

// UPDATE a post
app.put("/posts/:id", (req, res) => {
  const post = posts.find(p => p.id == req.params.id);
  if (post) {
    post.title = req.body.title || post.title;
    post.body = req.body.body || post.body;
    res.json(post);
  } else {
    res.status(404).json({ error: "Post not found" });
  }
});

// DELETE a post
app.delete("/posts/:id", (req, res) => {
  const index = posts.findIndex(p => p.id == req.params.id);
  if (index !== -1) {
    const deleted = posts.splice(index, 1);
    res.json(deleted[0]);
  } else {
    res.status(404).json({ error: "Post not found" });
  }
});

app.listen(3000, () => {
  console.log("API running on http://localhost:3000");
});

This API handles create, read, update, and delete operations.


Express Routing Structure

app
  |
  ├─ app.get("/path", handler)
  ├─ app.post("/path", handler)
  ├─ app.put("/path", handler)
  ├─ app.delete("/path", handler)
  |
  └─ app.listen(port)

Each route:
  path: URL to match
  handler: function to run
    req: incoming request
    res: outgoing response

Practice Assignment

1. Create a basic server:

const express = require("express");
const app = express();

// Create GET / endpoint that returns "Hello"
// Create GET /about endpoint that returns "About page"

app.listen(3000);

2. Handle URL parameters:

// Create GET /greet/:name that returns "Hello, {name}"
// Example: /greet/alice → "Hello, alice"

3. Handle POST requests:

// Parse JSON
// Create POST /data that receives { message: "..." }
// Return { received: message }

4. Build a simple resource API:

// Create an array of items
// GET /items → return all
// GET /items/:id → return one
// POST /items → create new
// DELETE /items/:id → delete one

Quick Recap

  • Express is a framework for building web servers in Node.js.

  • Routes are defined with app.get(), app.post(), app.put(), app.delete().

  • URL parameters come from req.params.

  • Query strings come from req.query.

  • POST data comes from req.body (with express.json() middleware).

  • Responses are sent with res.send(), res.json(), or res.status().

  • Status codes indicate what happened (200, 201, 404, 500).

  • Express removes boilerplate compared to raw Node.js.

  • A single app.listen() starts the server.

  • Routing in Express is simple and readable.

Express makes building web servers straightforward. Focus on routes and logic, not HTTP boilerplate.


If you enjoyed this article, check out my other blogs on this profile. 🔗 Connect with me: LinkedIn | GitHub | X (Twitter)