Beginner · Node.js and Express · topic 13 of 54 · 25 min
Express: your first web server
Explanation
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.
A minimal Express app
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');
});- 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).
// 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));
});A sensible project structure
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 databaseRoutes 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.
npm run dev # restarts the server when you save a file
npm start # runs it normally, like on the real serverNeed 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
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)
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" } }.
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(...) }.
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
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Middleware: checks before your handlerNode.js and Express · same module
- Environment variables and configNode.js and Express · same module
- Route handlers that follow the contractFull-Stack Development · Building the backend
- Calling the API with fetchFull-Stack Development · Connecting frontend and backend
- ASP.NET Core: your first Web APIC# and .NET · Web APIs with ASP.NET Core and EF Core
- Backend languages and frameworksChoosing a stack and getting hired
Questions people ask about this
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.
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.
Which status code does Results.Created(...) send?Related
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.
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
- 2 more topics in “Node.js and Express” before its exam: Middleware: checks before your handler, Environment variables and config.
- Exam: Node.js and Express · 14 questions · 25 min, without help. 4 topics of this module still to finish first.
- Then the next module, Databases and SQL basics. 54 topics left in the course before the final exam.