Thực hành tốt nhất về phân trang API


288

Tôi muốn một số trợ giúp xử lý trường hợp cạnh lạ với API được phân trang.

Giống như nhiều API, cái này phân trang kết quả lớn. Nếu bạn truy vấn / foos, bạn sẽ nhận được 100 kết quả (ví dụ: foo # 1-100) và liên kết đến / foos? Page = 2 sẽ trả về foo # 101-200.

Thật không may, nếu foo # 10 bị xóa khỏi tập dữ liệu trước khi người tiêu dùng API thực hiện truy vấn tiếp theo, / foos? Page = 2 sẽ bù 100 và trả về foos # 102-201.

Đây là một vấn đề đối với người tiêu dùng API, những người đang cố gắng kéo tất cả các foos - họ sẽ không nhận được foo # 101.

Cách thực hành tốt nhất để xử lý việc này là gì? Chúng tôi muốn làm cho nó nhẹ nhất có thể (nghĩa là tránh xử lý các phiên cho các yêu cầu API). Các ví dụ từ các API khác sẽ được đánh giá rất cao!


1
vấn đề ở đây là gì? Đối với tôi, có vẻ như ok, người dùng sẽ nhận được 100 mặt hàng.
NARKOZ

2
Tôi đã phải đối mặt với vấn đề tương tự và tìm kiếm một giải pháp. AFAIK, thực sự không có cơ chế bảo đảm vững chắc để thực hiện điều này, nếu mỗi trang thực hiện một truy vấn mới. Giải pháp duy nhất tôi có thể nghĩ đến là giữ một phiên hoạt động và giữ kết quả được đặt ở phía máy chủ, thay vì thực hiện các truy vấn mới cho mỗi trang, chỉ cần lấy bộ bản ghi được lưu trong bộ nhớ cache tiếp theo.
Jerry Dodge

31
Hãy xem cách twitter đạt được dev.twitter.com/rest/public/timelines
java_geek

1
@java_geek Thông số from_id được cập nhật như thế nào? Trong trang web twitter, có vẻ như họ đang thực hiện cả hai yêu cầu có cùng giá trị cho from_id. Tôi tự hỏi khi nào nó sẽ được cập nhật để nếu các tweet mới hơn được thêm vào, chúng có thể được tính?
Petar

1
@Petar Tham số from_id cần được cập nhật bởi người tiêu dùng API. Nếu bạn thấy, ví dụ ở đây đề cập đến các ứng dụng khách đang xử lý các tweet
java_geek

Câu trả lời:


175

Tôi không hoàn toàn chắc chắn làm thế nào dữ liệu của bạn được xử lý, vì vậy điều này có thể hoặc không hoạt động, nhưng bạn đã xem xét phân trang với trường dấu thời gian chưa?

Khi bạn truy vấn / foos bạn nhận được 100 kết quả. API của bạn sau đó sẽ trả về một cái gì đó như thế này (giả sử JSON, nhưng nếu nó cần XML thì các nguyên tắc tương tự có thể được tuân theo):

{
    "data" : [
        {  data item 1 with all relevant fields    },
        {  data item 2   },
        ...
        {  data item 100 }
    ],
    "paging":  {
        "previous":  "http://api.example.com/foo?since=TIMESTAMP1" 
        "next":  "http://api.example.com/foo?since=TIMESTAMP2"
    }

}

Chỉ cần một lưu ý, chỉ sử dụng một dấu thời gian phụ thuộc vào 'giới hạn' ngầm trong kết quả của bạn. Bạn có thể muốn thêm một giới hạn rõ ràng hoặc cũng có thể sử dụng một thuộc untiltính.

Dấu thời gian có thể được xác định động bằng cách sử dụng mục dữ liệu cuối cùng trong danh sách. Điều này dường như ít nhiều là cách Facebook phân trang trong API đồ thị của nó (cuộn xuống phía dưới để xem các liên kết phân trang theo định dạng tôi đã đưa ra ở trên).

Một vấn đề có thể là nếu bạn thêm một mục dữ liệu, nhưng dựa trên mô tả của bạn, có vẻ như chúng sẽ được thêm vào cuối (nếu không, hãy cho tôi biết và tôi sẽ xem liệu tôi có thể cải thiện điều này không).


29
Dấu thời gian không được đảm bảo là duy nhất. Đó là, nhiều tài nguyên có thể được tạo với cùng dấu thời gian. Vì vậy, cách tiếp cận này có nhược điểm là trang tiếp theo, có thể lặp lại các mục (vài?) Cuối cùng từ trang hiện tại.
rúp

4
@prmatta Trên thực tế, tùy thuộc vào cơ sở dữ liệu triển khai, dấu thời gian được đảm bảo là duy nhất .
ramblinjan

2
@jandjorgensen Từ liên kết của bạn: "Kiểu dữ liệu dấu thời gian chỉ là số tăng và không lưu giữ ngày hoặc thời gian. ... Trong máy chủ SQL 2008 trở về sau, loại dấu thời gian đã được đổi tên thành chuyển đổi dòng , có lẽ để phản ánh tốt hơn mục đích và giá trị. " Vì vậy, không có bằng chứng nào ở đây cho thấy dấu thời gian (những cái thực sự chứa giá trị thời gian) là duy nhất.
Nolan Amy

3
@jandjorgensen Tôi thích đề xuất của bạn, nhưng bạn sẽ không cần một số loại thông tin trong các liên kết tài nguyên, vì vậy chúng tôi biết nếu chúng tôi đi trước hoặc tiếp theo? Sth like: "trước": " api.example.com/foo?b Before = TIMESTAMP " "next": " api.example.com/foo?since=TIMESTAMP2 " Chúng tôi cũng sẽ sử dụng id chuỗi của chúng tôi thay vì dấu thời gian. Bạn có thấy bất kỳ vấn đề với điều đó?
longliveenduro

5
Một tùy chọn tương tự khác là sử dụng trường tiêu đề Liên kết được chỉ định trong RFC 5988 (phần 5): tools.ietf.org/html/rfc5988#page-6
Anthony F

28

Bạn có một số vấn đề.

Đầu tiên, bạn có ví dụ mà bạn đã trích dẫn.

Bạn cũng gặp vấn đề tương tự nếu các hàng được chèn, nhưng trong trường hợp này, người dùng nhận được dữ liệu trùng lặp (có thể dễ quản lý hơn dữ liệu bị thiếu, nhưng vẫn là một vấn đề).

Nếu bạn không chụp nhanh tập dữ liệu gốc, thì đây chỉ là thực tế của cuộc sống.

Bạn có thể yêu cầu người dùng thực hiện một ảnh chụp nhanh rõ ràng:

POST /createquery
filter.firstName=Bob&filter.lastName=Eubanks

Kết quả nào:

HTTP/1.1 301 Here's your query
Location: http://www.example.org/query/12345

Sau đó, bạn có thể trang đó cả ngày, vì nó hiện tĩnh. Đây có thể là trọng lượng hợp lý nhẹ, vì bạn chỉ có thể chụp các khóa tài liệu thực tế chứ không phải toàn bộ các hàng.

Nếu trường hợp sử dụng chỉ đơn giản là người dùng của bạn muốn (và cần) tất cả dữ liệu, thì bạn có thể chỉ cần cung cấp cho họ:

GET /query/12345?all=true

và chỉ cần gửi toàn bộ.


1
(Loại
foos

Trên thực tế, chỉ chụp các khóa tài liệu là không đủ. Bằng cách này, bạn sẽ phải truy vấn các đối tượng đầy đủ bằng ID khi người dùng yêu cầu chúng, nhưng có thể chúng không còn tồn tại.
Scadge

27

Nếu bạn đã phân trang, bạn cũng sắp xếp dữ liệu theo một số phím. Tại sao không để các máy khách API bao gồm khóa của phần tử cuối cùng của bộ sưu tập được trả về trước đó trong URL và thêm một WHEREmệnh đề vào truy vấn SQL của bạn (hoặc một cái gì đó tương đương, nếu bạn không sử dụng SQL) để nó chỉ trả về các phần tử mà khóa nào lớn hơn giá trị này?


4
Đây không phải là một gợi ý tồi, tuy nhiên chỉ vì bạn sắp xếp theo một giá trị không có nghĩa đó là 'khóa', tức là duy nhất.
Chris Peacock

Chính xác. Ví dụ, trong trường hợp của tôi, trường sắp xếp là một ngày và nó không phải là duy nhất.
Sat Thiru

19

Có thể có hai cách tiếp cận tùy thuộc vào logic phía máy chủ của bạn.

Cách tiếp cận 1: Khi máy chủ không đủ thông minh để xử lý các trạng thái đối tượng.

Bạn có thể gửi tất cả id duy nhất của bản ghi được lưu trong bộ nhớ cache đến máy chủ, ví dụ: "id1", "id2", "id3", "id4", "id5", "id6", "id7", "id8", "id9", "id10"] và tham số boolean để biết bạn đang yêu cầu bản ghi mới (kéo để làm mới) hoặc bản ghi cũ (tải thêm).

Máy chủ của bạn phải có trách nhiệm trả lại các bản ghi mới (tải thêm bản ghi hoặc bản ghi mới thông qua pull để làm mới) cũng như id của các bản ghi đã bị xóa từ ["id1", "id2", "id3", "id4", "id5", " id6 "," id7 "," id8 "," id9 "," id10 "].

Ví dụ: - Nếu bạn đang yêu cầu tải nhiều hơn thì yêu cầu của bạn sẽ giống như thế này: -

{
        "isRefresh" : false,
        "cached" : ["id1","id2","id3","id4","id5","id6","id7","id8","id9","id10"]
}

Bây giờ, giả sử bạn đang yêu cầu các bản ghi cũ (tải thêm) và giả sử bản ghi "id2" được cập nhật bởi ai đó và các bản ghi "id5" và "id8" bị xóa khỏi máy chủ thì phản hồi máy chủ của bạn sẽ giống như thế này: -

{
        "records" : [
{"id" :"id2","more_key":"updated_value"},
{"id" :"id11","more_key":"more_value"},
{"id" :"id12","more_key":"more_value"},
{"id" :"id13","more_key":"more_value"},
{"id" :"id14","more_key":"more_value"},
{"id" :"id15","more_key":"more_value"},
{"id" :"id16","more_key":"more_value"},
{"id" :"id17","more_key":"more_value"},
{"id" :"id18","more_key":"more_value"},
{"id" :"id19","more_key":"more_value"},
{"id" :"id20","more_key":"more_value"}],
        "deleted" : ["id5","id8"]
}

Nhưng trong trường hợp này nếu bạn có nhiều bản ghi lưu trữ cục bộ giả sử 500, thì chuỗi yêu cầu của bạn sẽ quá dài như sau: -

{
        "isRefresh" : false,
        "cached" : ["id1","id2","id3","id4","id5","id6","id7","id8","id9","id10",………,"id500"]//Too long request
}

Cách tiếp cận 2: Khi máy chủ đủ thông minh để xử lý các trạng thái đối tượng theo ngày.

Bạn có thể gửi id của bản ghi đầu tiên và bản ghi cuối cùng và thời gian kỷ nguyên yêu cầu trước đó. Theo cách này, yêu cầu của bạn luôn nhỏ ngay cả khi bạn có một lượng lớn các bản ghi được lưu trong bộ nhớ cache

Ví dụ: - Nếu bạn đang yêu cầu tải nhiều hơn thì yêu cầu của bạn sẽ giống như thế này: -

{
        "isRefresh" : false,
        "firstId" : "id1",
        "lastId" : "id10",
        "last_request_time" : 1421748005
}

Máy chủ của bạn có trách nhiệm trả lại id của các bản ghi đã bị xóa sau last_Vquest_time cũng như trả về bản ghi được cập nhật sau last_Vquest_time giữa "id1" và "id10".

{
        "records" : [
{"id" :"id2","more_key":"updated_value"},
{"id" :"id11","more_key":"more_value"},
{"id" :"id12","more_key":"more_value"},
{"id" :"id13","more_key":"more_value"},
{"id" :"id14","more_key":"more_value"},
{"id" :"id15","more_key":"more_value"},
{"id" :"id16","more_key":"more_value"},
{"id" :"id17","more_key":"more_value"},
{"id" :"id18","more_key":"more_value"},
{"id" :"id19","more_key":"more_value"},
{"id" :"id20","more_key":"more_value"}],
        "deleted" : ["id5","id8"]
}

Kéo để làm mới:-

nhập mô tả hình ảnh ở đây

Tải thêm

nhập mô tả hình ảnh ở đây


14

Có thể khó tìm thấy các thực tiễn tốt nhất vì hầu hết các hệ thống có API không phù hợp với kịch bản này, bởi vì đó là một lợi thế cực kỳ hoặc chúng thường không xóa các bản ghi (Facebook, Twitter). Facebook thực sự cho biết mỗi "trang" có thể không có số lượng kết quả được yêu cầu do quá trình lọc được thực hiện sau khi phân trang. https://developers.facebook.com/blog/post/478/

Nếu bạn thực sự cần điều chỉnh trường hợp cạnh này, bạn cần "nhớ" nơi bạn rời đi. đề xuất của jandjorgensen chỉ là về vị trí, nhưng tôi sẽ sử dụng một trường được đảm bảo là duy nhất như khóa chính. Bạn có thể cần sử dụng nhiều hơn một lĩnh vực.

Theo dòng chảy của Facebook, bạn có thể (và nên) lưu trữ các trang đã yêu cầu và chỉ trả lại những trang có hàng đã xóa được lọc nếu họ yêu cầu một trang mà họ đã yêu cầu.


2
Đây không phải là một giải pháp chấp nhận được. Đó là đáng kể thời gian và bộ nhớ tiêu thụ. Tất cả dữ liệu đã xóa cùng với dữ liệu được yêu cầu sẽ cần được lưu trong bộ nhớ, có thể hoàn toàn không được sử dụng nếu cùng một người dùng không yêu cầu thêm bất kỳ mục nào.
Deepak Garg

3
Tôi không đồng ý. Chỉ giữ các ID duy nhất không sử dụng nhiều bộ nhớ. Bạn không giữ lại dữ liệu vô thời hạn, chỉ trong "phiên". Điều này thật dễ dàng với memcache, chỉ cần đặt thời lượng hết hạn (tức là 10 phút).
Brent Baisley

bộ nhớ rẻ hơn tốc độ mạng / CPU. Vì vậy, nếu tạo ra một trang là rất tốn kém (về mạng hoặc là CPU chuyên sâu), sau đó bộ nhớ đệm kết quả là một cách tiếp cận hợp lệ @DeepakGarg
U Avalos

9

Phân trang nói chung là một hoạt động "người dùng" và để ngăn chặn quá tải cả trên máy tính và bộ não con người mà bạn thường đưa ra một tập hợp con. Tuy nhiên, thay vì nghĩ rằng chúng tôi không có được toàn bộ danh sách, có thể tốt hơn để hỏi liệu có vấn đề gì không?

Nếu cần một chế độ xem cuộn trực tiếp chính xác, các API REST có yêu cầu / phản hồi về bản chất không phù hợp cho mục đích này. Đối với điều này, bạn nên xem xét các sự kiện WebSockets hoặc HTML5 Server-Sent để cho giao diện của bạn biết khi xử lý các thay đổi.

Bây giờ nếu có nhu cầu có một ảnh chụp nhanh dữ liệu, tôi sẽ chỉ cung cấp một lệnh gọi API cung cấp tất cả dữ liệu trong một yêu cầu mà không cần phân trang. Nhắc bạn, bạn sẽ cần một cái gì đó sẽ phát trực tiếp đầu ra mà không tải tạm thời vào bộ nhớ nếu bạn có một bộ dữ liệu lớn.

Đối với trường hợp của tôi, tôi hoàn toàn chỉ định một số lệnh gọi API để cho phép nhận toàn bộ thông tin (chủ yếu là dữ liệu bảng tham chiếu). Bạn cũng có thể bảo mật các API này để nó không gây hại cho hệ thống của bạn.


8

Tùy chọn A: Phân trang khóa bằng dấu thời gian

Để tránh những hạn chế của phân trang bù mà bạn đã đề cập, bạn có thể sử dụng phân trang dựa trên keyset. Thông thường, các thực thể có dấu thời gian cho biết thời gian tạo hoặc sửa đổi của chúng. Dấu thời gian này có thể được sử dụng để phân trang: Chỉ cần vượt qua dấu thời gian của phần tử cuối cùng làm tham số truy vấn cho yêu cầu tiếp theo. Đến lượt mình, máy chủ sử dụng dấu thời gian làm tiêu chí lọc (ví dụ WHERE modificationDate >= receivedTimestampParameter)

{
    "elements": [
        {"data": "data", "modificationDate": 1512757070}
        {"data": "data", "modificationDate": 1512757071}
        {"data": "data", "modificationDate": 1512757072}
    ],
    "pagination": {
        "lastModificationDate": 1512757072,
        "nextPage": "https://domain.de/api/elements?modifiedSince=1512757072"
    }
}

Bằng cách này, bạn sẽ không bỏ lỡ bất kỳ yếu tố nào. Cách tiếp cận này phải đủ tốt cho nhiều trường hợp sử dụng. Tuy nhiên, hãy ghi nhớ những điều sau:

  • Bạn có thể chạy vào các vòng lặp vô tận khi tất cả các yếu tố của một trang có cùng dấu thời gian.
  • Bạn có thể phân phối nhiều phần tử nhiều lần cho máy khách khi các phần tử có cùng dấu thời gian trùng nhau hai trang.

Bạn có thể làm giảm những hạn chế đó bằng cách tăng kích thước trang và sử dụng dấu thời gian với độ chính xác đến mili giây.

Tùy chọn B: Phân trang khóa mở rộng với mã thông báo tiếp tục

Để xử lý các nhược điểm đã đề cập của phân trang bàn phím thông thường, bạn có thể thêm phần bù vào dấu thời gian và sử dụng cái gọi là "Mã thông báo tiếp tục" hoặc "Con trỏ". Phần bù là vị trí của phần tử so với phần tử đầu tiên có cùng dấu thời gian. Thông thường, mã thông báo có định dạng như Timestamp_Offset. Nó được chuyển đến máy khách trong phản hồi và có thể được gửi lại cho máy chủ để lấy trang tiếp theo.

{
    "elements": [
        {"data": "data", "modificationDate": 1512757070}
        {"data": "data", "modificationDate": 1512757072}
        {"data": "data", "modificationDate": 1512757072}
    ],
    "pagination": {
        "continuationToken": "1512757072_2",
        "nextPage": "https://domain.de/api/elements?continuationToken=1512757072_2"
    }
}

Mã thông báo "1512757072_2" trỏ đến phần tử cuối cùng của trang và nói "khách hàng đã có phần tử thứ hai với dấu thời gian 1512757072". Bằng cách này, máy chủ biết nơi để tiếp tục.

Xin lưu ý rằng bạn phải xử lý các trường hợp các yếu tố đã thay đổi giữa hai yêu cầu. Điều này thường được thực hiện bằng cách thêm một tổng kiểm tra vào mã thông báo. Tổng kiểm tra này được tính trên ID của tất cả các yếu tố có dấu thời gian này. Vì vậy, chúng tôi kết thúc với một định dạng mã thông báo như thế này:Timestamp_Offset_Checksum .

Để biết thêm thông tin về phương pháp này, hãy xem bài đăng trên blog "Phân trang API Web với các thẻ tiếp tục ". Một nhược điểm của phương pháp này là việc thực hiện khó khăn vì có nhiều trường hợp góc phải được tính đến. Đó là lý do tại sao các thư viện như mã thông báo tiếp tục có thể tiện dụng (nếu bạn đang sử dụng ngôn ngữ Java / JVM). Tuyên bố miễn trừ trách nhiệm: Tôi là tác giả của bài đăng và là đồng tác giả của thư viện.


4

Tôi nghĩ hiện tại api của bạn thực sự đáp ứng theo cách nó nên. 100 bản ghi đầu tiên trên trang theo thứ tự tổng thể của các đối tượng bạn đang duy trì. Giải thích của bạn cho biết rằng bạn đang sử dụng một số loại id thứ tự để xác định thứ tự các đối tượng của bạn để phân trang.

Bây giờ, trong trường hợp bạn muốn trang 2 phải luôn bắt đầu từ 101 và kết thúc ở 200, thì bạn phải đặt số lượng mục trên trang dưới dạng biến, vì chúng có thể bị xóa.

Bạn nên làm một cái gì đó giống như mã giả dưới đây:

page_max = 100
def get_page_results(page_no) :

    start = (page_no - 1) * page_max + 1
    end = page_no * page_max

    return fetch_results_by_id_between(start, end)

1
Tôi đồng ý. thay vì truy vấn theo số hồ sơ (không đáng tin cậy), bạn nên truy vấn bằng ID. Thay đổi truy vấn của bạn (x, m) thành "trả về m bản ghi SORTED theo ID, với ID> x", sau đó bạn có thể chỉ cần đặt x thành id tối đa từ kết quả truy vấn trước đó.
John Henckel

Đúng, hoặc sắp xếp trên id hoặc nếu bạn có một số lĩnh vực kinh doanh cụ thể để sắp xếp như
Creation_date,

4

Chỉ cần thêm vào câu trả lời này của Kamilk: https://www.stackoverflow.com/a/13905589

Phụ thuộc rất nhiều vào cách dữ liệu lớn bạn đang làm việc. Các tập dữ liệu nhỏ hoạt động hiệu quả trên phân trang bù nhưng các tập dữ liệu thời gian thực lớn yêu cầu phân trang con trỏ.

Tìm thấy một bài viết tuyệt vời về cách Slack phát triển sự phân trang của api khi các bộ dữ liệu tăng lên giải thích các mặt tích cực và tiêu cực ở mọi giai đoạn: https://slack.engineering/evolve-api-pagination-at-slack-1c1f644f8e12


3

Tôi đã suy nghĩ rất lâu về vấn đề này và cuối cùng kết thúc với giải pháp tôi sẽ mô tả dưới đây. Đó là một bước tiến khá lớn về sự phức tạp nhưng nếu bạn thực hiện bước này, bạn sẽ kết thúc với những gì bạn thực sự theo đuổi, đó là kết quả xác định cho các yêu cầu trong tương lai.

Ví dụ của bạn về một mục bị xóa chỉ là phần nổi của tảng băng chìm. Điều gì xảy ra nếu bạn đang lọc color=bluenhưng ai đó thay đổi màu của mục giữa các yêu cầu? Tìm nạp tất cả các mục một cách đáng tin cậy là không thể ... trừ khi ... chúng tôi thực hiện lịch sử sửa đổi .

Tôi đã thực hiện nó và nó thực sự ít khó khăn hơn tôi mong đợi. Đây là những gì tôi đã làm:

  • Tôi đã tạo một bảng duy nhất changelogsvới cột ID tăng tự động
  • Thực thể của tôi có một idtrường, nhưng đây không phải là khóa chính
  • Các thực thể có một changeIdtrường vừa là khóa chính cũng như khóa ngoại cho các thay đổi.
  • Bất cứ khi nào người dùng tạo, cập nhật hoặc xóa một bản ghi, hệ thống sẽ chèn một bản ghi mới vào changelogs, lấy id và gán nó cho một phiên bản mới của thực thể, sau đó nó sẽ chèn vào DB
  • Các truy vấn của tôi chọn thay đổi tối đa (được nhóm theo id) và tự tham gia để có được các phiên bản mới nhất của tất cả các bản ghi.
  • Bộ lọc được áp dụng cho các hồ sơ gần đây nhất
  • Trường trạng thái theo dõi xem một mục có bị xóa không
  • Thay đổi tối đa được trả về cho máy khách và được thêm làm tham số truy vấn trong các yêu cầu tiếp theo
  • Bởi vì chỉ những thay đổi mới được tạo ra, mỗi một thay đổi changeId hiện một ảnh chụp nhanh duy nhất của dữ liệu cơ bản tại thời điểm thay đổi được tạo.
  • Điều này có nghĩa là bạn có thể lưu trữ kết quả của các yêu cầu có tham số changeIdtrong đó mãi mãi. Kết quả sẽ không bao giờ hết hạn vì chúng sẽ không bao giờ thay đổi.
  • Điều này cũng mở ra tính năng thú vị như rollback / Revert, đồng bộ bộ đệm của máy khách, v.v ... Bất kỳ tính năng nào được hưởng lợi từ lịch sử thay đổi.

tôi bối rối. Làm thế nào điều này giải quyết trường hợp sử dụng bạn đề cập? (Một trường ngẫu nhiên thay đổi trong bộ đệm và bạn muốn làm mất hiệu lực bộ đệm)
U Avalos

Đối với bất kỳ thay đổi bạn tự thực hiện, bạn chỉ cần nhìn vào phản ứng. Máy chủ sẽ cung cấp một thay đổi mới và bạn sử dụng nó trong yêu cầu tiếp theo của bạn. Đối với những thay đổi khác (do người khác thực hiện), bạn sẽ thăm dò sự thay đổi mới nhất mỗi lần một lần và nếu nó cao hơn thay đổi của bạn, bạn biết có những thay đổi nổi bật. Hoặc bạn thiết lập một số hệ thống thông báo (bỏ phiếu dài. Đẩy máy chủ, websockets) để thông báo cho khách hàng khi có những thay đổi nổi bật.
Stijn de Witt

0

Một tùy chọn khác cho Phân trang trong API RESTFul, là sử dụng tiêu đề Liên kết được giới thiệu ở đây . Ví dụ: Github sử dụng nó như sau:

Link: <https://api.github.com/user/repos?page=3&per_page=100>; rel="next",
  <https://api.github.com/user/repos?page=50&per_page=100>; rel="last"

Các giá trị có thể rellà: đầu tiên, cuối cùng, tiếp theo, trước đó . Nhưng bằng cách sử dụng Linktiêu đề, có thể không thể chỉ định Total_count (tổng số phần tử).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.