🔥 0
0
Lesson 9 of 10 18 min +100 XP

Intro to Express

Express.js is the most popular Node.js web framework. It simplifies routing, middleware, and building APIs.

Setting Up

mkdir my-express-app
cd my-express-app
npm init -y
npm install express

Your First Express Server

// app.js
const express = require('express');
const app = express();

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

app.listen(3000, () => {
  console.log('Server running at http://localhost:3000/');
});
Run it:
node app.js

Compare this to the raw HTTP server - so much simpler!

Routing Made Easy

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

// Different HTTP methods
app.get('/', (req, res) => {
  res.send('GET request to homepage');
});

app.post('/submit', (req, res) => {
  res.send('POST request received');
});

app.put('/update', (req, res) => {
  res.send('PUT request received');
});

app.delete('/remove', (req, res) => {
  res.send('DELETE request received');
});

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

app.get('/contact', (req, res) => {
  res.send('Contact page');
});

app.listen(3000);

Route Parameters

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

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

// Multiple parameters
app.get('/users/:userId/posts/:postId', (req, res) => {
  const { userId, postId } = req.params;
  res.send(`User ${userId}, Post ${postId}`);
});

app.listen(3000);
Test it:
curl http://localhost:3000/users/42
curl http://localhost:3000/users/1/posts/5
Output:
User ID: 42
User 1, Post 5

Query Strings

// Query strings: /search?q=nodejs&limit=10
app.get('/search', (req, res) => {
  const query = req.query.q;
  const limit = req.query.limit || 10;
  res.send(`Searching for: ${query} (limit: ${limit})`);
});
Test it:
curl "http://localhost:3000/search?q=nodejs&limit=5"
Output:
Searching for: nodejs (limit: 5)

Sending JSON

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

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

// res.json() automatically sets Content-Type and stringifies
app.get('/api/users', (req, res) => {
  res.json(users);
});

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

app.listen(3000);

Middleware

Middleware functions run before your route handlers:

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

// Middleware that runs on EVERY request
app.use((req, res, next) => {
  console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`);
  next(); // Pass control to next middleware/route
});

// Built-in middleware for parsing JSON bodies
app.use(express.json());

// Built-in middleware for parsing URL-encoded bodies
app.use(express.urlencoded({ extended: true }));

// Your routes
app.get('/', (req, res) => {
  res.send('Home');
});

app.post('/api/data', (req, res) => {
  console.log('Body:', req.body); // Now accessible thanks to middleware
  res.json({ received: req.body });
});

app.listen(3000);
Test it:
curl -X POST http://localhost:3000/api/data \
  -H "Content-Type: application/json" \
  -d '{"name":"Alice"}'
Server log:
2024-01-15T10:30:00.000Z - POST /api/data
Body: { name: 'Alice' }

Complete REST API Example

// api.js
const express = require('express');
const app = express();

// Middleware
app.use(express.json());

// In-memory database
let todos = [
  { id: 1, text: 'Learn Express', done: false },
  { id: 2, text: 'Build an API', done: false }
];
let nextId = 3;

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

// GET single todo
app.get('/api/todos/:id', (req, res) => {
  const todo = todos.find(t => t.id === parseInt(req.params.id));
  if (!todo) {
    return res.status(404).json({ error: 'Todo not found' });
  }
  res.json(todo);
});

// CREATE todo
app.post('/api/todos', (req, res) => {
  const { text } = req.body;
  if (!text) {
    return res.status(400).json({ error: 'Text is required' });
  }

  const todo = {
    id: nextId++,
    text,
    done: false
  };
  todos.push(todo);
  res.status(201).json(todo);
});

// UPDATE todo
app.put('/api/todos/:id', (req, res) => {
  const todo = todos.find(t => t.id === parseInt(req.params.id));
  if (!todo) {
    return res.status(404).json({ error: 'Todo not found' });
  }

  const { text, done } = req.body;
  if (text !== undefined) todo.text = text;
  if (done !== undefined) todo.done = done;

  res.json(todo);
});

// DELETE todo
app.delete('/api/todos/:id', (req, res) => {
  const index = todos.findIndex(t => t.id === parseInt(req.params.id));
  if (index === -1) {
    return res.status(404).json({ error: 'Todo not found' });
  }

  todos.splice(index, 1);
  res.json({ message: 'Todo deleted' });
});

// 404 handler
app.use((req, res) => {
  res.status(404).json({ error: 'Not found' });
});

// Error handler
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).json({ error: 'Something went wrong!' });
});

app.listen(3000, () => {
  console.log('API running at http://localhost:3000/');
});
Test the full CRUD:
# List all
curl http://localhost:3000/api/todos

# Create
curl -X POST http://localhost:3000/api/todos \
  -H "Content-Type: application/json" \
  -d '{"text":"New todo"}'

# Update
curl -X PUT http://localhost:3000/api/todos/1 \
  -H "Content-Type: application/json" \
  -d '{"done":true}'

# Delete
curl -X DELETE http://localhost:3000/api/todos/2

Express Router (Organizing Routes)

For larger apps, organize routes in separate files:

// routes/users.js
const express = require('express');
const router = express.Router();

router.get('/', (req, res) => {
  res.json([{ id: 1, name: 'Alice' }]);
});

router.get('/:id', (req, res) => {
  res.json({ id: req.params.id, name: 'Alice' });
});

router.post('/', (req, res) => {
  res.status(201).json({ id: 2, ...req.body });
});

module.exports = router;
// app.js
const express = require('express');
const usersRouter = require('./routes/users');

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

// Mount the router at /api/users
app.use('/api/users', usersRouter);

app.listen(3000);

Now /api/users and /api/users/:id are handled by the router.

Static Files

Serve HTML, CSS, JS, and images:

const express = require('express');
const path = require('path');
const app = express();

// Serve everything in the 'public' folder
app.use(express.static(path.join(__dirname, 'public')));

// API routes
app.get('/api/data', (req, res) => {
  res.json({ message: 'Hello from API' });
});

app.listen(3000);

Now put index.html, style.css, etc. in a public/ folder and they're served automatically.

Key Takeaways

  • express() creates an app instance
  • app.get/post/put/delete define route handlers
  • req.params for URL parameters (:id)
  • req.query for query strings (?name=value)
  • req.body for POST/PUT body (needs middleware)
  • res.json() sends JSON response
  • res.status() sets HTTP status code
  • app.use() adds middleware
  • express.Router() organizes routes

What's Next?

You've learned Node.js fundamentals:

  • How Node.js works (runtime, event loop)
  • Modules and npm
  • File system operations
  • Async/await
  • Building HTTP servers
  • Express basics
Continue your journey:
  • Add a database (MongoDB, PostgreSQL)
  • Authentication (JWT, sessions)
  • Validation (Joi, Zod)
  • Testing (Jest)
  • Deployment (Docker, cloud platforms)
Crio.Do

Build Full-Stack Projects

Continue learning with real projects. Build APIs, connect databases, and deploy on pre-configured cloud workspaces.

Start Free Trial

Take the quiz to test your knowledge!

🧠 Quick Quiz

Test your understanding of this lesson.

1

What is Express.js?

2

What is middleware in Express?

3

How do you access URL parameters like /users/:id?

Building an HTTP Server