Skip to content
ADP
API Design PrincipleBETA

[ADP-137] Range

Overview

The Range header in HTTP allows clients to request specific portions of a resource, rather than the entire resource. This can be useful for efficiently handling large data sets, providing partial responses, and supporting resumable downloads. While primarily used for byte ranges, it can also be adapted for other units in RESTful APIs, such as items or records. However, careful documentation and adherence to standards are necessary to ensure correct implementation and client-server interaction.

Guidance

  • The Range header SHOULD NOT be used for pagination. Refer to ADP-312: Pagination for preferred practices.

    • If pagination based on Range must be used, clearly specify the units being used.

    • Example of Range-based pagination:

      ```http
      GET /users
      Range: users=0-9
      
      206 Partial Content
      Accept-Ranges: users
      Content-Range: users 0-9/200
      ```
      
    • In the example above, the unit is users. It should be the plural form of the resource/entity type.

  • For more complex use cases, the Range header MAY specify byte ranges, as detailed in RFC 9110.

    • Example of byte range values:

      ```
      bytes=-500
      bytes=9500-
      bytes=0-0,-1
      bytes=0-999,4500-5499,-1000
      ```
      
  • The server SHOULD respond with HTTP status 416 (Range Not Satisfiable) if the requested Range cannot be fulfilled or the specified unit is not supported.

    • Use HTTP Problem Details (RFC 9457) to provide more information about the error.

      ```http
      GET /images/{image-id} HTTP/1.1
      Range: bytes=500-509
      
      HTTP/1.1 416 Range Not Satisfiable
      Content-Type: application/problem+json
      Content-Range: */200
      {
        "type": "/problems/range-not-satisfiable",
        "title": "Range Not Satisfiable",
        "status": 416,
        "detail": "The requested range cannot be satisfied",
        "instance": "/images/{image-id}"
      }
      ```
      

Example

Consider an API endpoint for retrieving parts of a large file. Here’s how you might implement Range headers for partial content retrieval

http
GET /largefile HTTP/1.1
Range: bytes=0-999

HTTP/1.1 206 Partial Content
Accept-Ranges: bytes
Content-Range: bytes 0-999/5000

If the client requests a range that cannot be satisfied:

http
GET /largefile
Range: bytes=6000-6999

HTTP/1.1 416 Range Not Satisfiable
Content-Type: application/problem+json
Content-Range: */5000
{
  "type": "https://example.com/problems/range-not-satisfiable",
  "title": "Range Not Satisfiable",
  "status": 416,
  "detail": "The requested range cannot be satisfied",
  "instance": "/largefile"
}

OpenAPI Example

To document the use of the Range header in OpenAPI specifications, you can use the following example:

yaml
openapi: 3.1.0
info:
  title: Large File API
  version: 1.0.0
paths:
  /largefile:
    get:
      summary: Retrieve a range of bytes from a large file
      parameters:
        - name: Range
          in: header
          required: false
          schema:
            type: string
            example: bytes=0-999
          description: Range header to request a specific range of bytes.
      responses:
        '206':
          description: Partial Content
          headers:
            Accept-Ranges:
              description: Supported units for the Range header
              schema:
                type: string
            Content-Range:
              description: The range of bytes returned
              schema:
                type: string
          content:
            application/octet-stream:
              schema:
                type: string
                format: binary
        '416':
          description: Range Not Satisfiable
          headers:
            Content-Range:
              description: The actual range of the resource
              schema:
                type: string
          content:
            application/problem+json:
              schema:
                type: object
                properties:
                  type:
                    type: string
                    example: "https://example.com/problems/range-not-satisfiable"
                  title:
                    type: string
                    example: "Range Not Satisfiable"
                  status:
                    type: integer
                    example: 416
                  detail:
                    type: string
                    example: "The requested range cannot be satisfied"
                  instance:
                    type: string
                    example: "/largefile"
        '200':
          description: Successful response (if no Range header is used)
        '400':
          description: Bad Request (if the Range header is malformed)

Refrain from redefining known headers

As per ADP-767, you SHOULD utilize the external headers definition YAML or reference #/components/headers using $refs, thereby avoiding the redefinition of known headers across all operations.

Semantics

Refer to ADP-351: Range Requests.

References