Skip to content
Laviyx Learn

Try

Node.js and Express course menu

Express.js Tutorial: Your First Express Server

Get started with Express 5: installing it, creating an app, defining GET and POST routes, sending text and JSON, reading route and query parameters and JSON bodies, the 404 response, and running the server with node --watch.

Intermediate9 min readUpdated
On this page

Express is the most widely used web framework for Node.js. It keeps the speed and flexibility of Node's http module while removing the repetitive work: routing, parsing request bodies, sending JSON, and organising code with middleware. The examples in this course use Express 5 (version 5.3.0 when this was written).

Install#

In a project folder with a package.json set to "type": "module":

Terminal
npm install express

Hello, Express#

app.js (JavaScript)
import express from "express";

const app = express();
const PORT = 3000;

app.get("/", (req, res) => {
  res.send("Welcome to the ShopKart API");
});

app.get("/api/health", (req, res) => {
  res.json({ status: "ok", service: "shopkart-api" });
});

app.listen(PORT, () => console.log(`Server running at http://localhost:${PORT}`));
Terminal
node app.js
Output
Server running at http://localhost:3000
Terminal
curl -s localhost:3000/
curl -s localhost:3000/api/health
Output
Welcome to the ShopKart API
{"status":"ok","service":"shopkart-api"}

Compared with the plain http server:

  • app.get(path, handler) registers a route for one method and path; Express matches requests for you.
  • res.send() sends text (or HTML), sets Content-Type and ends the response.
  • res.json() converts data to JSON and sets Content-Type: application/json.
  • Requests that match no route get an automatic 404 response.

During development, run node --watch app.js so the server restarts whenever you save.

Route parameters and query strings#

params.js (JavaScript)
import express from "express";

const app = express();
const products = [
  { id: 1, name: "Notebook", category: "stationery", price: 60 },
  { id: 2, name: "Gel pen", category: "stationery", price: 25 },
  { id: 3, name: "Backpack", category: "bags", price: 1299 },
];

// /api/products?category=stationery&maxPrice=50
app.get("/api/products", (req, res) => {
  const { category, maxPrice } = req.query;
  let result = products;
  if (category) result = result.filter((p) => p.category === category);
  if (maxPrice) result = result.filter((p) => p.price <= Number(maxPrice));
  res.json(result);
});

// /api/products/3
app.get("/api/products/:id", (req, res) => {
  const product = products.find((p) => p.id === Number(req.params.id));
  if (!product) return res.status(404).json({ error: "Product not found" });
  res.json(product);
});

app.listen(3000);
Terminal
curl -s "localhost:3000/api/products?category=stationery"
curl -s "localhost:3000/api/products?category=stationery&maxPrice=50"
curl -s localhost:3000/api/products/3
curl -s localhost:3000/api/products/42
Output
[{"id":1,"name":"Notebook","category":"stationery","price":60},{"id":2,"name":"Gel pen","category":"stationery","price":25}]
[{"id":2,"name":"Gel pen","category":"stationery","price":25}]
{"id":3,"name":"Backpack","category":"bags","price":1299}
{"error":"Product not found"}
  • req.params holds the named parts of the path (:id), always as strings.
  • req.query holds the query string as an object of strings.
  • res.status(404).json(...) sets the status code before sending; chainable methods keep it on one line.

Receiving JSON#

Express does not read request bodies unless you ask it to. express.json() is middleware that parses JSON bodies into req.body:

post.js (JavaScript)
import express from "express";

const app = express();
app.use(express.json());

const messages = [];

app.post("/api/messages", (req, res) => {
  const { name, text } = req.body;
  if (!name || !text) {
    return res.status(400).json({ error: "name and text are required" });
  }
  const message = { id: messages.length + 1, name, text, createdAt: "2026-10-25" };
  messages.push(message);
  res.status(201).json(message);
});

app.get("/api/messages", (req, res) => res.json(messages));

app.listen(3000);
Terminal
curl -s -X POST localhost:3000/api/messages -H "Content-Type: application/json" -d '{"name":"Asha","text":"Is the backpack waterproof?"}'
curl -s -X POST localhost:3000/api/messages -H "Content-Type: application/json" -d '{"name":"Ravi"}'
curl -s localhost:3000/api/messages
Output
{"id":1,"name":"Asha","text":"Is the backpack waterproof?","createdAt":"2026-10-25"}
{"error":"name and text are required"}
[{"id":1,"name":"Asha","text":"Is the backpack waterproof?","createdAt":"2026-10-25"}]

(A fixed createdAt keeps the example's output repeatable; a real app would use new Date().toISOString().)

201 Created is the right status for a successfully created resource. The data lives in memory, so it disappears when the server restarts; the database lesson fixes that.

What happens with unknown routes#

Terminal
curl -s localhost:3000/api/unknown
Output
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Cannot GET /api/unknown</pre>
</body>
</html>

Express's default 404 response is a small HTML page. APIs usually replace it with a JSON response, as the error handling lesson shows.

Common mistakes#

Practice#

Practice exercise

Build an Express app with GET /api/convert?km=5 that returns { "km": 5, "miles": 3.11 } (1 km = 0.621371 miles, rounded to 2 decimals), and a 400 response with an error message when km is missing or not a number.

Show hint

const km = Number(req.query.km); then check req.query.km === undefined || Number.isNaN(km).

Show solution
convert.js (JavaScript)
import express from "express";

const app = express();

app.get("/api/convert", (req, res) => {
  const km = Number(req.query.km);
  if (req.query.km === undefined || Number.isNaN(km)) {
    return res.status(400).json({ error: "Provide km as a number, e.g. ?km=5" });
  }
  res.json({ km, miles: Math.round(km * 0.621371 * 100) / 100 });
});

app.listen(3000);
Terminal
curl -s "localhost:3000/api/convert?km=5"
curl -s "localhost:3000/api/convert?km=42.195"
curl -s "localhost:3000/api/convert?km=far"
Output
{"km":5,"miles":3.11}
{"km":42.195,"miles":26.22}
{"error":"Provide km as a number, e.g. ?km=5"}

Key takeaway#

Next: Routing and Route Parameters.

Finished this lesson?