2012-08-28 9 views
54

Tôi muốn hỗ trợ phân trang trong API RESTful của tôi.Tải trọng phản hồi phân trang từ một API RESTful

Phương pháp API của tôi phải trả về danh sách sản phẩm JSON qua /products/index. Tuy nhiên, có khả năng hàng ngàn sản phẩm, và tôi muốn trang qua chúng, vì vậy yêu cầu của tôi nên tìm một cái gì đó như thế này:

/products/index?page_number=5&page_size=20 

Nhưng những gì phản ứng JSON tôi cần phải nhìn như thế nào? Người tiêu dùng API có thường mong đợi dữ liệu meta phân trang trong phản hồi không? Hoặc chỉ là một loạt các sản phẩm cần thiết? Tại sao?

Dường như API của Twitter bao gồm dữ liệu meta: https://dev.twitter.com/docs/api/1/get/lists/members (xem Yêu cầu mẫu).

Với dữ liệu meta:

{ 
    "page_number": 5, 
    "page_size": 20, 
    "total_record_count": 521, 
    "records": [ 
    { 
     "id": 1, 
     "name": "Widget #1" 
    }, 
    { 
     "id": 2, 
     "name": "Widget #2" 
    }, 
    { 
     "id": 3, 
     "name": "Widget #3" 
    } 
    ] 
} 

Chỉ cần một loạt các sản phẩm (không có dữ liệu meta):

[ 
    { 
    "id": 1, 
    "name": "Widget #1" 
    }, 
    { 
    "id": 2, 
    "name": "Widget #2" 
    }, 
    { 
    "id": 3, 
    "name": "Widget #3" 
    } 
] 

Trả lời

70

API ReSTful được tiêu thụ chủ yếu bởi các hệ thống khác, đó là lý do tại sao tôi đặt dữ liệu phân trang trong tiêu đề phản hồi. Tuy nhiên, một số người tiêu dùng API có thể không có quyền truy cập trực tiếp vào tiêu đề phản hồi hoặc có thể đang xây dựng UX trên API của bạn, do đó cung cấp cách truy xuất (theo yêu cầu) siêu dữ liệu trong phản hồi JSON là dấu cộng.

Tôi tin rằng việc triển khai của bạn nên bao gồm siêu dữ liệu có thể đọc được máy làm mặc định và siêu dữ liệu có thể đọc được khi được yêu cầu. Siêu dữ liệu có thể đọc được của con người có thể được trả về với mọi yêu cầu nếu bạn thích hoặc, tốt nhất là theo yêu cầu thông qua tham số truy vấn, chẳng hạn như include=metadata hoặc include_metadata=true.

Trong trường hợp cụ thể của bạn, tôi sẽ bao gồm URI cho từng sản phẩm có bản ghi. Điều này giúp người tiêu dùng API dễ dàng tạo liên kết đến từng sản phẩm. Tôi cũng sẽ đặt ra một số kỳ vọng hợp lý theo giới hạn của yêu cầu phân trang của tôi.Việc triển khai và ghi lại các cài đặt mặc định cho kích thước trang là một thực tế có thể chấp nhận được. Ví dụ: GitHub's API đặt kích thước trang mặc định thành 30 bản ghi với tối đa 100, cộng với đặt giới hạn tốc độ về số lần bạn có thể truy vấn API. Nếu API của bạn có kích thước trang mặc định thì chuỗi truy vấn có thể chỉ định chỉ mục trang.

Trong kịch bản của con người có thể đọc được, khi điều hướng đến /products?page=5&per_page=20&include=metadata, phản ứng có thể là:

{ 
    "_metadata": 
    { 
     "page": 5, 
     "per_page": 20, 
     "page_count": 20, 
     "total_count": 521, 
     "Links": [ 
     {"self": "/products?page=5&per_page=20"}, 
     {"first": "/products?page=0&per_page=20"}, 
     {"previous": "/products?page=4&per_page=20"}, 
     {"next": "/products?page=6&per_page=20"}, 
     {"last": "/products?page=26&per_page=20"}, 
     ] 
    }, 
    "records": [ 
    { 
     "id": 1, 
     "name": "Widget #1", 
     "uri": "/products/1" 
    }, 
    { 
     "id": 2, 
     "name": "Widget #2", 
     "uri": "/products/2" 
    }, 
    { 
     "id": 3, 
     "name": "Widget #3", 
     "uri": "/products/3" 
    } 
    ] 
} 

Đối với siêu dữ liệu máy có thể đọc, tôi sẽ thêm Link headers để phản ứng:

Link: </products?page=5&perPage=20>;rel=self,</products?page=0&perPage=20>;rel=first,</products?page=4&perPage=20>;rel=previous,</products?page=6&perPage=20>;rel=next,</products?page=26&perPage=20>;rel=last 

(giá trị tiêu đề Liên kết phải được mã hóa url)

... và có thể tùy chỉnh total-count phản ứng tiêu đề, nếu bạn lựa chọn:

total-count: 521 

Dữ liệu phân trang khác tiết lộ trong siêu dữ liệu con người làm trung tâm có thể là không cần thiết cho siêu dữ liệu máy trung tâm, như các tiêu đề liên kết cho tôi biết trang nào Tôi đang trên và số trên mỗi trang và tôi có thể nhanh chóng truy xuất số lượng bản ghi trong mảng. Do đó, tôi có lẽ sẽ chỉ tạo tiêu đề cho tổng số. Bạn luôn có thể đổi ý sau và thêm siêu dữ liệu.

Ngoài ra, bạn có thể nhận thấy tôi đã xóa /index khỏi URI của bạn. Một quy ước được chấp nhận chung là phải có bộ sưu tập điểm cuối ReST của bạn. Có /index ở cuối muddies tăng nhẹ.

Đây chỉ là một vài điều tôi muốn có khi tiêu thụ/tạo API. Hy vọng rằng sẽ giúp!

+0

per_page không tuân theo quy ước page_size –

+1

'" page_count ": 20' và' {"last": "/ products? Page = 26 & per_page = 20"} '? –

+0

điều gì sẽ xảy ra nếu số lượng sản phẩm đột nhiên tăng trong khi tìm nạp tất cả các bản ghi từ trang 1 đến trang x? – MeV

23

Là một người đã viết nhiều thư viện cho tiêu thụ các dịch vụ REST, hãy để tôi cung cấp cho bạn quan điểm của khách hàng về lý do tại sao tôi cho rằng kết quả trong siêu dữ liệu là cách để đi:

  • Không có tổng số , làm thế nào khách hàng có thể biết rằng nó vẫn chưa nhận được tất cả mọi thứ có và nên tiếp tục phân trang thông qua tập kết quả? Trong giao diện người dùng không thực hiện nhìn về phía trước trang tiếp theo, trong trường hợp xấu nhất, điều này có thể được biểu thị dưới dạng liên kết Tiếp theo/Thêm không thực sự tìm nạp thêm bất kỳ dữ liệu nào.
  • Bao gồm siêu dữ liệu trong phản hồi cho phép khách hàng theo dõi trạng thái ít hơn. Bây giờ tôi không phải khớp với yêu cầu REST của tôi với phản hồi, vì phản hồi chứa siêu dữ liệu cần thiết để xây dựng lại trạng thái yêu cầu (trong trường hợp này là con trỏ vào tập dữ liệu).
  • Nếu tiểu bang là một phần của phản hồi, tôi có thể thực hiện nhiều yêu cầu trong cùng một tập dữ liệu cùng một lúc và tôi có thể xử lý các yêu cầu theo bất kỳ thứ tự nào xảy ra mà không nhất thiết phải theo thứ tự tôi đã thực hiện yêu cầu.

Và đề xuất: Giống như Twitter API, bạn nên thay thế số trang bằng chỉ số/con trỏ thẳng. Lý do là, API cho phép khách hàng đặt kích thước trang theo yêu cầu. Là số trang trả về số trang mà khách hàng đã yêu cầu cho đến thời điểm này hay số trang được cho sử dụng lần cuối page_size (gần như chắc chắn là sau này, nhưng tại sao không tránh sự mơ hồ đó)?

+5

Để đạn đầu tiên của bạn, nó sẽ là một giải pháp thích hợp để bỏ qua một rel = tiếp theo nếu không có trang tiếp theo? Đối với dấu đầu dòng thứ hai của bạn, thông tin vẫn có sẵn trong phản hồi cho máy khách, nó không nằm trong phần trả lời mà thay vào đó là trong các tiêu đề. +1 trên đoạn cuối của bạn. –

5

Tôi khuyên bạn nên thêm tiêu đề cho cùng một. Việc di chuyển siêu dữ liệu đến tiêu đề giúp loại bỏ các phong bì như result, data hoặc records và nội dung phản hồi chỉ chứa dữ liệu chúng tôi cần. Bạn cũng có thể sử dụng tiêu đề Link nếu bạn cũng tạo liên kết pagination.

HTTP/1.1 200 
    X-Pagination-Count: 100 
    X-Pagination-Page: 5 
    X-Pagination-Limit: 20 
    Content-Type: application/json 

    [ 
     { 
     "id": 10, 
     "name": "shirt", 
     "color": "red", 
     "price": "$23" 
     }, 
     { 
     "id": 11, 
     "name": "shirt", 
     "color": "blue", 
     "price": "$25" 
     } 
    ] 

Để biết chi tiết tham khảo:

https://github.com/adnan-kamili/rest-api-response-format

Đối với hồ vênh vang:

https://github.com/adnan-kamili/swagger-response-template