Skip to content

Pagination: nextURL from Link: rel="next" can drop original query filters #17

@ronaldmannak

Description

@ronaldmannak

swift-huggingface currently exposes pagination via PaginatedResponse.nextURL (parsed from the HTTP Link header). In practice, the rel="next" URL returned by HuggingFace omits query parameters from the original request (e.g. author, limit, search, filter). Following nextURL as-is can therefore return an incorrect next page (e.g. “all models” instead of “models from mlx-community”).

This makes nextURL a confusing/unsafe abstraction for callers, because they can’t reliably fetch the next page without also reconstructing the URL using the original filters.

Reproducing

  1. Call listModels with filters:
   let page1 = try await client.listModels(
       author: "mlx-community",
       limit: 1000
   )
   print(page1.nextURL)
  1. Copy the url in a browser and notice the models in the list are all models, not just mlx-community.

Suggested fix

Replace the nextURL property of PaginatedResponse to the cursor only and update parseNextPageURL

/// A response that includes pagination information from Link headers.
public struct PaginatedResponse<T: Decodable & Sendable>: Sendable {
    /// The items in the current page.
    public let items: [T]

    /// The cursor for the next page, if available.
    public let cursor: String?
...

Then perhaps add an optional cursor to the HubClient methods that return PaginatedResponse like so:

    public func listModels(
        search: String? = nil,
        author: String? = nil,
        filter: String? = nil,
        sort: String? = nil,
        direction: SortDirection? = nil,
        limit: Int? = nil,
        full: Bool? = nil,
        config: Bool? = nil,
        cursor: String?
    ) async throws -> PaginatedResponse<Model> {
...

I'm happy to create a PR or add these changes to the PR #16

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions