2011-11-28 27 views
32

Bối cảnhCác phương pháp hay nhất để thêm siêu dữ liệu vào phản hồi JSON RESTful là gì?

Chúng tôi đang tạo một API khôi phục sẽ trả về các đối tượng dữ liệu dưới dạng JSON. Trong hầu hết các trường hợp, chỉ cần trả lại đối tượng dữ liệu, nhưng trong một số trường hợp, f.ex. phân trang hoặc xác thực, chúng tôi cần thêm một số siêu dữ liệu vào phản hồi.

gì chúng tôi có cho đến nay

Chúng tôi đã được bao bọc tất cả các phản ứng json như ví dụ sau:

{ 
    "metadata" :{ 
     "status": 200|500, 
     "msg": "Some message here", 
     "next": "http://api.domain.com/users/10/20" 
     ... 
    }, 
    "data" :{ 
     "id": 1001, 
     "name": "Bob" 
    } 
} 

Ưu

  • Chúng ta có thể thêm siêu dữ liệu hữu ích để đáp ứng

Nhược điểm

  • Trong hầu hết các trường hợp chúng ta không cần lĩnh vực siêu dữ liệu, và nó cho biết thêm phức tạp sang định dạng json
  • Vì nó không phải là một đối tượng dữ liệu nữa, nhưng giống như một phản ứng bao bọc , chúng tôi không thể sử dụng phản hồi ngay trong f.ex backbone.js mà không cần giải nén đối tượng dữ liệu.

Câu hỏi

thực hiện những điều tốt nhất để thêm siêu dữ liệu để đáp ứng json là gì?

CẬP NHẬT

Những gì tôi đã có cho đến nay từ câu trả lời dưới đây:

  • Tháo metadata.status một sự trở lại các mã phản hồi http trong giao thức http thay (200, 500 ...)
  • Thêm thông báo lỗi vào nội dung của một đại diện http 500
  • Để phân trang tôi tự nhiên có một số siêu dữ liệu nói về cấu trúc phân trang và dữ liệu lồng trong cấu trúc đó
  • lượng nhỏ dữ liệu meta có thể được thêm vào tiêu đề http (X-một cái gì đó)
+0

Bạn có biết rằng ví dụ của mình không phải là JSON không? – JeremyP

+0

cảm ơn, cập nhật –

+1

Bạn có thể đi vào chi tiết hơn về các trường hợp sử dụng tiềm năng của bạn và tại sao mã trạng thái HTTP và đặt tiêu đề phản hồi thích hợp sẽ không phù hợp? – Charlie

Trả lời

0

Chúng tôi đã có trường hợp sử dụng cùng, trong đó chúng tôi cần phải thêm siêu dữ liệu pagination để một phản ứng JSON. Chúng tôi đã kết thúc việc tạo ra một loại bộ sưu tập trong Backbone có thể xử lý dữ liệu này, và một wrapper nhẹ ở phía Rails. Ví dụ này chỉ thêm siêu dữ liệu vào đối tượng thu thập để tham chiếu theo dạng xem.

Vì vậy, chúng tôi tạo ra một cái gì đó Backbone Collection lớp như thế này

// Example response: 
// { num_pages: 4, limit_value: 25, current_page: 1, total_count: 97 
// records: [{...}, {...}] } 

PageableCollection = Backbone.Collection.extend({ 
    parse: function(resp, xhr) { 
    this.numPages = resp.num_pages; 
    this.limitValue = resp.limit_value; 
    this.currentPage = resp.current_page; 
    this.totalCount = resp.total_count; 
    return resp.records; 
    } 
}); 

Và sau đó chúng tôi tạo ra lớp đơn giản này ở phía bên Rails, để phát ra các dữ liệu meta khi paginated với Kaminari

class PageableCollection 
    def initialize (collection) 
    @collection = collection 
    end 
    def as_json(opts = {}) 
    { 
     :num_pages => @collection.num_pages 
     :limit_value => @collection.limit_value 
     :current_page => @collection.current_page, 
     :total_count => @collection.total_count 
     :records => @collection.to_a.as_json(opts) 
    } 
    end 
end 

Bạn sử dụng nó trong một bộ điều khiển như thế này

class ThingsController < ApplicationController 
    def index 
    @things = Thing.all.page params[:page] 
    render :json => PageableCollection.new(@things) 
    end 
end 

Thưởng thức. Hi vọng bạn tìm được thứ hữu dụng.

+0

Sẽ không tốt hơn nếu thêm các liên kết phân trang trong phản hồi thay vì nhúng logic yêu cầu phân trang trong ứng dụng khách? –

4

Dọc theo dòng nhận xét của Charlie: cho phần phân trang câu hỏi của bạn, bạn vẫn cần phải siêu dữ liệu vào phản hồi, nhưng thuộc tính statusmessage ở đây hơi dư thừa, vì chúng đã được bao phủ bởi HTTP bản thân giao thức (trạng thái 200 - mô hình được tìm thấy, 404 - không tìm thấy mô hình, 403 - không đủ tư cách, bạn có ý tưởng) (xem spec). Ngay cả khi máy chủ của bạn trả về một điều kiện lỗi, bạn vẫn có thể gửi phần message làm nội dung phản hồi. Hai trường này sẽ bao gồm khá nhiều nhu cầu siêu dữ liệu của bạn.

Cá nhân, tôi có xu hướng hướng tới (ab) sử dụng tiêu đề HTTP tùy chỉnh cho các phần siêu dữ liệu nhỏ hơn (với tiền tố X-), nhưng tôi đoán giới hạn ở đó không thực tế là khá thấp.

Tôi đã expanded một chút về vấn đề này trong một câu hỏi với phạm vi nhỏ hơn, nhưng tôi nghĩ rằng các điểm vẫn hợp lệ cho câu hỏi này.

+0

Rõ ràng tiền tố với 'X-' là [không còn được khuyến nghị] (http://stackoverflow.com/a/3561399/320036). – z0r

+1

@ z0r Tuyên bố là gây tranh cãi, theo các câu trả lời từ liên kết. –

8

Bạn có một vài phương tiện để vượt qua siêu dữ liệu trong một API RESTful:

  1. Http Status Mã
  2. Headers
  3. đáp ứng Body

Đối với metadata.status, sử dụng tình trạng Http Mã, đó là những gì cho! Nếu siêu dữ liệu đề cập đến toàn bộ phản hồi, bạn có thể thêm siêu dữ liệu đó làm trường tiêu đề. Nếu siêu dữ liệu chỉ đề cập đến một phần của phản hồi, bạn sẽ phải nhúng siêu dữ liệu như một phần của đối tượng. KHÔNG bọc toàn bộ phản hồi trong một phong bì nhân tạo và tách trình bao bọc trong dữ liệu và siêu dữ liệu.

Và cuối cùng, nhất quán trên API của bạn với các lựa chọn bạn thực hiện.

Ví dụ tốt là GET trên toàn bộ bộ sưu tập có phân trang. GET/items Bạn có thể trả về kích thước bộ sưu tập và trang hiện tại trong tiêu đề tùy chỉnh. Và liên kết pagination trong tiêu đề Link Header:

Link: <https://api.mydomain.com/v1/items?limit=25&offset=25>; rel=next 

Vấn đề với cách tiếp cận này là khi bạn cần thêm siêu dữ liệu tham chiếu các yếu tố cụ thể trong phản hồi. Trong trường hợp đó, chỉ cần nhúng nó vào chính đối tượng đó. Và để có cách tiếp cận nhất quán ... hãy thêm luôn tất cả siêu dữ liệu để phản hồi.Vì vậy, quay lại mục GET/items, hãy tưởng tượng rằng mỗi mục đã tạo và cập nhật siêu dữ liệu:

{ 
    items:[ 
    { 
     "id":"w67e87898dnkwu4752igd", 
     "message" : "some content", 
     "_created": "2014-02-14T10:07:39.574Z", 
     "_updated": "2014-02-14T10:07:39.574Z" 
    }, 
    ...... 
    { 
     "id":"asjdfiu3748hiuqdh", 
     "message" : "some other content", 
     "_created": "2014-02-14T10:07:39.574Z", 
     "_updated": "2014-02-14T10:07:39.574Z" 
    } 
    ], 
    "_total" :133, 
    "_links" :[ 
    { 
     "next" :{ 
      href : "https://api.mydomain.com/v1/items?limit=25&offset=25" 
     } 
    ] 
} 

Lưu ý rằng phản hồi bộ sưu tập là trường hợp đặc biệt. Nếu bạn thêm siêu dữ liệu vào bộ sưu tập, bộ sưu tập không còn có thể được trả về dưới dạng mảng nữa, nó phải là đối tượng có mảng trong đó. Tại sao một đối tượng? vì bạn muốn thêm một số thuộc tính siêu dữ liệu.

So sánh với siêu dữ liệu trong các mục riêng lẻ. Không có gì gần gói thực thể. Bạn chỉ cần thêm một số thuộc tính vào tài nguyên.

Một quy ước là phân biệt các trường điều khiển hoặc siêu dữ liệu. Bạn có thể thêm tiền tố cho các trường đó bằng dấu gạch dưới.

Các vấn đề liên quan