रेल मार्गों के लिए एपीआई संस्करण


141

मैं स्ट्राइप है की तरह मेरे एपीआई संस्करण की कोशिश कर रहा हूँ। नीचे नवीनतम एपीआई संस्करण 2 दिया गया है।

/api/users एक 301 देता है /api/v2/users

/api/v1/users संस्करण 1 पर उपयोगकर्ताओं के 200 का सूचकांक देता है

/api/v3/users एक 301 देता है /api/v2/users

/api/asdf/users एक 301 देता है /api/v2/users

ताकि मूल रूप से ऐसा कुछ भी हो जो संस्करण लिंक को नवीनतम तक निर्दिष्ट नहीं करता है जब तक कि निर्दिष्ट संस्करण मौजूद नहीं है, तब तक इसे रीडायरेक्ट करें।

अभी तक मेरे पास इतना ही है:

scope 'api', :format => :json do
  scope 'v:api_version', :api_version => /[12]/ do
    resources :users
  end

  match '/*path', :to => redirect { |params| "/api/v2/#{params[:path]}" }
end

जवाबों:


280

इस उत्तर का मूल रूप बेतहाशा अलग है, और यहाँ पाया जा सकता है । बस सबूत है कि एक बिल्ली की त्वचा के लिए एक से अधिक तरीके हैं।

मैंने नामस्थान का उपयोग करने और 302 के डिफ़ॉल्ट के बजाय 301 रीडायरेक्ट का उपयोग करने के बाद से उत्तर अपडेट किया है। उन चीजों पर संकेत देने के लिए पिक्सेल्ट्रिक्स और बो जीन का धन्यवाद।


आप वास्तव में एक मजबूत हेलमेट पहनना चाहते हैं क्योंकि यह आपके दिमाग को उड़ाने वाला है

रेल 3 रूटिंग एपीआई सुपर दुष्ट है। ऊपर अपनी आवश्यकताओं के अनुसार, अपने एपीआई के लिए मार्गों को लिखने के लिए, आपको बस इसकी आवश्यकता है:

namespace :api do
  namespace :v1 do
    resources :users
  end

  namespace :v2 do
    resources :users
  end
  match 'v:api/*path', :to => redirect("/api/v2/%{path}")
  match '*path', :to => redirect("/api/v2/%{path}")
end

यदि इस बिंदु के बाद भी आपका दिमाग बरकरार है, तो मुझे समझाएं।

सबसे पहले, हम कहते namespaceहैं कि जब आप एक विशिष्ट पथ और मॉड्यूल के लिए स्कोप किए गए मार्गों का एक गुच्छा चाहते हैं जो समान रूप से नामित हैं , तो सुपर काम है। इस स्थिति में, हम चाहते हैं कि ब्लॉक के अंदर के सभी मार्गों namespaceको Apiमॉड्यूल के भीतर नियंत्रकों के लिए स्कूप किया जाए और इस मार्ग के अंदर आने वाले सभी मार्गों के साथ अनुरोध किया जाएगा api। अनुरोध जैसे कि /api/v2/users, फिर जानते हैं?

नामस्थान के अंदर, हम दो और नामस्थानों को परिभाषित करते हैं (woah!)। इस बार हम "वी 1" नाम स्थान तय कर रहे हैं, तो नियंत्रकों यहाँ सभी मार्गों के अंदर हो जाएगा V1अंदर मॉड्यूल Apiमॉड्यूल: Api::V1resources :usersइस मार्ग के अंदर परिभाषित करके , नियंत्रक पर स्थित होगा Api::V1::UsersController। यह संस्करण 1 है, और आप अनुरोधों को बनाकर वहां पहुंच जाते हैं /api/v1/users

संस्करण 2 केवल एक छोटा सा अलग है। नियंत्रक की सेवा के बजाय पर यह किया जा रहा है Api::V1::UsersController, यह अब पर है Api::V2::UsersController। आप जैसे अनुरोध करके वहाँ पहुँचते हैं /api/v2/users

अगला, एक matchप्रयोग किया जाता है। यह सभी एपीआई मार्गों से मेल खाएगा जो कि चीजों पर जाते हैं /api/v3/users

यह वह हिस्सा है जिसे मुझे देखना था। :to =>विकल्प आपको यह निर्दिष्ट करने के लिए, जो किसी विशेष अनुरोध कहीं और पुनः निर्देशित किया जाना चाहिए की अनुमति देता है - मैं जानता था कि बहुत - लेकिन मैं कैसे इसे कहीं और करने के लिए पुन: निर्देशित और उसके साथ मूल अनुरोध के एक टुकड़े में पारित करने के लिए प्राप्त करने के लिए नहीं पता था ।

ऐसा करने के लिए, हम redirectविधि को कॉल करते हैं और इसे एक विशेष-प्रक्षेपित %{path}पैरामीटर के साथ एक स्ट्रिंग पास करते हैं । जब कोई अनुरोध इस अंतिम से मेल खाता है match, तो यह pathपैरामीटर को %{path}स्ट्रिंग के अंदर के स्थान में प्रक्षेपित करेगा और उस उपयोगकर्ता को रीडायरेक्ट करेगा जहां उन्हें जाने की आवश्यकता है।

अंत में, हम अन्य matchसभी का उपयोग करते हुए शेष सभी मार्गों को पूर्वनिर्मित करते हैं /apiऔर उन्हें पुनर्निर्देशित करते हैं /api/v2/%{path}। इसका मतलब है कि अनुरोध जैसे /api/usersही जाएंगे /api/v2/users

मैं यह पता नहीं लगा सका कि /api/asdf/usersमैच कैसे हो सकता है, क्योंकि आप यह कैसे निर्धारित करते हैं कि यह एक अनुरोध है /api/<resource>/<identifier>या नहीं /api/<version>/<resource>?

वैसे भी, यह शोध करने के लिए मजेदार था और मुझे आशा है कि यह आपकी मदद करता है!


24
प्रिय रयान बिग जी। तुम होशियार हो।
मलिटोर

18
एक बस एक रूबी हीरो की प्रतिष्ठा को मापता नहीं है।
वसीम

1
रयान ... मुझे नहीं लगता कि यह वास्तव में सटीक है। इसमें एक एकल कैनोनिकल URL होने के बजाय / api और / api / v2 समान सामग्री होगी। / एपीआई को / एपीआई / वी 2 (मूल लेखक के रूप में निर्दिष्ट) पर पुनर्निर्देशित किया जाना चाहिए। मैं सही मार्गों की अपेक्षा करूँगा कि gist.github.com/2044335 जैसा कुछ दिखे (दी गई, मैंने इसका परीक्षण नहीं किया है, हालाँकि)। केवल / एपीआई / वी [१२] में २००, एपी / / / एपी / / खराब संस्करण लौटना चाहिए / 301 / / २ / २ पर वापस लौटना चाहिए
बो जीन्स

2
यह ध्यान देने योग्य है कि रूट फ़ाइल में 301 को डिफ़ॉल्ट पुनर्निर्देशित किया गया है और अच्छे कारण के लिए। गाइड से: Please note that this redirection is a 301 “Moved Permanently” redirect. Keep in mind that some web browsers or proxy servers will cache this type of redirect, making the old page inaccessible.
maletor

3
यदि मार्ग सही नहीं है तो क्या यह अनंत पुनर्निर्देश नहीं बनाता है? उदाहरण के लिए, अनुरोध / एपीआई / v3 / path_that_dont_match_the_routes एक अनंत पुनर्निर्देशन पैदा करेगा, है ना?
रॉबिन

38

कुछ चीजों को जोड़ने के लिए:

आपका रीडायरेक्ट मैच कुछ मार्गों के लिए काम नहीं कर रहा है - *apiपरम लालची है और सब कुछ निगल जाएगा, जैसे /api/asdf/users/1कि रीडायरेक्ट करेगा /api/v2/1। आप नियमित रूप से जैसे एक परम का उपयोग कर बेहतर होगा :api। बेशक यह ऐसे मामलों से मेल नहीं खाता, /api/asdf/asdf/users/1लेकिन अगर आपके पास आपके एपीआई में नेस्टेड संसाधन हैं तो यह एक बेहतर समाधान है।

रयान क्यों यू नहीं पसंद namespace? :-), उदा:

current_api_routes = lambda do
  resources :users
end

namespace :api do
  scope :module => :v2, &current_api_routes
  namespace :v2, &current_api_routes
  namespace :v1, &current_api_routes
  match ":api/*path", :to => redirect("/api/v2/%{path}")
end

जिसका वर्जन और जेनेरिक नामित मार्गों का अतिरिक्त लाभ है। एक अतिरिक्त ध्यान दें - सम्मेलन :moduleका उपयोग करते समय अंडरस्कोर नोटेशन का उपयोग करना है, जैसे: api/v1'Api :: V1' नहीं। एक बिंदु पर उत्तरार्द्ध काम नहीं किया था, लेकिन मेरा मानना ​​है कि यह रेल 3.1 में तय किया गया था।

इसके अलावा, जब आप अपने एपीआई के v3 को जारी करते हैं तो मार्गों को इस तरह अपडेट किया जाएगा:

current_api_routes = lambda do
  resources :users
end

namespace :api do
  scope :module => :v3, &current_api_routes
  namespace :v3, &current_api_routes
  namespace :v2, &current_api_routes
  namespace :v1, &current_api_routes
  match ":api/*path", :to => redirect("/api/v3/%{path}")
end

निश्चित रूप से यह संभव है कि आपके API के संस्करणों के बीच अलग-अलग मार्ग हों, जिस स्थिति में आप ऐसा कर सकते हैं:

current_api_routes = lambda do
  # Define latest API
end

namespace :api do
  scope :module => :v3, &current_api_routes
  namespace :v3, &current_api_routes

  namespace :v2 do
    # Define API v2 routes
  end

  namespace :v1 do
    # Define API v1 routes
  end

  match ":api/*path", :to => redirect("/api/v3/%{path}")
end

आप अंतिम मामले से कैसे निपटेंगे? यानी /api/asdf/users?साथ ही /api/users/1? मैं अपने अद्यतित उत्तर में यह पता नहीं लगा सका, ताकि आपको पता चले कि आप एक तरह से जान सकते हैं
रयान बिग

इसे करने का कोई आसान तरीका नहीं है - आपको कैच से पहले सभी रीडायरेक्ट को परिभाषित करना होगा लेकिन आपको केवल प्रत्येक मूल संसाधन के लिए प्रत्येक करने की आवश्यकता होगी, जैसे / एपीआई / उपयोगकर्ता / * पथ => / एपीआई / वी 2 / उपयोगकर्ता /% {पथ}
पिक्सटेल्ट्रिक्स

13

यदि संभव हो तो, मैं आपके url को फिर से जोड़ने का सुझाव दूंगा ताकि संस्करण url में न हो, लेकिन इसे स्वीकार किए जाते हैं हेडर में। यह ढेर अतिप्रवाह उत्तर में अच्छी तरह से चला जाता है:

एपीआई संस्करण के लिए सर्वोत्तम अभ्यास?

और इस लिंक से पता चलता है कि रेल मार्ग के साथ यह कैसे करना है:

http://freelancing-gods.com/posts/versioning_your_ap_is


यह ऐसा करने का एक उत्कृष्ट तरीका है, और संभवतः "/ api / asdf / users" अनुरोध के लिए भी पूरा करेगा।
रयान बिग

9

मैं मार्गों द्वारा संस्करण का बहुत बड़ा प्रशंसक नहीं हूं। हम बनाया VersionCake एपीआई संस्करण का एक आसान प्रपत्र का समर्थन करने के।

हमारे प्रत्येक दृश्य (जूलर, आरएबीएल, आदि) के फ़ाइलनाम में एपीआई संस्करण संख्या को शामिल करके, हम संस्करण को विनीत रखते हैं और पीछे की अनुकूलता का समर्थन करने के लिए आसान गिरावट की अनुमति देते हैं (जैसे यदि दृश्य का v5 मौजूद नहीं है, तो हम दृश्य के v4 प्रस्तुत करना)।


8

मुझे यकीन नहीं है कि अगर आप किसी संस्करण को स्पष्ट रूप से अनुरोध नहीं किया गया है तो आप एक विशिष्ट संस्करण पर पुनर्निर्देशित क्यों करना चाहते हैं । ऐसा लगता है कि आप बस एक डिफ़ॉल्ट संस्करण को परिभाषित करना चाहते हैं जो परोसा जाता है यदि कोई संस्करण स्पष्ट रूप से अनुरोध नहीं किया गया है। मैं डेविड बॉक से भी सहमत हूं कि संस्करणों को URL संरचना से बाहर रखना संस्करणकरण का समर्थन करने का एक स्वच्छ तरीका है।

बेशर्म प्लग: वर्जनिस्ट इन उपयोग मामलों (और अधिक) का समर्थन करता है।

https://github.com/bploetz/versionist


2

रेयान बिग्ग उत्तर ने मेरे लिए काम किया।

यदि आप क्वेरी पैरामीटर को पुनर्निर्देशन के माध्यम से रखना चाहते हैं, तो आप इसे इस तरह से कर सकते हैं:

match "*path", to: redirect{ |params, request| "/api/v2/#{params[:path]}?#{request.query_string}" }

2

इसे आज लागू किया और पाया कि मैं RailsCasts पर सही तरीका मानता हूं - REST API वर्जनिंग । बहुत आसन। इसलिए बनाए रखने योग्य। इतना प्रभावी।

जोड़ें lib/api_constraints.rb(vnd.example बदलना भी नहीं है)

class ApiConstraints
  def initialize(options)
    @version = options[:version]
    @default = options[:default]
  end

  def matches?(req)
    @default || req.headers['Accept'].include?("application/vnd.example.v#{@version}")
  end
end

सेटअप config/routes.rbऐसा

require 'api_constraints'

Rails.application.routes.draw do

  # Squads API
  namespace :api do
    # ApiConstaints is a lib file to allow default API versions,
    # this will help prevent having to change link names from /api/v1/squads to /api/squads, better maintainability
    scope module: :v1, constraints: ApiConstraints.new(version:1, default: true) do
      resources :squads do
        # my stuff was here
      end
    end
  end

  resources :squads
  root to: 'site#index'

अपना नियंत्रक संपादित करें (यानी /controllers/api/v1/squads_controller.rb)

module Api
  module V1
    class SquadsController < BaseController
      # my stuff was here
    end
  end
end

तो फिर तुम से अपने अनुप्रयोग में सभी लिंक को बदल सकते हैं /api/v1/squadsकरने के लिए /api/squadsऔर कर सकते हैं आप आसानी से भी लिंक को बदलने के लिए बिना नई API संस्करण लागू

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.