CodingNic

REST API Design

Resource Design

REST API Design 10 min read

Resource Design

Objectives

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

  • Name resource URLs consistently, using plural nouns
  • Structure nested resources to express a real relationship between them
  • Avoid common URL design mistakes that make an API harder to predict

💡 Why this matters: Consistent naming is what makes an API guessable, once a developer sees /products, they should be able to correctly guess /orders and /users follow the same pattern, without checking documentation for each one individually.

⚠️ A note on verification: every snippet and every response shown below was actually run and tested with real HTTP requests.

Plural Nouns, Consistently

text
Good:      /products        /products/5
Also seen: /product          /product/5   (inconsistent, avoid)

Resource collections use plural nouns, /products (the collection), /products/5 (one specific product within it), consistently across an entire API. Mixing /product/5 in one place and /orders (plural) elsewhere makes an API’s naming unpredictable, pick one convention, plural is the overwhelming norm, and apply it everywhere.

Nested Resources for Real Relationships

javascript
const users = [{ id: 1, name: 'Erin' }];
const orders = [
  { id: 101, userId: 1, total: 45 },
  { id: 102, userId: 1, total: 89 }
];

app.get('/users/:userId/orders', (req, res) => {
  const userOrders = orders.filter(o => o.userId === Number(req.params.userId));
  res.json(userOrders);
});

app.get('/users/:userId/orders/:orderId', (req, res) => {
  const order = orders.find(
    o => o.userId === Number(req.params.userId) && o.id === Number(req.params.orderId)
  );
  if (!order) return res.status(404).json({ error: 'Not Found' });
  res.json(order);
});
bash
curl http://localhost:4502/users/1/orders
text
[{"id":101,"userId":1,"total":45},{"id":102,"userId":1,"total":89}]
bash
curl http://localhost:4502/users/1/orders/101
text
{"id":101,"userId":1,"total":45}

/users/:userId/orders reads as “the orders belonging to this user,” expressing a genuine ownership relationship directly in the URL structure, this is the right call when a resource only makes sense in the context of its parent (an order without a user is meaningless). A resource that stands on its own, /products, doesn’t need artificial nesting.

When Not to Nest

Nesting too deeply (/users/:userId/orders/:orderId/items/:itemId/reviews/:reviewId) becomes unwieldy fast, a common convention is nesting one level, then referencing deeper resources by their own top-level, flat endpoint instead (/reviews/:reviewId, rather than the full nested chain). If a resource can be looked up meaningfully on its own (an order has its own unique ID, regardless of which user it belongs to), a flat /orders/:orderId alongside the nested /users/:userId/orders is a reasonable, common pattern, giving two valid ways to reach the same resource.

Avoiding Verbs in URLs

text
Avoid:  POST /products/5/activate
Better: PATCH /products/5   { "status": "active" }

A URL like /products/5/activate reintroduces a verb (Lesson 1’s core distinction), a PATCH updating a status field expresses the same change while staying resource-oriented. This isn’t an absolute rule, some actions genuinely don’t map cleanly to CRUD (sending an email, triggering a batch job), and a well-named action endpoint is sometimes the pragmatic, honest choice, but it should be the exception, not the default.

Try It

  1. Take an API with inconsistent naming (mixing singular and plural resource names) and rewrite every URL consistently.
  2. Design (in words, then code) a nested resource relationship for a blog: posts and their comments, and decide whether a flat /comments/:id endpoint should exist alongside the nested one.
  3. Find a URL using a verb (/users/5/deactivate, for example) and redesign it as a resource-oriented PATCH instead.
  4. Explain, in your own words, when nesting a resource under its parent makes sense, and when a flat, top-level resource is the better choice.

Recap

  • Resource collections use plural nouns consistently, /products, /orders, /users, applied the same way everywhere in an API.
  • Nested resources (/users/:userId/orders) express a genuine ownership relationship, avoid nesting more than one or two levels deep.
  • Prefer expressing an action as a resource update (PATCH with a changed field) over a verb baked into the URL, reserving verb-like endpoints for actions that genuinely don’t map to CRUD.

Next lesson: API versioning, changing an API without breaking existing clients.