Stop 05 · Express.js & Web FrameworksProjects · 2/3

Blog API

Part of the Backend Developer Roadmap

In short

A blog API adds what the todo app doesn't have: users, ownership, relationships and public versus private data. It feels much closer to a real product backend.

A backend for a blog — posts, comments, and categories — practice for relational data modeling and nested resource routes.

The mascot pins a new article on a college notice board with comment slips below.

Think of it like this

The college notice board

Anyone can read the notice board. Only the person who pinned a notice can take it down, and students leave comment slips under popular ones. A blog API works the same: public reading, owner-only editing, comments attached to posts.

Watch it happen

Build plan

Routers
Posts CRUD
Ownership
Comments
Pagination

1/5Set up routes/posts.js and routes/comments.js with express.Router and an error handler.

The big ideas

What you need to know

Readable URLs with slugs

/posts/my-first-api reads better than /posts/8213. Make slugs unique and generate them from titles.

Ownership checks

401 means 'who are you?'. 403 means 'I know you, but this isn't yours'. Use both correctly.

Public vs draft

Drafts are visible only to their author. The public list shows only published: true posts.

Related resources

Comments belong to a post. Deleting a post should also handle its comments.

See it in code

Walk through the code

js
1function requireOwner(req, res, next) {2  const post = posts.find((p) => p.slug === req.params.slug);3  if (!post) return res.status(404).json({ error: "Post not found" });4  if (post.authorId !== req.user.id) {5    return res.status(403).json({ error: "You can only edit your own posts" });6  }7  req.post = post;8  next();9}10 11postsRouter.patch("/:slug", requireAuth, requireOwner, (req, res) => {12  const { title, body, published } = req.body;13  Object.assign(req.post, { title, body, published, updatedAt: new Date() });14  res.json(req.post);15});

1/4Load the post by slug, or 404 if it doesn't exist.

In a real project, validate the body first so undefined fields don't overwrite real values. This snippet keeps the focus on ownership.

Save yourself the pain

Common mistakes

Oops

Checking only that the user is logged in before letting them edit any post.

Do this instead

Also check post.authorId matches req.user.id. Logged in is not the same as allowed.

Oops

Returning drafts in the public posts list.

Do this instead

Filter by published: true for public lists, and show drafts only to their author.

Your mission

Milestone 1: posts with owners

~45 min

Quick check

A logged-in user tries to delete someone else's post. Which status is right?

Go deeper

  1. 1Model the relationship between posts, comments and authors properly.
  2. 2Build nested routes, e.g. `/posts/:id/comments`, for related resources.
  3. 3Add pagination for the posts listing endpoint.

More projects at this stop

Stuck on this topic? Ask an Insider

Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.

Download
InsideEdge