CodingNic

Server-Rendered Views

Exercises

Server-Rendered Views 25 min read

Exercises

Objectives

By the end of this lesson, you should be able to:

  • Build a multi-page server-rendered site with a shared navigation partial
  • Render a list with an empty state and a detail page from route parameters
  • Decide correctly between rendering a view and returning JSON for a given route

⚠️ A note on verification: every command and output in this lesson was actually run with Express, EJS, and Handlebars.

Exercise: A Recipe Site

a) Set up EJS. Configure a fresh Express app to use EJS, with a views folder.

b) Build a nav partial. Create views/partials/nav.ejs with links to / and /recipes, and include it at the top of every page template you build below.

c) List recipes. Using this seed data:

javascript
const recipes = [
  { id: 1, name: 'Pancakes', minutes: 20 },
  { id: 2, name: 'Salad', minutes: 10 }
];

Render a GET /recipes route showing every recipe’s name and cook time in a list, with an appropriate empty-state message when there are no recipes at all (test this with a second route or by temporarily passing an empty array).

bash
curl http://localhost:4108/recipes
text
<h1>Recipes</h1>
<ul>
  <li>Pancakes (20 min)</li>
  <li>Salad (10 min)</li>
</ul>

d) Recipe detail page. Add a GET /recipes/:id route rendering a single recipe’s full details (name and cook time), looked up by its id route parameter. Return a 404 (with res.status(404).send(...), no view needed for the error itself) if the ID doesn’t match any recipe, checked before attempting to render.

e) A JSON version, side by side. Add a GET /api/recipes route on the same app, returning the same recipe data as JSON with res.json() instead of rendering it. Confirm both /recipes (HTML) and /api/recipes (JSON) work correctly from the same running server.

f) Add a recipe count. Pass the total number of recipes into the /recipes view (recipes.length) and display it above the list, for example "3 recipes".

g) Test everything. Use curl to test every route above, confirming the rendered HTML (or JSON) matches what you expect, including the empty state and the 404 case.

h) Rebuild it in Handlebars. As a bonus, rebuild the same recipe list (parts c and d only) using express-handlebars instead of EJS: a main layout, a nav partial, and {{#each}}/{{#if}} in place of EJS’s <% %> tags. Confirm the rendered HTML matches what your EJS version produced.

Recap

This module covered rendering real HTML pages from Express: setting up a view engine, EJS’s templating syntax (loops, conditionals, escaping), passing data (including whole objects and computed values) into views, reusing HTML with partials and layouts, Handlebars as an alternative syntax (including a full create-read-update-delete flow), and choosing between server-rendered views and a JSON API, including running both from the same app.

Next module: middleware, the mechanism that lets code run on every request before it reaches a route.