Introduction to Express.js: A Beginner's Guide

Introduction to Express.js: A Beginner's Guide

HTTP Basic

const http = require('http');

const server = http.createServer((req, res) => {
  const url = req.url;

  // Home page
  if (url === '/') {
    res.writeHead(200, { 'content-type': 'text/html' });
    res.write('<h1>home page</h1>');
    res.end();
  }
  // About page
  else if (url === '/about') {
    res.writeHead(200, { 'content-type': 'text/html' });
    res.write('<h1>about page</h1>');
    res.end();
  }
  // 404
  else {
    res.writeHead(404, { 'content-type': 'text/html' });
    res.write('<h1>page not found</h1>');
    res.end();
  }
});

server.listen(5000);

For more details on MIME types (IANA media types).

Sending HTML Files in res.send()

const http = require('http');
const { readFileSync } = require('fs');

// Get all files
const homePage = readFileSync('./navbar-app/index.html');
const homeStyles = readFileSync('./navbar-app/styles.css');
const homeImage = readFileSync('./navbar-app/logo.svg');
const homeLogic = readFileSync('./navbar-app/browser-app.js');

const server = http.createServer((req, res) => {
  const url = req.url;

  // Home page
  if (url === '/') {
    res.writeHead(200, { 'content-type': 'text/html' });
    res.write(homePage);
    res.end();
  }
  // About page
  else if (url === '/about') {
    res.writeHead(200, { 'content-type': 'text/html' });
    res.write('<h1>about page</h1>');
    res.end();
  }
  // Styles
  else if (url === '/styles.css') {
    res.writeHead(200, { 'content-type': 'text/css' });
    res.write(homeStyles);
    res.end();
  }
  // Image/logo
  else if (url === '/logo.svg') {
    res.writeHead(200, { 'content-type': 'image/svg+xml' });
    res.write(homeImage);
    res.end();
  }
  // Logic
  else if (url === '/browser-app.js') {
    res.writeHead(200, { 'content-type': 'text/javascript' });
    res.write(homeLogic);
    res.end();
  }
  // 404 error page
  else {
    res.writeHead(404, { 'content-type': 'text/html' });
    res.write('<h1>page not found</h1>');
    res.end();
  }
});

server.listen(5000);

Commonly Used HTTP Status Codes

Status CodeStatus Text
200OK
201CREATED
202ACCEPTED
400BAD_REQUEST
401UNAUTHORIZED
404NOT_FOUND
405METHOD_NOT_ALLOWED
500INTERNAL_SERVER_ERROR
502BAD_GATEWAY

Express Basics

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

app.get('/', (req, res) => {
  console.log('User hit the resource');
  res.status(200).send('Home Page');
});

app.get('/about', (req, res) => {
  res.status(200).send('About Page');
});

// '*' represents all other endpoints which are not defined above
app.all('*', (req, res) => {
  res.status(404).send('<h1>Resource not found</h1>');
});

app.listen(5000, () => {
  console.log('Server is listening on port 5000...');
});

πŸ’‘ Tip: Send static files in Express using static middleware

app.use(express.static('./public'));
const express = require('express');
const path = require('path');
const app = express();

// Setup static and middleware
app.use(express.static('./public'));

app.get('/', (req, res) => {
  res.sendFile(path.resolve(__dirname, './navbar-app/index.html'));
});

app.all('*', (req, res) => {
  res.status(404).send('Resource not found');
});

app.listen(5000, () => {
  console.log('Server is listening on port 5000....');
});

πŸ’‘ Tip: You can keep index.html inside the public folder, then you won’t require to write the '/' endpoint get request.

JSON Basics

Check out the JSON MDN docs.

res.json(null);
res.json({ user: 'tobi' });
res.status(500).json({ error: 'message' });

Params Query

app.get('/api/products/:id', (req, res) => {
    const idx = data.products.findIndex(product => product.id === parseInt(req.params.id));
    if (idx === -1) {
        res.status(404).json('Product not found');
        return;
    }
    res.json(data.products[idx]);
});

Complex Params Query

app.get('/api/products/:productID/reviews/:reviewID', (req, res) => {
    const productID = parseInt(req.params.productID);
    const reviewID = parseInt(req.params.reviewID);
    const product = data.products.find(product => product.id === productID);
    const review = product.reviews.find(review => review.reviewId === reviewID);
    if (product && review) {
        res.json(review);
    } else {
        res.status(404).json('Product or review not found');
    }
});

Multiple Query URL Routes req.query()

Example URL: http://localhost:5000/api/v1/query?name=john&id=12

Check out the Express docs.

πŸ’‘ Tip: As req.query’s shape is based on user-controlled input, all properties and values in this object are untrusted and should be validated before trusting.

app.get('/api/v1/query', (req, res) => {
    const { search, limit } = req.query;
    const products = search ? data.products.filter(product => product.name.startsWith(search)) : data.products;
    const limitedProducts = limit ? products.slice(0, Number(limit)) : products;
    return res.json(limitedProducts);
});

Middlewares

Check out the Express docs.

πŸ’‘ Tip: If the current middleware function does not end the request-response cycle, it must call next() to pass control to the next middleware function. Otherwise, the request will be left hanging.

const logger = (req, res, next) => {
  const method = req.method;
  const url = req.url;
  const time = new Date().getFullYear();
  console.log(method, url, time);
  next();
};

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

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

app.get('/api', [logger, authorize], (req, res) => {
  res.send('API');
});

πŸ’‘ Tip: To use a particular middleware with all the routes, you can use the app.use() method.

app.use() Middleware

const logger = require('./logger');
const authorize = require('./authorize');

app.use([logger, authorize]);

app.get('/', (req, res) => {
  res.send('Home');
});
app.use('/api', logger);
app.use('/api/products', [logger, authorize]);
const authorize = (req, res, next) => {
    const { user } = req.query;
    if (user === 'john') {
        req.user = { name: 'john', id: 3 };
        next();
    } else {
        res.send('Unauthorized');
    }
};

module.exports = authorize;

Commonly Used Express Middlewares

// Serve static files 
app.use(express.static('/public'));

// Parse data from forms
app.use(express.urlencoded({ extended: false }));

// Parse JSON payloads
app.use(express.json());

// Cookie-parser β€” Parse cookies
app.use(cookieParser());

πŸ’‘ Tip: Difference between a node module and Express middleware?

A node module is a reusable block of code that can be imported and used in a Node.js application. Express middleware is a specific type of node module that intercepts incoming HTTP requests and provides additional functionality to the application, such as parsing request data or handling authentication.

πŸ”— Recommended Reads:

HTTP Methods

const express = require('express');
const app = express();
let { people }

 = require('./data');

app.use(express.static('./methods-public'));
app.use(express.urlencoded({ extended: false }));
app.use(express.json());

app.get('/api/people', (req, res) => {
  res.status(200).json({ success: true, data: people });
});

app.post('/api/people', (req, res) => {
  const { name } = req.body;
  if (!name) {
    return res.status(400).json({ success: false, msg: 'please provide name value' });
  }
  res.status(201).json({ success: true, person: name });
});

app.put('/api/people/:id', (req, res) => {
  const { id } = req.params;
  const { name } = req.body;
  const person = people.find((person) => person.id === Number(id));

  if (!person) {
    return res.status(404).json({ success: false, msg: `no person with id ${id}` });
  }
  const newPeople = people.map((person) => {
    if (person.id === Number(id)) {
      person.name = name;
    }
    return person;
  });
  res.status(200).json({ success: true, data: newPeople });
});

app.delete('/api/people/:id', (req, res) => {
  const person = people.find((person) => person.id === Number(req.params.id));
  if (!person) {
    return res.status(404).json({ success: false, msg: `no person with id ${req.params.id}` });
  }
  const newPeople = people.filter((person) => person.id !== Number(req.params.id));
  return res.status(200).json({ success: true, data: newPeople });
});

app.listen(5000, () => {
  console.log('Server is listening on port 5000....');
});

Third-Party Middlewares

morgan

const morgan = require('morgan');

app.use(morgan('tiny'));

Helmet

  • Use Helmet middleware for setting HTTP headers that enhance security.

  • Install using npm install helmet

  • Helmet GitHub repository

const helmet = require('helmet');

app.use(helmet());

CORS (Cross-Origin Resource Sharing)

  • Use CORS middleware for handling CORS issues in REST APIs.

  • Install using npm install cors

  • CORS GitHub repository

const cors = require('cors');

app.use(cors());

Rate Limiter

const rateLimit = require('express-rate-limit');

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 100,
});

app.use(limiter);

Express Routers

  • Express Routers are a way to modularize the application by separating routes into different files.

  • You can split routers for different parts of the application (e.g., auth routes, product routes).

const express = require('express');
const router = express.Router();

// Router-specific middleware
router.use(express.json());

router.get('/', (req, res) => {
  res.send('Product Home Page');
});

router.get('/:id', (req, res) => {
  res.send(`Product with ID: ${req.params.id}`);
});

module.exports = router;

Use the router in your main app:

const productRouter = require('./routes/product');

app.use('/products', productRouter);

Template Engines in Express

Handlebars

npm install express-handlebars
const express = require('express');
const exphbs = require('express-handlebars');
const app = express();

// Set up Handlebars as the template engine
app.engine('handlebars', exphbs());
app.set('view engine', 'handlebars');

app.get('/', (req, res) => {
  res.render('home', { title: 'Home Page' });
});

app.listen(3000, () => {
  console.log('Server is listening on port 3000....');
});

EJS

npm install ejs
const express = require('express');
const app = express();

// Set EJS as the template engine
app.set('view engine', 'ejs');

app.get('/', (req, res) => {
  res.render('home', { title: 'Home Page' });
});

app.listen(3000, () => {
  console.log('Server is listening on port 3000....');
});

πŸ”— Recommended Reads:

Β