REST API Nested Resources

Real data connects. A customer places orders, an order holds items, and a blog post gathers comments. REST expresses these links through URLs that mirror the structure of the data. Well-designed nesting makes an API feel natural, and careless nesting produces long, brittle paths.

The Folder Picture

Picture the folders on your computer. A folder named Customers holds a folder for each customer, and each customer folder holds an Orders folder. The path to a file tells you exactly where it lives. Nested URLs work the same way. The path /customers/42/orders/7 means order 7 inside the orders of customer 42.

The Resource Tree

/customers
   └── /customers/42
          ├── /customers/42/profile
          └── /customers/42/orders
                 └── /customers/42/orders/7
                        └── /customers/42/orders/7/items

When Nesting Fits

Use nesting when a child resource cannot exist without its parent. An order line item has no meaning outside its order. A comment belongs to one post. A chapter belongs to one book. These strong ownership links suit nested paths.

Common Operations

RequestMeaning
GET /customers/42/ordersList all orders of customer 42
POST /customers/42/ordersCreate an order for customer 42
GET /customers/42/orders/7Read order 7 of customer 42
DELETE /customers/42/orders/7Remove order 7

The Two-Level Rule

Limit nesting to two levels. A path such as /customers/42/orders/7/items/3/discounts/9 forces clients to know five identifiers and makes every URL fragile. Once a resource has its own unique id, expose it at the top level.

Deep path (hard to use):
/customers/42/orders/7/items/3

Flat path (easy to use):
/items/3
/orders/7/items

Flattening with Query Parameters

Many-to-many links do not fit a single parent. A student joins many courses, and a course holds many students. Expose each side as its own collection and filter by relationship.

GET /courses?studentId=15
GET /students?courseId=3

Embedding vs Linking

A response can include related data directly or point to it with a link.

Embedded Data

{
  "id": 7,
  "customer": { "id": 42, "name": "Asha" },
  "total": 120
}

Embedding saves a request and suits small, frequently needed data.

Linked Data

{
  "id": 7,
  "customerUrl": "/customers/42",
  "itemsUrl": "/orders/7/items",
  "total": 120
}

Links keep responses small and let clients fetch extra data only when they need it. An optional query parameter such as ?include=customer lets the client choose.

A Library Example

A library API manages members, loans, and books. A loan belongs to one member, so the path /members/18/loans lists every loan for member 18. A book exists on its own shelf, so /books/905 stands at the top level. A loan links to its book through a field such as bookUrl. This split keeps ownership clear and avoids copying book data into every loan.

/members/18/loans ──→ loan 3 ──→ bookUrl: /books/905
                  ──→ loan 8 ──→ bookUrl: /books/117

Clients read the loan list first and follow each book link only when the screen needs book details.

Naming Tips

  • Use plural nouns for collections: /orders, /items.
  • Keep verbs out of paths. Write POST /orders/7/cancellation instead of /orders/7/cancelOrder.
  • Use lowercase letters and hyphens for multi-word names, such as /order-items.
  • Check that the parent exists before returning child data, and return 404 when it does not.

Common Mistakes

Mismatched Parent and Child

A request for /customers/42/orders/7 must confirm that order 7 belongs to customer 42. Skipping that check lets one customer read another customer's data.

Deep Chains Everywhere

Developers sometimes nest every relationship out of habit. Ask whether the child can stand alone, and flatten the path when it can.

Mixed Styles

One endpoint using /orders/7/items and another using /order-items?orderId=7 for the same data confuses users. Pick one pattern per relationship and use it consistently.