[ADP-360] Resource Expansion
Guidance
SHOULD NOT return standalone subresources by default
httpGET /orders/{orderId} HTTP/1.1 { "orderId": "12345", "customerName": "John Doe", "totalPrice": 100.00, "orderedAt": "2024-07-05" }
The resource is expected to have items and shippings as standalone subresources (e.g., each resource has its own id)
INFO
For performance optimization, subresources (like items and shippings) should be maintained as standalone resources with their own identifiers. This approach enables efficient resource management and scalability.
While you may design an API to return all related resources in a single response, this must be explicitly documented in the API specification. This principle provides a standardized mechanism for expanding related resources that are not included in the default response.
SHOULD support embedding subresources by
embed
query parameterhttpGET /orders/{order-id}?embed=(items) { "orderId": "12345", "customerName": "John Doe", "totalPrice": 100.00, "items": [ { "orderItemId": "1", "productId": "987", "productName": "Widget", "quantity": 2, "price": 25.00 }, { "orderItemId": "2", "productId": "654", "productName": "Gadget", "quantity": 1, "price": 50.00 } ], "shipping": { "shippingId": "56789", "carrier": "UPS", "trackingNumber": "1Z9999999999999999", "estimatedDeliveryDate": "2024-07-10" } }
SHOULD use standard JSON structure for embedded resources with clear property naming
httpGET /orders/{order-id}?embed=(items,shippings) { "id": "uuid-...", "orderId": "12345", "customerName": "John Doe", "totalPrice": 100.00, "items": [ { "orderItemId": "1", "productId": "987", "productName": "Widget", "quantity": 2, "price": 25.00, "links": { "self": "/products/987" } }, { "orderItemId": "2", "productId": "654", "productName": "Gadget", "quantity": 1, "price": 50.00, "links": { "self": "/products/654" } } ], "shipping": { "shippingId": "56789", "carrier": "UPS", "trackingNumber": "1Z9999999999999999", "estimatedDeliveryDate": "2024-07-10", "links": { "self": "/shippings/56789" } } }
SHOULD use Link headers for navigation between resources according to RFC 8288
httpGET /orders/12345?embed=(items,shippings) HTTP/1.1 HTTP/1.1 200 OK Content-Type: application/json Link: </orders/12345>; rel="self", </orders/12345/items>; rel="items", </orders/12345/shippings>; rel="shippings" { "id": "uuid-...", "orderId": "12345", "customerName": "John Doe", "totalPrice": 100.00, "items": [...], "shipping": {...} }
SHOULD document the available embed options in the API specification
SHOULD limit the depth of embedded resources to prevent performance issues
SHOULD implement proper error handling for invalid embed requests
OpenAPI 3.1.0 Example
openapi: 3.1.0
info:
title: Order API
version: 1.0.0
paths:
/orders/{orderId}:
get:
summary: Get an order
parameters:
- name: embed
in: query
description: Embed related resources
schema:
type: array
items:
type: string
enum:
- items
- shippings
collectionFormat: csv
responses:
'200':
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/Order'
components:
schemas:
Order:
type: object
properties:
orderId:
type: string
customerName:
type: string
totalPrice:
type: number
orderedAt:
type: string
items:
type: array
items:
$ref: '#/components/schemas/OrderItem'
shipping:
$ref: '#/components/schemas/Shipping'
OrderItem:
type: object
properties:
orderItemId:
type: string
productId:
type: string
productName:
type: string
quantity:
type: integer
price:
type: number
Shipping:
type: object
properties:
shippingId:
type: string
carrier:
type: string
trackingNumber:
type: string
estimatedDeliveryDate:
type: string
References
Design References
- https://opensource.zalando.com/restful-api-guidelines/#158
- https://api.otto.de/portal/guidelines/rest-guidelines/resources
Changelog
2025-03-07
: Added performance clarification and cross-references to related ADPs.