Skip to content
ADP
API Design PrincipleBETA

[ADP-360] Resource Expansion

Guidance

  • SHOULD NOT return standalone subresources by default

    http
    GET /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 parameter

    http
    GET /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

    http
    GET /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

    http
    GET /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

yaml
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

Changelog

  • 2025-03-07: Added performance clarification and cross-references to related ADPs.