web-dev-qa-db-ja.com

RESTful JSONコレクションにHATEOASスタイルのリンクを実装するにはどうすればよいですか?

物事をシンプルに保ち、名前の衝突を避けるために、このようにレコードリソースにリンクをバンドルしています...

{
    id: 211,
    first_name: 'John',
    last_name: 'Lock',
    _links: [
        { rel: 'self', href: 'htttp://example.com/people/211' }
    ]
}

ただし、コレクションにリンクを実装する方法はわかりません。私は例のためにウェブを探し回るのに長い時間を費やしてきましたが、それほど無駄ではありません [〜#〜] hal [〜#〜] 私は問題を解決できません。

[
    {id:1,first_name:.....},
    {id:2,first_name:.....},
    {id:3,first_name:.....}, 
    "_links": "Cant put a key value pair here because its an-array" 
]

つまり、配列をコンテナオブジェクトにラップする必要があります。

[
    people: [ {id:1,first_name:.....} ],
    links: [ { rel:parent, href:.... ]
]

しかし、これは単一のリソースとは異なるため、レコードをコレクションのように動作させ、コンテナーにラップします。

{
    person: {
        id: 211,
        first_name: 'John',
        last_name: 'Lock',
        _links: 
    },
    links:[
        { rel: 'self', href: 'htttp://example.com/people/211' }
    ] 
}

表面的には、これは非常にきちんとした解決策のように思えます。結果のJSONは1レベル深くなりますが、HATEOASが実装されているので、それでいいのですか?どういたしまして。私がコレクションに戻ったときに本当の刺し傷が来る。これで、コレクションとの一貫性を保つために単一のリソースがコンテナにラップされたので、変更を反映するためにコレクションを変更する必要があります。そして、ここがitいところです。とてもい。これで、コレクションは次のようになります...

{
    "people": [
        {
            "person": {
                ....
            },
            "links" : [
                {
                    "rel": "self",
                    "href": "http://example.com/people/1"
                }
            ]
        },
        {
            "person": {
                ....
            },
            "links" : [
                {
                    "rel": "self",
                    "href": "http://example.com/people/2"
                }
            ]
        }
    ],
    "links" : [
        {
            "rel": "self",
            "href": "http://example.com/people"
        }
    ]
}

コレクションにHATEOASを実装するより簡単なソリューションはありますか?または、データ構造を過度に複雑にすることを余儀なくされたHATEOASに別れを告げるべきでしょうか?

35
thomas-peter

HALが少し肥大化したように見える(JSON形式では非常に最小限である)からといって、HALをすぐに閉じないでください。

HALはJSONに対するもので、HTMLはプレーンテキストに対するものです

ハイパーリンクを追加します。 RESTには、ハイパーリンクと一般的に理解されている表現形式(HALやCollection + JSONなど)が必要です。 RESTにはHATEOASも必要ですが、HATEOASがなければRESTではありません! HATEOASはもちろんハイパーリンクを必要とします。

あなたの場合、あなたはコレクションリソースを構築しようとしています。 IANA登録済みの関係 は、「アイテム」です(逆の関係「コレクション」)。 PeopleコレクションのHALでの表現は次のとおりです。

{
    "_links": {
        "self": { "href": "http://example.com/people" },
        "item": [
            { "href": "http://example.com/people/1", "title": "John Smith" },
            { "href": "http://example.com/people/2", "title": "Jane Smith" }
        ]
    },
    "_embedded": {
        "http://example.com/rels#person": [
            {
                "first_name": "John",
                "last_name": "Smith",
                "_links": {
                    "self": { "href": "http://example.com/people/1" },
                    "http://example.com/rels#spouse": { "href": "http://example.com/people/2" }
                }
            },
            {
                "first_name": "Jane",
                "last_name": "Smith",
                "_links": {
                    "self": { "href": "http://example.com/people/2" },
                    "http://example.com/rels#spouse": { "href": "http://example.com/people/1" }
                }
            }
        ]
    }
}

注意:

  • このコレクションの主なデータは、_links.item[]。これらはコレクション内のアイテムです。各アイテムの完全な(または少なくとも追加の)データは、_embedded配列。クライアントがこれらの追加データを必要とする場合、_embedded[n]._links.self.hrefnに対して。これは、HALの設計上の制約です。他のハイパーメディア表現形式にも同様の制約があります(ただし、おそらく他の方向に向かっています)。

  • title配列の各メンバーにitem値を追加しました。これは、HTMLにレンダリングする場合は開始アンカータグと終了アンカータグの間に表示するか、クライアントでメニュー項目のテキストとして表示できます。クライアントによる表現のさらなる処理は必要ありません。

  • IDパラメーターはありません。他のリソースへのすべての参照は、ハイパーリンクとして公開されます。クライアントは、事前に定義された場所でIDをURLに接着してURLを「構築」する必要はありません。これは、クライアントとサーバーへの独立した変更を禁止する帯域外情報を構成します。

  • 相対URLは問題を引き起こす可能性があるため、ハイパーリンクはすべて絶対リンクにする必要があります。すべてのリレーションは、そのIANAページにリストされるか、URIを使用してそれらを定義する必要があります。理想的には、そのURIは、もう一方の端にある関係についてのドキュメントを備えた逆参照可能なHTTP URLである必要があります。

35
Nicholas Shanks

JSONリンクはまだ解決された問題ではないようです。いくつかの候補があります。

参照資料

15
Willie Wheeler

まず、コレクション(JSON配列)を返すエンドポイントを持つAPIが本当にRESTfulであるとは思いません。ただし、ほとんどの「REST」APIはここでルールを曲げます。

私は最近、REST NextBus XMLフィードrestbus のAPIを開発しました。私が使用した構造のサンプルです:

{
  // ... SF-Muni resource from restbus API ...

  _links: {
    self: {
      href: "http://localhost:3535/agencies/sf-muni",
      type: "application/json",
      rel: "self",
      rt: "agency",
      title: "Transit agency 'sf-muni'."
    },
    to: [
      {
        href: "http://localhost:3535/agencies/sf-muni/routes",
        type: "application/json",
        rel: "describedby",
        rt: "route",
        title: "A collection of routes for transit agency 'sf-muni'."
      },
      {
        href: "http://localhost:3535/agencies/sf-muni/vehicles",
        type: "application/json",
        rel: "describedby",
        rt: "vehicle",
        title: "A collection of vehicles for transit agency 'sf-muni'."
      }
    ],
    from: [
      {
        href: "http://localhost:3535/agencies",
        type: "application/json",
        rel: "bookmark",
        rt: "agency",
        title: "A collection of transit agencies. This is the API root!"
      }
    ]
  }

}

[〜#〜] hal [〜#〜]et のような一般的なJSONリンク戦略(または関連するメディアタイプ)には従おうとしません。 alIETF Standards Track (まだ)にないようです。代わりに、リンクオブジェクトのターゲット属性およびリンク関係値を満たす RFC 5988 Webリンク仕様 可能な限り。

restbus hypertext link structure の詳細を見ることができます。

3
Morgan

Restful object specification を試してみてください。その男たちは具体的なAPIを作成します。私は全体のアイデアが好きではないので、それらから取得できる多くの実用的な解決策があります。

1
swist