19

これは、「どうやってこれを機能させるか」ではなく、「なぜこのように機能するのか」という問題です。

私のアプリは、JSON を返すサード パーティの REST API を呼び出しており、独自のJSON API の一部として結果を返しています。

私は Rails 3respond_torespond_withメソッドを使用していました。リクエストの場合GET、これは期待どおりに機能し、JSON を通過するだけです。

の場合はPOST、返されたオブジェクトから URL を作成して:locationオプションに渡すなど、さらに多くのことを行います。しかし、私のオブジェクトは単なる JSON (ActiveRecord ではない) であるため、エラーが発生します。

例えば...

# POST /api/products.json with params id=:id
def create
  query_string = "#{user_id}&id=#{params[:id]}"
  @products = third_party_api_wrapper.products(query_string, 'POST')
  respond_with @products
end 

サードパーティ API のラッパーが POST リクエストを発行すると、正常に返されます。Rails は 500 エラーを返し、次のようにログに記録されます。

NoMethodError (undefined method `{"response":{"message":"product 4e1712d9ec0f257c510013f8 selected"}}_url' for #<MyController> 

Rails は、私の @products オブジェクトにロケーション URL の作成方法を認識させたいと考えています。

明確化:@productsサード パーティの API によって返されるオブジェクトは、純粋な JSON (上記のエラー ログ メッセージに埋め込まれている文字列) です。このエラーが発生するのは、Rails がオブジェクトをもっと何かにしたいように見えるためです。Rails の内部 API サポートでは、それは ActiveRecord オブジェクトです。

新しいrespond_with構文を古いスタイルに置き換えると

respond_to do |format|
  format.json { render :json => @products }  # note, no :location or :status options
end

その後、すべてが機能します。そして、これは私がやったことなので、「どのように」の問題ではなく、「なぜ」という質問があります。

イントロダクションに関するRyan Daigle の投稿は、何が起こっているかを説明しています。

私の質問は:なぜrespond_withデータ (および HTTP ステータス) 以外のものを期待しているのですかPOST?

それが間違っていると言っているのではなく、Rails 実装の理論的根拠を理解しようとしているだけです。

4

3 に答える 3

16

概要: Rails は HTTP と REST からその理論的根拠を得ています。

(更新された質問をありがとう。これで、あなたの中心的な質問を理解しました:「それが間違っていると言っているのではなく、Rails実装の理論的根拠を理解しようとしているだけです。」)

それでは説明です。Rails がどのように動作するかについての理論的根拠は、HTTP および REST 規則を受け入れることに根ざしています。

あなたが読んだことから私がこれから詳しく説明することへの橋渡しをするために、デフォルトの RESTful レンダリングに関する Ryan Daigle の記事から関連する部分に言及したいと思います。

:html 形式が要求された場合:

[一部テキストを削除]

  • [PUT または POST 後、検証エラーなし] リソースの場所 (つまり、user_url) にリダイレクトします。

([括弧内] のテキストは私が追加したものです。)

別の形式が要求された場合 (例: :xml または :json)

[一部テキストを削除]

  • POST リクエストの場合は、リソースで :to_format メソッドを呼び出し、:created ステータスと新しく作成されたリソースの :location を付けて送り返します。"

Railsが良い習慣だと信じていることについて、私の言葉でこれを言いましょう:

  • ヒューマン コンテンツ (HTML など) の場合、POST または PUT の後、サーバーはブラウザに303経由で新しく作成されたリソースにリダイレクトするように指示する必要があります。これは一般的な方法です。ユーザーは編集結果の更新を確認したいので、非常に便利です。

  • マシン コンテンツ (JSON、XML など) の場合、PUT の後、サーバーは201をレンダリングする必要があります。クライアント (この場合、API を使用するプログラム) は、そこで停止することを決定する場合があります。(結局、クライアントはリクエストを指定して 201 を取得したので、すべてがホンキー・ドリーです。) これが、303 (リダイレクト) ではなく 201 (成功) が使用される理由です。クライアントが新しく作成されたリソースを要求したい場合、Location ヘッダーを使用して検索できますが、リダイレクトを強制するべきではありません。

いずれの場合も、新しく作成されたリソースの場所が必要であることに注意してください。@productsこれが、上記の例でデータと場所の両方を含める必要がある理由です。

背景として、 201 Created の W3C ページから少し共有しました。

10.2.2 201 作成済み

要求が満たされ、新しいリソースが作成されました。新しく作成されたリソースは、応答のエンティティで返された URI によって参照できます。リソースの最も具体的な URI は Location ヘッダー フィールドによって指定されます。応答には、ユーザーまたはユーザー エージェントが最も適切なものを選択できる、リソースの特性と場所のリストを含むエンティティを含める必要があります。エンティティ形式は、Content-Type ヘッダー フィールドで指定されたメディア タイプによって指定されます。オリジン サーバーは、201 ステータス コードを返す前にリソースを作成する必要があります。アクションをすぐに実行できない場合、サーバーは代わりに 202 (Accepted) 応答で応答する必要があります。

これが理論的根拠を説明するのに役立つことを願っています。この理論的根拠が Web フレームワーク全体で広く受け入れられていることは、私の (素朴な?) 理解です。歴史的に見て、REST とリソース指向アーキテクチャーの多くの熱烈な支持者にとって、Rails は熱烈な実装の土台 (新語アラート!) だったのではないかと思います。

于 2012-06-21T04:46:23.893 に答える
2

「なぜ」は@david-jamesによって見事に答えられました。これは、次の方法で答える簡単な「方法」respond_withです。

class Api::V1::UsersController < ApplicationController

  respond_to :json

  def create
    @user = User.create(...)
    respond_with @user, location: url_for([:api, :v1, @user])
  end

end
于 2014-11-30T23:55:47.987 に答える
1

この質問に答えるには: 「API がデータ (および HTTP ステータス) 以外のものを返す必要があるのはなぜですか?。それが間違っていると言っているわけではなく、その根拠を理解しようとしているだけです。」

まともな根拠が思いつきません。さらに重要なことは、API がデータ構造以外のものを返す方法がまったく見当たらないことです! (この質問は私には意味がありません!)

定義により、API 呼び出しはデータ構造を返す必要があります。(文字列のように単純な場合もあります。JSON の場合もあります。XML の場合もあります。) コンテンツ ネゴシエーションを使用して形式を決定できます。厳密なスキーマである場合とそうでない場合がありますが、少なくともクライアント ライブラリはそれを解析できる必要があります。いずれにせよ、API ドキュメントはこれを十分に明確にし、それに固執する必要があります。クライアント ライブラリは他にどのような相互運用を期待できますか?

ここで要点を見逃していると思います。これはあまりにも明白なようです。(上記のコードに別の問題があると思われます。)

于 2012-06-19T20:39:44.780 に答える