Menu
CoddyTech

Redirects

Part of the Express Basics section of Coddy's Node.js journey. Lesson 12 of 23.

Pages move, and old links in bookmarks and search results should still lead somewhere.

app.get('/old-prices', (req, res) => {
    res.redirect(301, '/prices');
});

A redirect answers with a status and a Location header naming the new URL, and the browser asks for that URL at once. res.redirect sets both.

The status says how long the move lasts. 301 means moved for good: browsers and search engines remember the new address and stop asking for the old one. 302, the default when you pass no status, means for now, so they keep using the old URL.

challenge icon

Challenge

Easy

The old menu pages have moved to the recipe pages for good, and old bookmarks should still work.

  1. In server.js, add a route for /menu that redirects to /recipes with status 301, which means moved for good.
  2. Add a route for /menu/:id that redirects to the recipe page with the same id, also with status 301: /menu/3 goes to /recipes/3.

Try it: Press Run and send /menu/3. You should see status 301 and a Location header of /recipes/3. Send /menu: 301 with Location /recipes. Send /menu/42: 301 with Location /recipes/42. The redirect does not check whether recipe 42 exists; /recipes/42 itself then responds with 404.

Try it yourself

import { escapeHtml } from './html.js';
import express from 'express';
import { recipes } from './data.js';

const app = express();

app.use(express.static('public'));

app.get('/', (req, res) => {
    const items = recipes.map((r) => `<li><a href="/recipes/${r.id}">${escapeHtml(r.title)}</a></li>`);
    res.send(`<link rel="stylesheet" href="/style.css"><h1>Recipe Box</h1><ul>${items.join('')}</ul>`);
});

// type('text') sends plain text, so each title shows on its own line.
app.get('/recipes', (req, res) => {
    const { tag } = req.query;
    const list = tag ? recipes.filter((recipe) => recipe.tags.includes(tag)) : recipes;
    res.type('text').send(list.map((recipe) => recipe.title).join('\n'));
});

app.get('/recipes/:id', (req, res) => {
    const recipe = recipes.find((r) => r.id === Number(req.params.id));
    if (!recipe) {
        res.status(404).send('No such recipe');
        return;
    }
    res.send(recipe.title);
});

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

app.get('/api/recipes/:id', (req, res) => {
    const recipe = recipes.find((r) => r.id === Number(req.params.id));
    if (!recipe) {
        res.status(404).json({ error: 'No such recipe' });
        return;
    }
    res.json(recipe);
});

app.get('/about', (req, res) => {
    res.send('Recipe Box collects family recipes.');
});

app.listen(3000, () => {
    console.log('Recipe Box is running on port 3000');
});

All lessons in Express Basics

Practice on your own: Express playground