Skip to content

Beginner · Node.js and Express · topic 13 of 54 · 25 min

Express: your first web server

Explanation

Express is a small framework for building web servers with Node.js. You tell it which function should answer which URL and method, and it does the rest: reading requests, sending JSON and handling errors. With about ten lines you have a working API.

What is a framework?

A framework is ready-made code that gives your app its shape. You fill in the parts that are special to your app; the framework handles the boring parts that every app needs. Express is the most used web framework for Node.js.

Think of it like this: A framework is like renting a fully fitted restaurant kitchen. The gas line, sink, fridge and exhaust are already there. You only bring your recipes. Without a framework you would first have to build the kitchen yourself.

A minimal Express app

javascript
import express from 'express';

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

const trains = [
  { id: 12951, name: 'Mumbai Rajdhani', from: 'Mumbai' },
  { id: 12627, name: 'Karnataka Express', from: 'Bengaluru' },
];

app.get('/api/trains', (req, res) => {
  res.json(trains);
});

app.post('/api/trains', (req, res) => {
  const train = req.body;
  trains.push(train);
  res.status(201).json(train);
});

app.listen(3000, () => {
  console.log('API running on http://localhost:3000');
});
A full Express API. Runs on a server with Node.js after npm install express.
  • express() creates the app.
  • app.use(express.json()) reads JSON request bodies and puts them in req.body.
  • app.get(path, handler) answers GET requests to that path; app.post answers POST requests.
  • req is the request that came in; res is the response you send back.
  • res.status(201).json(data) sets the status code and sends data as JSON.
  • app.listen(3000) starts the server on port 3000. A port is like a door number on the computer.

Route params and query

A route param is a part of the path that changes, written with a colon: /api/trains/:id. Express puts its value in req.params.id. The query string is the part after ? in a URL, like ?from=Mumbai. Express puts it in req.query. Both always arrive as text (strings).

javascript
// GET /api/trains/12951
app.get('/api/trains/:id', (req, res) => {
  const id = Number(req.params.id);
  const train = trains.find((t) => t.id === id);
  if (!train) return res.status(404).json({ error: 'Train not found' });
  res.json(train);
});

// GET /api/search?from=Mumbai
app.get('/api/search', (req, res) => {
  const from = req.query.from;
  res.json(trains.filter((t) => t.from === from));
});
Runs on a server with Node.js: req.params for the path, req.query for the part after ?.

A sensible project structure

output
my-api/
  package.json
  .env
  src/
    server.js          starts the app (app.listen)
    routes/
      trains.js        which URL goes to which controller
    controllers/
      trains.js        reads req, sends res
    services/
      trains.js        the real rules (search, fares)
    db/
      index.js         talks to the database
One folder per job keeps a growing project easy to find your way around.

Routes only connect a URL to a controller. Controllers read the request and send the response. Services hold the business rules and know nothing about req or res, so you can test them like plain functions. The db folder is the only place that talks to the database.

bash
npm run dev     # restarts the server when you save a file
npm start       # runs it normally, like on the real server
npm scripts from package.json: "dev" uses node --watch, "start" uses node.
Tip: Keep controllers thin. If a function decides prices, checks seats or filters data, move it to a service. Plain functions are easy to test, as you will do in the tasks below.
Careful: If req.body is undefined in a POST route, you probably forgot app.use(express.json()). Also remember that req.params.id is the text "12951", not the number 12951, so convert it with Number() before comparing with ===.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Express: your first web server · 1/7

Express: your first web server

Today we build a real web server with Express, the most popular framework for Node.js.

Prefer a video by a teacher? Find free videos on “express js tutorial for beginners rest api” on YouTube ↗

In real life: A coaching centre batch API

A coaching centre in Kota wants an app that lists its batches. The backend has GET /api/batches (all batches), GET /api/batches/:id (one batch) and GET /api/batches?subject=Physics (filter). The route file maps each URL to a controller. The controller reads req.params and req.query, calls a service such as findBatches({ subject }), and sends the result with res.json(). When a new batch starts, the admin app sends POST /api/batches with JSON, and the server answers 201 Created.

Practice (0/3 done)

Task 1 · Code · Javascript

Write the controller for GET /api/trains/:id as a plain function getTrain(params). params.id arrives as TEXT, like "12951". Return { status: 200, body: train } when a train in TRAINS has that id, else { status: 404, body: { error: "Train not found" } }.

Task 2 · Code · Javascript

Now GET /api/trains?from=...&maxFare=... with a service and a controller. 1) Write a service findTrains({ from, maxFare }) that returns the trains from TRAINS that match: from is compared ignoring upper/lower case, maxFare is a number; a filter that is undefined is not applied. 2) Write the controller listTrains(query): query values are text. If query.maxFare is given but is not a number, return { status: 400, body: { error: "maxFare must be a number" } }. Otherwise return { status: 200, body: findTrains(...) }.

Task 3 · Practice

On your computer, build the minimal Express app from this lesson with the trains list. Run it and test the routes in your browser or with curl.

Quick quiz

Question 1

1.What does app.use(express.json()) do?

Question 2

2.For the route /api/users/:id and the URL /api/users/42, what is req.params.id?

Question 3

3.Where do you find city in the URL /api/shops?city=Pune?

Question 4

4.Which line sends status 201 with a JSON body?

Question 5

5.In a routes / controllers / services structure, where should the rule "fare must include 5% GST" live?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

What does app.use(express.json()) do?

Answer: Reads JSON request bodies into req.body

express.json() reads a JSON body from the request and puts the parsed object in req.body.

For the route /api/users/:id and the URL /api/users/42, what is req.params.id?

Answer: The text "42"

Route params always arrive as strings. Convert with Number() when you need a number.

Where do you find city in the URL /api/shops?city=Pune?

Answer: req.query.city

The part after ? is the query string, and Express puts it in req.query.

Which line sends status 201 with a JSON body?

Answer: res.status(201).json(order)

res.status() sets the code and returns res, so you can chain .json() to send the data.

In a routes / controllers / services structure, where should the rule "fare must include 5% GST" live?

Answer: In the service

Business rules belong in services: plain functions that do not know about req or res and are easy to test.

In Express 5, what happens when an async route handler throws an error?Related

Answer: Express passes the error to the error-handling middleware automatically

Express 5 catches rejected promises from handlers and calls next(err) for you. Express 4 needed try/catch or a wrapper.

From Route handlers that follow the contract

Your POST reaches Express but req.body is empty. What is the most likely cause?Related

Answer: The Content-Type: application/json header is missing

express.json() only reads bodies whose Content-Type says JSON. Without the header, the body is skipped.

From Calling the API with fetch

Which status code does Results.Created(...) send?Related

Answer: 201

201 Created, with a Location header.

From ASP.NET Core: your first Web API

For the pattern /shops/:shopId/items/:itemId and the path /shops/3/items/77, what are the params?Related

Answer: { shopId: "3", itemId: "77" }

Each :name captures the value in its place, and path values are always strings.

From Routing: sending each request to the right code

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 2 more topics in “Node.js and Express” before its exam: Middleware: checks before your handler, Environment variables and config.
  2. Exam: Node.js and Express · 14 questions · 25 min, without help. 4 topics of this module still to finish first.
  3. Then the next module, Databases and SQL basics. 54 topics left in the course before the final exam.

← Previous: Node.js: JavaScript on the server