Skip to content

Feat/gh7137 content range#7856

Open
Nayte91 wants to merge 3 commits intoapi-platform:mainfrom
Nayte91:feat/GH7137-content-range
Open

Feat/gh7137 content range#7856
Nayte91 wants to merge 3 commits intoapi-platform:mainfrom
Nayte91:feat/GH7137-content-range

Conversation

@Nayte91
Copy link

@Nayte91 Nayte91 commented Mar 19, 2026

Q A
Branch? main
Tickets #7137
License MIT
Doc PR no but I can do this after

Pagination in headers: Range request header and content-range response handling.

I created a PR for this topic, please see the issue for the main idea.

For now, there is 3 separate commits:

  • 1 for content-range response
  • 1 for range request
  • More tests/misc additions

I also did a specific testfiles, ContentRangeHeaderTest & RangeHeaderProviderTest to help designing the feature. We can totally merge everything in other testfiles if wanted.

Content-range response header

This commit adds RFC 9110-compliant Content-Range and Accept-Ranges response headers to all paginated collection endpoints.

RFC 9110 sections followed

§14.4 Content-Range — defines the header grammar: range-unit SP (range-resp/unsatisfied-range). We use custom range units (for example book) as allowed by the extensible range unit mechanism. The unsatisfied-range production (*/complete-length) requires complete-length to be a digit, so the header is omitted when both the page is empty and the total is unknown (since */* would be invalid ABNF).
§14.3 Accept-Ranges — advertises which range unit the server supports for a given resource. Sent on every paginated collection response.
§14.1 Range Units — confirms that range units are extensible tokens, not limited to bytes.
§15.3.7 206 Partial Content — clarifies that 206 is strictly reserved for responses to Range requests. Since this commit only handles the response side (no Range request parsing yet), the status code remains 200.

Main logic implemented

  • Private method HttpResponseHeadersTrait::addContentRangeHeaders() — fetches range from paginator (0-indexed offsets) and emits the Content-Range & Accept-Ranges headers.

Tests

  • Dedicated ContentRangeHeaderTest — 11 test cases covering partial collections, full collections, page offsets, unknown totals, empty pages, non-collection operations, and the unit fallback.

Range request header

This commit adds server-side parsing of the Range request header, enabling clients to request specific slices of a collection via standard HTTP semantics.

RFC 9110 sections followed

§14.2 Range — defines the request header format: Range: <unit>=<first-pos>-<last-pos>. Unrecognized formats or units are silently ignored (the server delegates normally), as recommended by the spec.
§15.3.7 206 Partial Content — the response status when a valid Range request is successfully fulfilled. The operation status is set to 206 so RespondProcessor returns it alongside the Content-Range header.
§15.5.17 416 Range Not Satisfiable — returned when the range is syntactically valid but not satisfiable (start > end, or range not aligned to page boundaries).

Main logic implemented

  • A new RangeHeaderProvider decorator on the read provider — parses the Range header, converts the range to page/itemsPerPage pagination filters via _api_filters, and sets the operation status to 206. Follows the same decorator pattern as JsonApiProvider.
  • Service registration in provider.php — decorates api_platform.state_provider.read (at priority 1).

Tests

  • A dedicated RangeHeaderProviderTest — 9 unit tests covering delegation (no header, wrong operation type, wrong HTTP method), ignored formats (unparseable, wrong unit), valid ranges, and 416 errors.
  • Two additional integration tests in ContentRangeHeaderTest — verify the full flow: Range header in → 206 status + Content-Range header out.

Limitations & concerns

  1. Potential BC break for projects that use and make proper implementation of those headers
  2. API break if status codes are willing to change (if your project is wired to make things on 200 responses but API-Platform fires some 206),
  3. current use of a HEAD verb, to just receive pagination through header's Content-range, doesn't save any cycles as it is processed just like a GET. The content is stripped right before sending the response. There's a clear room for improvement here!
  4. In committed files there's a lot of comments with RFC links, to help reviewing. It's meant to be removed.

The point 3 is the most concerning and also the most enjoyable to address. But for now I would like to know if concept/philosophy/first draft of implementation is ok for you guys.

@Nayte91 Nayte91 force-pushed the feat/GH7137-content-range branch from 8d0ede3 to faff142 Compare March 19, 2026 16:30
@Nayte91 Nayte91 force-pushed the feat/GH7137-content-range branch from faff142 to 7f9c148 Compare March 19, 2026 16:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant