背景
JSONとしてデータオブジェクトを返すRestful APIを構築しています。ほとんどの場合、データオブジェクトを返すだけで問題ありませんが、場合によってはf.ex.ページネーションまたは検証では、応答にメタデータを追加する必要があります。
これまでのところ
次の例のように、すべてのjson応答をラップしました。
{
"metadata" :{
"status": 200|500,
"msg": "Some message here",
"next": "http://api.domain.com/users/10/20"
...
},
"data" :{
"id": 1001,
"name": "Bob"
}
}
長所
短所
質問
Jsonレスポンスにメタデータを追加するためのベストプラクティスは何ですか?
[〜#〜]更新[〜#〜]
以下の答えから私がこれまで得たもの:
metadata.status
を削除し、代わりにhttpプロトコルでhttp応答コードを返します(200、500 ...)RESTful APIでメタデータを渡す方法はいくつかあります。
Metadata.statusには、HTTPステータスコードを使用してください。メタデータが応答全体を参照している場合は、ヘッダーフィールドとして追加できます。メタデータが応答の一部のみを参照する場合は、オブジェクトの一部としてメタデータを埋め込む必要があります。DO N'T応答全体を人工的なエンベロープでラップし、ラッパーをデータとメタデータに分割します。
そして最後にAPI全体で一貫性がある選択した内容を使用します。
良い例は、ページネーション付きのコレクション全体に対するGETです。 GET/itemsカスタムヘッダーでコレクションのサイズと現在のページを返すことができます。標準のリンクヘッダーのページネーションリンク:
Link: <https://api.mydomain.com/v1/items?limit=25&offset=25>; rel=next
このアプローチの問題は、応答の特定の要素を参照するメタデータを追加する必要がある場合です。その場合は、オブジェクト自体に埋め込むだけです。また、一貫したアプローチをとるために、すべてのメタデータを常に応答に追加します。 GET/itemsに戻って、各アイテムがメタデータを作成および更新したと想像してください。
{
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"
}
]
}
コレクションレスポンスは特殊なケースであることに注意してください。コレクションにメタデータを追加すると、コレクションは配列として返されなくなり、配列を含むオブジェクトである必要があります。なぜオブジェクトなのか?メタデータ属性を追加したいからです。
個々のアイテムのメタデータと比較します。エンティティのラッピングに近いものはありません。リソースにいくつかの属性を追加するだけです。
1つの規則は、コントロールまたはメタデータフィールドを区別することです。これらのフィールドの先頭にアンダースコアを付けることができます。
@Charlieのコメントの行に沿って:質問のページ分割の部分では、メタデータを応答somhowにベイクする必要がありますが、ここでのstatus
およびmessage
属性は多少冗長です。 HTTP
プロトコル自体(ステータス200
-モデルが見つかりました、404
-モデルが見つかりません、403
-不十分なプライバシー、アイデアがわかります)( spec を参照)。サーバーがエラー状態を返したとしても、message
部分を応答本文として送信できます。これら2つのフィールドは、メタデータのニーズのかなりの部分をカバーします。
個人的に、私は(ab)のメタデータの小さな部分にカスタムHTTPヘッダーを使用する傾向があります(X-
接頭辞)、しかし、それが実用的でなくなる制限はかなり低いと思います。
私は expanded スコープが小さい質問でこれについて少し説明しましたが、この質問ではポイントはまだ有効だと思います。
このページを読むことをお勧めします https://www.odata.org/ ODataを使用する必要はありませんが、ODataが動作する方法は、RESTの優れたプラクティスの良い例です。
同じ使用例があり、JSON応答にページ分割メタデータを追加する必要がありました。このデータを処理できるコレクションタイプと、Rails側の軽量ラッパーを作成しました。この例では、ビューで参照できるようにコレクションデータにメタデータを追加しています。
そこで、次のようなバックボーンコレクションクラスを作成しました
// 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;
}
});
次に、この単純なクラスをRails側に作成し、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
このようなコントローラーで使用します
class ThingsController < ApplicationController
def index
@things = Thing.all.page params[:page]
render :json => PageableCollection.new(@things)
end
end
楽しい。お役に立てば幸いです。