Versioning & Pagination

When designing a production API, you must assume two things: your data will grow infinitely, and your business requirements will change constantly.

To handle infinite data, you need Pagination. To handle changing requirements without breaking existing clients, you need Versioning.

1. Versioning Strategies

When you introduce a breaking change (like deleting a required field or changing a data structure), you must create a new version of the API. Old mobile apps floating around in the wild must continue to work.

URL Path Versioning (The Standard)

The version is baked directly into the URL. GET https://api.example.com/v1/users

Header Versioning

The client sends a custom header. Accept: application/vnd.example.v1+json or X-API-Version: 2024-01-01 (Stripe's method).

2. Pagination: Offset vs. Cursor

If an endpoint returns 50,000 records, sending them all in one JSON payload will crash the server and the client. You must paginate the results.

There are two dominant strategies for pagination.

Offset-Based Pagination (The Easy Way)

The client provides a page number and a limit. The database skips the first N records.

GET /users?page=3&limit=20

How it works in SQL:

SELECT * FROM users ORDER BY created_at DESC LIMIT 20 OFFSET 40;

Pros:

Cons (The Danger):

Cursor-Based Pagination (The Scalable Way)

The client provides a unique pointer (a Cursor) to a specific record, and asks for the next X records after it. The Cursor is usually an ID or a Timestamp.

GET /users?limit=20&after=user_id_987

How it works in SQL:

SELECT * FROM users WHERE id > 987 ORDER BY id ASC LIMIT 20;

[!TIP] ELI5: The Bookmark

  • Offset: "Open the book and flip exactly 400 pages." (You have to physically count 400 pages every time).
  • Cursor: "Open the book directly to the Bookmark I left on page 400." (Instant access).

Pros:

Cons:

[!IMPORTANT] Interview Rule of Thumb: If the list is small (like comments on a blog post) or requires jumping to specific pages, use Offset. If the list is infinite (like a Twitter timeline or a massive log stream), you must use Cursor-based pagination.