जब आप किसी API को रैप करने के लिए Ruby का उपयोग करते हैं, तो आपके पास इसे कॉन्फ़िगर करने का एक तरीका होना चाहिए। शायद रैपर को एक उपयोगकर्ता नाम और गुप्त कुंजी की आवश्यकता है, या शायद सिर्फ एक होस्ट।
इसे संभालने के कुछ अलग तरीके हैं। तो आपको कौन सा चुनना चाहिए?
आसान, वैश्विक तरीका
आप चाह सकते हैं कि आपकी सेवा ऐसा व्यवहार करे जैसे वह हमेशा मौजूद है। कोई फर्क नहीं पड़ता कि आप अपने ऐप में कहां हैं, आपके पास इसका उपयोग करने के लिए तैयार होगा। अन्यथा, आप इसका उपयोग करने वाली हर लाइन के लिए इसे कॉन्फ़िगर करने में तीन लाइनें खर्च करेंगे!
आप स्थिरांक या क्लास विशेषताओं का उपयोग करके कॉन्फ़िगरेशन को वैश्विक बना सकते हैं:
ProductApi.root = "https://staging-host.example.com/" ProductApi.user = "justin" ProductApi.secret = "mysecret123"pre>app/controllers/products_controller.rb def show @product = ProductApi.find(params[:id]) endpre>बहुत सारे जेम्स इस पैटर्न का उपयोग करते हैं। यह लिखने में बहुत आसान है, और उपयोग करने में वास्तव में आसान है। लेकिन इसकी कुछ बड़ी समस्याएं हैं:
आपके पास केवल एक
ProductApiहो सकता है।यदि आप Product API को दो अलग-अलग उपयोगकर्ताओं के रूप में उपयोग करना चाहते हैं, या एक ही ऐप से अलग-अलग सर्वर हिट करना चाहते हैं, तो आप भाग्य से बाहर हैं।
ProductApiमें वैश्विक डेटा है जिसे गलती से बदलना आसान है।यदि कोई थ्रेड या आपके ऐप का कोई हिस्सा
ProductApi.userबदल देता है, तोProductApiका उपयोग करने वाली हर दूसरी चीज़ टूट जाएगी। और वे दर्दनाक बग हैं जिन्हें ट्रैक करना मुश्किल है।
तो, क्लास वेरिएबल्स की कुछ समस्याएं हैं। क्या होगा यदि आप अपने Product API क्लास के इंस्टेंस को कॉन्फ़िगर करते हैं, बजाय इसके?
#initialize के साथ यह कैसा दिखेगा?
यदि आप इंस्टेंस का उपयोग करते हैं, तो आप अपने API रैपर को बनाएंगे और कॉन्फ़िगर करेंगे जब आपको इसकी आवश्यकता होगी:
def show product_api = ProductApi.new( root: "https://staging-host.example.com/", user: "justin", secret: "mysecret123") @product = product_api.find(params[:id]) endpre>अब, आप जब भी इसका उपयोग करते हैं तो अपने API को अलग-अलग विवरण पास कर सकते हैं। कोई अन्य मेथड या थ्रेड आपके इंस्टेंस का उपयोग नहीं कर रहा है, इसलिए आपको इसके बिना जाने बिना बदलने की चिंता नहीं करनी होगी।
यह बेहतर लगता है। लेकिन यह अभी भी उतना आसान नहीं है जितना होना चाहिए। क्योंकि आपको अपने API को हर बार कॉन्फ़िगर करना होगा जब आप इसका उपयोग करते हैं।
अधिकांश समय आपको परवाह नहीं है कि API कैसे सेट अप है, आप बस इसे समझदार विकल्पों के साथ उपयोग करना चाहते हैं। लेकिन जब आप इंस्टेंस के साथ काम कर रहे होते हैं, तो आपके ऐप का हर हिस्सा जो API का उपयोग करता है, उसे पता होना चाहिए कि इसे कैसे कॉन्फ़िगर करना है।
लेकिन अच्छा डिफ़ॉल्ट और लचीलापन दोनों पाने का एक तरीका है।
और यह पैटर्न एक दिलचस्प जगह पर हर समय दिखाई देता है: OS X और iOS विकास।
आप अच्छे डिफ़ॉल्ट और लचीलापन कैसे प्राप्त करते हैं?
क्या होगा यदि आप अपने API रैपर के प्रत्येक इंस्टेंस को कॉन्फ़िगर कर सकते हैं, लेकिन आपके पास एक वैश्विक "डिफ़ॉल्ट" इंस्टेंस भी हो जब आप बस परवाह नहीं करते?
आप iOS और Mac OS SDKs में हर जगह इस "defaultSomething" या "sharedWhatever" पैटर्न को देखेंगे:
[[NSURLSession sharedSession] downloadTaskWithURL:@"https://www.google.com"]; [[NSFileManager defaultManager] removeItemAtPath:...];pre>और आप अभी भी इन क्लासेज के इंस्टेंस मांग सकते हैं अगर आपको डिफ़ॉल्ट से अधिक की आवश्यकता है:
NSURLSession *session = [NSURLSession sessionWithConfiguration:...]; NSFileManager fileManager = [[NSFileManager alloc] init];pre>आप Ruby में ऐसा कुछ बना सकते हैं, एक
default_apiक्लास मेथड के साथ:app/controllers/products_controller.rb def show @product = ProductApi.default_product_api.find(params[:id]) end ... def show_special special_product_api = ProductApi.new( root: "https://special-product-host.example.com/" user: "justin" secret: "mysecret123") @special_product = special_product_api.find(params[:id]) endpre>और कार्यान्वयन ऐसा कुछ दिख सकता है:
class ProductApi def initialize(root:, user:, secret:) @root, @user, @secret = root, user, secret end def self.default_api @default_api ||= new( root: ENV['PRODUCT_API_ROOT'], user: ENV['PRODUCT_API_USER'], secret: ENV['PRODUCT_API_SECRET']) end def find(product_id) ... end endpre>यहां, मैंने
default_apiमें पर्यावरण चर का उपयोग किया, लेकिन आप कॉन्फ़िग फ़ाइलों का भी उपयोग कर सकते हैं। और आप थ्रेड- या रिक्वेस्ट-लोकल स्टोरेज का उपयोग करने के लिए||=को बदल सकते हैं।लेकिन यह एक सभ्य शुरुआत है।
मैंने जो अधिकांश जेम्स देखे हैं, जैसे Twitter जेम, वे आपको प्रत्येक API ऑब्जेक्ट को कॉन्फ़िगर करने और बनाने के लिए कहेंगे जब आपको उनकी आवश्यकता हो। यह एक ठीक समाधान है (हालांकि मैं आमतौर पर लोगों को इन्हें वैसे भी ग्लोबल्स को असाइन करते हुए देखता हूं)।
लेकिन यदि आप एक कदम आगे जाते हैं, और एक पूर्व-कॉन्फ़िगर डिफ़ॉल्ट ऑब्जेक्ट का भी उपयोग करते हैं, तो आपका समय बहुत अधिक आरामदायक होगा।