this-rs supports multi-level entity relationships through semantic URLs, allowing you to navigate complex entity graphs naturally.
Order
└─► Invoice
└─► Payment
Configuration:
links:
- link_type: has_invoice
source_type: order
target_type: invoice
forward_route_name: invoices
reverse_route_name: order
- link_type: has_payment
source_type: invoice
target_type: payment
forward_route_name: payments
reverse_route_name: invoice
Generated Routes:
# Level 1: Order → Invoice
GET /orders/{order_id}/invoices
GET /orders/{order_id}/invoices/{invoice_id}
# Level 2: Invoice → Payment
GET /invoices/{invoice_id}/payments
GET /invoices/{invoice_id}/payments/{payment_id}
# Reverse: Payment → Invoice → Order
GET /payments/{payment_id}/invoice
GET /invoices/{invoice_id}/order
Navigate from parent to children:
# Get all invoices for an order
GET /orders/abc-123/invoices
# Get all payments for an invoice
GET /invoices/inv-456/payments
Response includes target entities:
{
"links": [
{
"target_id": "inv-456",
"target": {
"id": "inv-456",
"amount": 1500.00,
// Full invoice data
}
}
]
}
Navigate from child back to parent:
# Get the order for an invoice
GET /invoices/inv-456/order
# Get the invoice for a payment
GET /payments/pay-789/invoice
Response includes source entities:
{
"links": [
{
"source_id": "abc-123",
"source": {
"id": "abc-123",
"number": "ORD-123",
// Full order data
}
}
]
}
Navigate multiple levels:
# Step 1: Get order
GET /orders/abc-123
# Step 2: Get invoices for order
GET /orders/abc-123/invoices
# Returns: [{ "target": { "id": "inv-456", ... } }]
# Step 3: Get payments for invoice
GET /invoices/inv-456/payments
# Returns: [{ "target": { "id": "pay-789", ... } }]
# Or reverse: payment → invoice → order
GET /payments/pay-789/invoice
GET /invoices/inv-456/order
User
├─(owner)─► Car
└─(driver)─► Car
Configuration:
links:
- link_type: owner
source_type: user
target_type: car
forward_route_name: cars-owned
reverse_route_name: owner
- link_type: driver
source_type: user
target_type: car
forward_route_name: cars-driven
reverse_route_name: drivers
Routes:
# Cars owned by user
GET /users/123/cars-owned
# Cars driven by user
GET /users/123/cars-driven
# Owner of car
GET /cars/456/owner
# Drivers of car
GET /cars/456/drivers
Project
└─(has_member)─► User
└─(has_skill)─► Skill
Configuration:
links:
- link_type: has_member
source_type: project
target_type: user
forward_route_name: members
reverse_route_name: projects
- link_type: has_skill
source_type: user
target_type: skill
forward_route_name: skills
reverse_route_name: users
Navigation:
# Get all members of a project
GET /projects/proj-1/members
# Get all projects for a user
GET /users/user-1/projects
# Get all skills for a user
GET /users/user-1/skills
# Get all users with a skill
GET /skills/skill-1/users
# Link order → invoice
POST /orders/abc-123/invoices/inv-456
Body: { "metadata": { "created_by": "system" } }
# Link invoice → payment
POST /invoices/inv-456/payments/pay-789
Body: { "metadata": { "method": "credit_card" } }
# Create new invoice and link to order
POST /orders/abc-123/invoices
Body: {
"entity": {
"number": "INV-999",
"amount": 2000.00,
"status": "pending"
},
"metadata": {
"created_by": "api"
}
}
# Then create payment and link to invoice
POST /invoices/{new_invoice_id}/payments
Body: {
"entity": {
"amount": 2000.00,
"method": "wire_transfer"
}
}
Start from the root entity and navigate down:
# 1. Get order
GET /orders/abc-123
# 2. Get its invoices (enriched)
GET /orders/abc-123/invoices
# 3. For each invoice, get payments
GET /invoices/inv-1/payments
GET /invoices/inv-2/payments
Start from a leaf entity and navigate up:
# 1. Get payment
GET /payments/pay-789
# 2. Get its invoice (enriched)
GET /payments/pay-789/invoice
# 3. Get the order (enriched)
GET /invoices/inv-456/order
Get all entities at one level before moving to the next:
# Level 1: All orders
GET /orders
# Level 2: All invoices for each order
for each order:
GET /orders/{order_id}/invoices
# Level 3: All payments for each invoice
for each invoice:
GET /invoices/{invoice_id}/payments
# ✅ Good: Clear parent-child relationships
Order → Invoice → Payment
User → Post → Comment
# ❌ Avoid: Circular dependencies
A → B → C → A
# ✅ Good: Descriptive names
forward_route_name: invoices # /orders/123/invoices
forward_route_name: members # /projects/456/members
# ❌ Avoid: Generic names
forward_route_name: links # /orders/123/links (unclear)
forward_route_name: relations # /projects/456/relations (unclear)
# ✅ Good: Use enriched responses
GET /orders/123/invoices
# Returns invoices with full data in one request
# ❌ Avoid: Multiple separate queries
GET /orders/123/invoices # Get link IDs
GET /invoices/id1 # Then fetch each invoice
GET /invoices/id2
GET /invoices/id3
// ✅ Good: Index frequently queried fields
impl_data_entity!(Order, "order", ["number", "customer_name"], {
number: String,
customer_name: String,
});
Customer
└─► Order
├─► OrderItem (product, quantity)
├─► Invoice
│ └─► Payment
└─► Shipment
└─► TrackingEvent
Configuration:
links:
- { link_type: has_order, source_type: customer, target_type: order, forward_route_name: orders }
- { link_type: has_item, source_type: order, target_type: order_item, forward_route_name: items }
- { link_type: has_invoice, source_type: order, target_type: invoice, forward_route_name: invoices }
- { link_type: has_payment, source_type: invoice, target_type: payment, forward_route_name: payments }
- { link_type: has_shipment, source_type: order, target_type: shipment, forward_route_name: shipments }
- { link_type: has_tracking, source_type: shipment, target_type: tracking_event, forward_route_name: tracking }
Navigation:
# Customer journey
GET /customers/cust-1/orders
GET /orders/ord-123/items
GET /orders/ord-123/invoices
GET /invoices/inv-456/payments
# Fulfillment tracking
GET /orders/ord-123/shipments
GET /shipments/ship-789/tracking
Multi-level navigation makes complex data relationships simple and intuitive! 🚀🌳✨