2011-01-10 2 views
4

TL; DR:APIを作成しています。異なるバージョンのフィールドが必要です。賢明な人を教えてください。APIが分離していることを保証する

私は現在、バージョン管理されたAPIを作成する最良の方法を見つけようとしています。つまり、一連のフィールドを持つプロジェクトのリストを表示する/api/v1/projects.jsonというURLと、別々のフィールドを持つプロジェクトのリストを表示するapi/v2/projects.jsonというURLを持っています。

私はこの問題を約15分間考えていましたが、これはおそらくすべてが間違っていることを意味しています。

def self.api_fields 
    { 
    :v1 => ["name"], 
    :v2 => ["name", "tickets_count"] 
    } 
end 

その後、私はこのように私のAPIコントローラ(api/v1/projects_controller.rb)でこれを使用することができます:

def index 
    respond_with(Project.all(:select => Project.api_fields[:v1])) 
end 

これは素晴らしいですし、私は「として働く現時点では私は私のapp/models/project.rbファイルでこれを持っていますそれは好きですが、おそらくもっと良い方法があります。それはあなたの仕事です!あなたの山々のAPI作成の知恵を共有してください。

Projectメソッドのtickets_countメソッドのように、モデルのオブジェクトのインスタンスのメソッドを使用できるようになるソリューションを考案した場合のボーナスポイントです。

答えて

1

polarblauには、異なるバージョンのAPI用に複数のコントローラが必要です。だから、私はこの質問のボーナスポイントを目指します。

#tickets_countを呼び出す機能をアーカイブすると、モデルの#as_json#to_xmlのメソッドをオーバーライドする必要があります。

API/V1/projects_controller.rb

def index 
    respond_with Project.all, :api_version => :v1 
end 

project.rb

class Project < ActiveRecord::Base 
    API_FIELDS = { 
    :v1 => { :only => [:name] }, 
    :v2 => { :only => [:name], :methods => [:tickets_count] } 
    } 

    def as_json(options = {}) 
    options.merge! API_FIELDS[options[:api_version]] 
    super 
    end 

    def to_xml(options = {}, &block) 
    options.merge! API_FIELDS[options[:api_version]] 
    super 
    end 
end 

しかし、あなたはドン場合」:私はあなたがこのようにそれをしなければならないと思いますコントローラーの混乱を心配して、私は:only:methodsrespond_withで呼んでいると思います。 e #as_jsonおよび#to_xmlメソッド。

1

ちょうどコメントとして:

これらはまだ見たことがありますか?

http://devoh.com/posts/2010/04/simple-api-versioning-in-rails

Best practices for API versioning?

devoh.com良いアイデアのように思われる、ルーティングレベルですでにバージョンを分割することをお勧め:

map.namespace(:v1) do |v1| 
    v1.resources :categories 
    v1.resources :products 
end 

map.namespace(:v2) do |v2| 
    v2.resources :categories, :has_many => :products 
end 

次にあなたが返すように異なるコントローラを使用することができます異なるフィールド。

+0

これは私がすでにやっていることです。さまざまなフィールドを返すために異なるコントローラを使用しています。その部分は私が間違いなく釘付けにしてしまった。質問は、 "これは正しい方法ですか?" –

+0

私には良い気分だと感じていますが、それが私が "ただのコメント"で答えを出した理由です - 私の知恵では十分自信がありません。 – polarblau

+0

APIコントローラのディレクトリ構造も 'app/controllers/api/v2/categories_controller.rb'のようにする必要があります。 – yfeldblum

0

あなたが知っているように、あなたが公開しているものは、エンドクライアントが直接の依存関係を作成できるということです。あなたのモデルを世界に直接公開するとしたら、たとえば、

  1. エンドクライアントがそれと一緒に暮らすとずっと「スキーマレスデータベース」のように振る舞う必要があります:あなたはあなたの製品モデルを変更するたびhttp://domain.com/products.jsonは、オプションの数が限られています。あなたはそれが変わるつもりだと言いますが、それは完了です(クライアントはそれに対処しなければなりません)!
  2. APIにエンタープライズのようなバージョン管理を追加しました。これは、より高度なレベルでは、エンドクライアントに公開するものはあなたのモデルではないということです。代わりにパブリックオブジェクトを公開し、パブリックオブジェクトをバージョン管理することができます。私たちは次のことを行うことができます第二のアプローチを追求することを望んだ場合これはデータ転送オブジェクト(http://en.wikipedia.org/wiki/Data_transfer_object)

と呼ばれている:

class Project < ActiveRecord::Base 
end 

class PublicProject 
    def to_json(version = API_VERSION) 
    self.send("load_#{version}_project").to_json 
    end 

    private 
    def load_v1_project 
     project = load_v2_project 
     # logic that transforms a current project in a project that v1 users can understand 
    end 

    def load_v2_project 
     Project.find... 
    end 
end 

・ホープ助けになる。

0

/api/v1のルートにSinatraアプリをマウントして、API呼び出しを処理します。新しいAPIを追加するのが簡単になり、非推奨にするまで下位互換性が維持されます。

+0

それはRails 3 in Actionのためです。私はこの理由のためにSinatraを使用したくありません。私はRailsもこれをうまくやることができるはずだと思う。 –

関連する問題