Skip to content

Relationships

Including and querying related resources


Relationships define connections between resources. Mesh supports requesting related resources in a single call, reducing round trips and enabling efficient data fetching.


Use the relationships array to include related resources:

{
"call": {
"function": "orders.get",
"version": "1",
"arguments": {
"id": "12345",
"relationships": ["customer", "items"]
}
}
}
  • relationships is an array of relationship names
  • Related resources are returned in the included array
  • Only declared relationships can be requested
  • Order in the array does not affect response

Each relationship contains a data member with resource identifiers:

{
"data": {
"type": "order",
"id": "12345",
"attributes": { ... },
"relationships": {
"customer": {
"data": { "type": "customer", "id": "42" }
},
"items": {
"data": [
{ "type": "order_item", "id": "1" },
{ "type": "order_item", "id": "2" }
]
}
}
}
}
Typedata ValueDescription
To-one{ "type": "...", "id": "..." }Single related resource
To-many[{ "type": "...", "id": "..." }, ...]Multiple related resources
Empty to-onenullNo related resource
Empty to-many[]No related resources

When relationships are requested, full resource objects appear in included:

{
"result": {
"data": {
"type": "order",
"id": "12345",
"attributes": { "status": "pending" },
"relationships": {
"customer": {
"data": { "type": "customer", "id": "42" }
}
}
},
"included": [
{
"type": "customer",
"id": "42",
"attributes": {
"name": "Alice",
"email": "alice@example.com"
}
}
]
}
}

A compound document contains the primary resource(s) plus related resources.

{
"result": {
"data": { ... }, // Primary resource(s)
"included": [ ... ], // Related resources
"meta": { ... } // Optional metadata
}
}
  1. Each resource in included MUST be unique by type + id
  2. Resources in included MUST be referenced by at least one relationship
  3. included resources MAY have their own relationships
  4. Circular references are allowed (resource A → B → A)

When multiple resources reference the same related resource, it appears once in included:

{
"data": [
{
"type": "order",
"id": "1",
"relationships": {
"customer": { "data": { "type": "customer", "id": "42" } }
}
},
{
"type": "order",
"id": "2",
"relationships": {
"customer": { "data": { "type": "customer", "id": "42" } }
}
}
],
"included": [
{
"type": "customer",
"id": "42",
"attributes": { "name": "Alice" }
}
// Customer 42 appears only once
]
}

Request relationships of relationships using dot notation:

{
"relationships": ["customer", "items", "items.product"]
}

This includes:

  • customer - The order’s customer
  • items - The order’s line items
  • items.product - Each item’s product
{
"data": {
"type": "order",
"id": "12345",
"relationships": {
"customer": { "data": { "type": "customer", "id": "42" } },
"items": {
"data": [
{ "type": "order_item", "id": "1" },
{ "type": "order_item", "id": "2" }
]
}
}
},
"included": [
{
"type": "customer",
"id": "42",
"attributes": { "name": "Alice" }
},
{
"type": "order_item",
"id": "1",
"attributes": { "quantity": 2, "price": { "amount": "29.99", "currency": "USD" } },
"relationships": {
"product": { "data": { "type": "product", "id": "prod_abc" } }
}
},
{
"type": "order_item",
"id": "2",
"attributes": { "quantity": 1, "price": { "amount": "49.99", "currency": "USD" } },
"relationships": {
"product": { "data": { "type": "product", "id": "prod_xyz" } }
}
},
{
"type": "product",
"id": "prod_abc",
"attributes": { "name": "Widget", "sku": "WDG-001" }
},
{
"type": "product",
"id": "prod_xyz",
"attributes": { "name": "Gadget", "sku": "GDG-002" }
}
]
}

Servers SHOULD enforce a maximum nesting depth (e.g., 3 levels):

// Allowed
"items.product.category"
// May be rejected
"items.product.category.parent.parent"

Servers MUST define which relationships are available:

{
"relationships": ["customer", "items", "shipping_address", "billing_address"]
}
  • Requesting non-allowed relationships MUST return an error
  • Servers SHOULD expose allowed relationships via mesh.describe
{
"errors": [{
"code": "INVALID_ARGUMENTS",
"message": "Relationship not allowed: secret_notes",
"retryable": false,
"source": {
"pointer": "/call/arguments/relationships/2"
},
"details": {
"relationship": "secret_notes",
"allowed": ["customer", "items", "shipping_address", "billing_address"]
}
}]
}

Filter the primary resource based on related resource attributes:

{
"filters": {
"self": [
{ "attribute": "status", "operator": "equals", "value": "pending" }
],
"customer": [
{ "attribute": "type", "operator": "equals", "value": "vip" }
]
},
"relationships": ["customer"]
}

This returns orders that:

  1. Have status “pending”
  2. Have a customer with type “vip”
SELECT orders.* FROM orders
JOIN customers ON customers.id = orders.customer_id
WHERE orders.status = 'pending'
AND customers.type = 'vip'

See Filtering for complete filter syntax.


Control which fields are returned for related resources:

{
"fields": {
"self": ["id", "status", "total_amount"],
"customer": ["id", "name"],
"items": ["id", "quantity", "price"]
},
"relationships": ["customer", "items"]
}

See Sparse Fieldsets for field selection details.


Request relationship data without full resources:

// Request without relationships array
{
"arguments": {
"id": "12345"
}
}
// Response includes relationship identifiers but no included array
{
"data": {
"type": "order",
"id": "12345",
"attributes": { ... },
"relationships": {
"customer": {
"data": { "type": "customer", "id": "42" }
}
}
}
// No "included" - only identifiers
}

This allows clients to:

  • See what relationships exist
  • Fetch related resources separately if needed
  • Reduce payload when relationships aren’t needed

// Request
{
"protocol": { "name": "mesh", "version": "0.1.0" },
"id": "req_single",
"call": {
"function": "orders.get",
"version": "1",
"arguments": {
"id": "12345",
"relationships": ["customer"]
}
}
}
// Response
{
"protocol": { "name": "mesh", "version": "0.1.0" },
"id": "req_single",
"result": {
"data": {
"type": "order",
"id": "12345",
"attributes": {
"status": "pending",
"total_amount": { "amount": "99.99", "currency": "USD" }
},
"relationships": {
"customer": {
"data": { "type": "customer", "id": "42" }
}
}
},
"included": [
{
"type": "customer",
"id": "42",
"attributes": {
"name": "Alice",
"email": "alice@example.com"
}
}
]
}
}
// Request
{
"protocol": { "name": "mesh", "version": "0.1.0" },
"id": "req_multi",
"call": {
"function": "shipments.get",
"version": "1",
"arguments": {
"id": "ship_123",
"fields": {
"self": ["id", "tracking_number", "status"],
"origin": ["id", "name", "country_code"],
"destination": ["id", "name", "country_code"]
},
"relationships": ["origin", "destination", "events"]
}
}
}
// Response
{
"protocol": { "name": "mesh", "version": "0.1.0" },
"id": "req_multi",
"result": {
"data": {
"type": "shipment",
"id": "ship_123",
"attributes": {
"tracking_number": "MH726955185FI",
"status": "in_transit"
},
"relationships": {
"origin": {
"data": { "type": "location", "id": "loc_001" }
},
"destination": {
"data": { "type": "location", "id": "loc_002" }
},
"events": {
"data": [
{ "type": "tracking_event", "id": "evt_001" },
{ "type": "tracking_event", "id": "evt_002" }
]
}
}
},
"included": [
{
"type": "location",
"id": "loc_001",
"attributes": {
"name": "Helsinki Warehouse",
"country_code": "FI"
}
},
{
"type": "location",
"id": "loc_002",
"attributes": {
"name": "Tampere Office",
"country_code": "FI"
}
},
{
"type": "tracking_event",
"id": "evt_001",
"attributes": {
"status": "picked_up",
"location": "Helsinki",
"occurred_at": "2024-01-14T10:00:00Z"
}
},
{
"type": "tracking_event",
"id": "evt_002",
"attributes": {
"status": "in_transit",
"location": "Highway",
"occurred_at": "2024-01-15T08:00:00Z"
}
}
]
}
}
// Request
{
"protocol": { "name": "mesh", "version": "0.1.0" },
"id": "req_collection",
"call": {
"function": "orders.list",
"version": "1",
"arguments": {
"fields": {
"self": ["id", "status", "created_at"],
"customer": ["id", "name"]
},
"filters": [
{ "attribute": "status", "operator": "in", "value": ["pending", "processing"] }
],
"relationships": ["customer"],
"pagination": {
"limit": 10
}
}
}
}
// Response
{
"protocol": { "name": "mesh", "version": "0.1.0" },
"id": "req_collection",
"result": {
"data": [
{
"type": "order",
"id": "12345",
"attributes": {
"status": "pending",
"created_at": "2024-01-15T10:30:00Z"
},
"relationships": {
"customer": {
"data": { "type": "customer", "id": "42" }
}
}
},
{
"type": "order",
"id": "12346",
"attributes": {
"status": "processing",
"created_at": "2024-01-15T11:00:00Z"
},
"relationships": {
"customer": {
"data": { "type": "customer", "id": "42" }
}
}
}
],
"included": [
{
"type": "customer",
"id": "42",
"attributes": {
"name": "Alice"
}
}
],
"meta": {
"page": {
"cursor": {
"current": "...",
"next": "..."
}
}
}
}
}
// Request
{
"protocol": { "name": "mesh", "version": "0.1.0" },
"id": "req_nested",
"call": {
"function": "orders.get",
"version": "1",
"arguments": {
"id": "12345",
"fields": {
"self": ["id", "status"],
"items": ["id", "quantity"],
"items.product": ["id", "name", "sku"]
},
"relationships": ["items", "items.product"]
}
}
}
// Response
{
"protocol": { "name": "mesh", "version": "0.1.0" },
"id": "req_nested",
"result": {
"data": {
"type": "order",
"id": "12345",
"attributes": {
"status": "pending"
},
"relationships": {
"items": {
"data": [
{ "type": "order_item", "id": "1" },
{ "type": "order_item", "id": "2" }
]
}
}
},
"included": [
{
"type": "order_item",
"id": "1",
"attributes": {
"quantity": 2
},
"relationships": {
"product": {
"data": { "type": "product", "id": "prod_abc" }
}
}
},
{
"type": "order_item",
"id": "2",
"attributes": {
"quantity": 1
},
"relationships": {
"product": {
"data": { "type": "product", "id": "prod_xyz" }
}
}
},
{
"type": "product",
"id": "prod_abc",
"attributes": {
"name": "Widget",
"sku": "WDG-001"
}
},
{
"type": "product",
"id": "prod_xyz",
"attributes": {
"name": "Gadget",
"sku": "GDG-002"
}
}
]
}
}

Functions SHOULD advertise available relationships via mesh.describe:

{
"result": {
"function": "orders.list",
"query": {
"relationships": {
"available": ["customer", "items", "shipping_address", "billing_address"],
"nested": {
"items": ["product", "product.category"]
},
"max_depth": 3
}
}
}
}