Skip to content

23 Resource Relationships

DodaTech 3 min read

title: Resource Relationships in REST API Design weight: 33 date: 2026-06-28 lastmod: 2026-06-28 description: Learn modeling resource relationships in REST APIs including one-to-one, one-to-many, many-to-many with nesting, references, and embedded representations. tags: [api-development, rest]


Resource relationships in REST APIs model how entities connect to each other using nested URIs for parent-child relationships, resource references for loose associations, and embedded representations for reducing API calls.

```mermaid
flowchart TD
  A[Relationships] --> B[One-to-One]
  A --> C[One-to-Many]
  A --> D[Many-to-Many]
  B --> E[/users/42/profile]
  C --> F[/users/42/orders]
  D --> G[/users/42/roles]
  D --> H[/roles/5/users]
  style A fill:#e1f5fe
  style B fill:#c8e6c9
  style C fill:#c8e6c9
  style D fill:#fff9c4

One-to-one: a user has one profile. Access it via /users/42/profile. One-to-many: a user has many orders. Access via /users/42/orders. Many-to-many: users have roles. Access via /users/42/roles or /roles/5/users. The choice between nesting and referencing depends on how tightly coupled the resources are.

Think of resource relationships like a family tree. Nested resources under a parent (user -> orders) are like children living in the parent's house. Referenced resources (user -> roles) are like cousins who live elsewhere but share a last name.

Example: Nested Relationships (One-to-Many)

import requests

# Get orders for a specific user
response = requests.get("https://api.example.com/users/42/orders")
orders = response.json()
print(f"User 42 has {len(orders)} orders:")
for order in orders:
    print(f"  Order {order['id']}: ${order['total']}")

Expected output:

User 42 has 3 orders:
  Order 5: $100.00
  Order 8: $250.00
  Order 12: $50.00

Example: Resource References vs Embedded

import requests

# Reference approach - client fetches related resource
user_response = requests.get("https://api.example.com/users/42")
user = user_response.json()
print(f"User: {user['name']}")
print(f"Profile URI: {user['profile_uri']}")

# Client must make a second call
profile = requests.get(f"https://api.example.com{user['profile_uri']}")
print(f"Profile: {profile.json()}")

# Embedded approach - related data included
embedded_user = requests.get("https://api.example.com/users/42?embed=profile").json()
print(f"User with embedded profile:")
print(f"  Name: {embedded_user['name']}")
print(f"  Bio: {embedded_user['profile']['bio']}")

Expected output:

User: Alice
Profile URI: /users/42/profile
Profile: {"bio": "Developer", "avatar": "/avatars/42.jpg"}
User with embedded profile:
  Name: Alice
  Bio: Developer

Example: Many-to-Many Relationships

import requests

# Get roles for a user
roles_response = requests.get("https://api.example.com/users/42/roles")
roles = roles_response.json()
print(f"User roles: {[r['name'] for r in roles]}")

# Get users for a role
users_response = requests.get("https://api.example.com/roles/admin/users")
users = users_response.json()
print(f"Admin users: {[u['name'] for u in users]}")

Expected output:

User roles: ['admin', 'editor']
Admin users: ['Alice', 'Bob']

Common Mistakes

  1. Over-nesting relationships/users/42/orders/5/items/12/reviews creates fragile URIs. Limit nesting to 2-3 levels.
  2. Embedding too much data — Embedding all related resources makes responses bloated. Use sparse fieldsets or embedding with explicit opt-in.
  3. Inconsistent relationship exposure — Some endpoints return nested data, others return references. Pick one pattern and apply consistently.
  4. Not providing inverse relationship access — If you can get user orders, also provide getting the user from an order: /orders/5/user.
  5. Circular references in embedded data -- Embedding user -> orders -> user creates infinite loops. Limit embed depth.

Practice Questions

  1. When should you use nested URIs vs resource references?
  2. What is the recommended maximum nesting depth for related resources?
  3. How do you handle many-to-many relationships in REST?
  4. What is the advantage of embedding related resources in responses?
  5. Challenge: Design the URI structure and response format for a course management system with students, courses, enrollments, assignments, and grades. Show the relationship patterns for each connection type.

FAQ

Should I embed or reference related resources?

Embed for tightly coupled resources (user + profile). Reference for loosely coupled resources. Use embedding with an ?embed parameter to let clients choose.

How do I handle circular references in JSON responses?

Use resource identifiers instead of full objects in circular cases. Return {id: 42, name: 'Alice'} instead of the full nested user object.

What is the difference between composition and aggregation in API design?

Composition (user -> orders) means the child cannot exist without the parent. Aggregation (user -> roles) means the child exists independently.

How do I represent a many-to-many relationship with additional properties?

Create a separate resource for the join table: /enrollments with student_id, course_id, and enrollment_date.

Should I provide inverse relationship endpoints?

Yes, if you provide GET /users/42/orders, also provide GET /orders/5/user. This follows the principle of navigable relationships.

Mini Project

Design and implement a resource relationship system for a social media API. Include users, posts, comments, likes, followers, and groups. Show the URI structure, response formats with embedded vs referenced relationships, and depth control with an embed parameter.

What's Next

Now learn about bulk operations in REST API Design.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro