जब आप एक API को लपेटने के लिए रूबी का उपयोग करते हैं, तो आपके पास इसे कॉन्फ़िगर करने का एक तरीका होना चाहिए। शायद रैपर को एक यूजरनेम और सीक्रेट कुंजी की आवश्यकता है, या शायद सिर्फ एक होस्ट।
इसे संभालने के कुछ अलग तरीके हैं। तो आपको कौन सा चुनना चाहिए?
आसान, वैश्विक तरीका
आप चाहते हैं कि आपकी सेवा ऐसा व्यवहार करे जैसे यह हमेशा मौजूद है। कोई फर्क नहीं पड़ता कि आप अपने ऐप में कहां हैं, आपके पास यह उपयोग के लिए तैयार होगा। अन्यथा, आप इसे उपयोग करने की हर लाइन के लिए इसे कॉन्फ़िगर करने में तीन लाइनें खर्च करेंगे!
आप कॉन्फ़िगरेशन को ग्लोबल बना सकते हैं, कॉन्स्टेंट्स या क्लास एट्रिब्यूट्स का उपयोग करके:
ProductApi.root = "https://staging-host.example.com/" ProductApi.user = "justin" ProductApi.secret = "mysecret123"
def show @product = ProductApi.find(params[:id]) end
बहुत सारे जेम्स इस पैटर्न का उपयोग करते हैं। यह लिखना काफी आसान है, और उपयोग करना वास्तव में आसान है। लेकिन इसकी कुछ बड़ी समस्याएं हैं:
आपके पास केवल एक
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]) end
अब, जब भी आप इसका उपयोग करते हैं, आप अपने API को अलग-अलग विवरण पास कर सकते हैं। कोई अन्य मेथड या थ्रेड आपके इंस्टेंस का उपयोग नहीं कर रहा है, इसलिए आपको इसके बिना जाने बदलने के बारे में चिंता करने की ज़रूरत नहीं है।
यह बेहतर लगता है। लेकिन यह अभी भी उतना आसान नहीं है जितना होना चाहिए। क्योंकि आपको हर बार जब आप इसका उपयोग करते हैं तो अपने API को कॉन्फ़िगर करना पड़ता है।
अधिकांश समय आप इस बात की परवाह नहीं करते कि API कैसे सेट अप है, आप सिर्फ इसे समझदार विकल्पों के साथ उपयोग करना चाहते हैं। लेकिन जब आप इंस्टेंस के साथ काम कर रहे होते हैं, तो आपके ऐप का हर हिस्सा जो API का उपयोग करता है, उसे पता होना चाहिए कि इसे कैसे कॉन्फ़िगर किया जाए।
लेकिन अच्छे डिफ़ॉल्ट्स का उपयोग करके ग्लोबल एक्सेस की सुविधा प्राप्त करने का एक तरीका है, जबकि जरूरत पड़ने पर इसे बदलने में सक्षम होना।
और यह पैटर्न एक दिलचस्प जगह पर हर समय दिखाई देता है: OS X और iOS डेवलपमेंट।
आप अच्छे डिफ़ॉल्ट्स और लचीलापन कैसे प्राप्त करते हैं?
क्या होगा यदि आप अपने API रैपर के प्रत्येक इंस्टेंस को कॉन्फ़िगर कर सकते हैं, लेकिन आपके पास एक ग्लोबल "डिफ़ॉल्ट" इंस्टेंस भी है जब आपको परवाह नहीं है?
आप इस "defaultSomething" या "sharedWhatever" पैटर्न को iOS और Mac OS SDKs में हर जगह देखेंगे:
[[NSURLSession sharedSession] downloadTaskWithURL:@"https://www.google.com"]; [[NSFileManager defaultManager] removeItemAtPath:...];
और आप अभी भी इन क्लासेस के इंस्टेंस मांग सकते हैं यदि आपको डिफ़ॉल्ट से अधिक की आवश्यकता है:
NSURLSession *session = [NSURLSession sessionWithConfiguration:...]; NSFileManager fileManager = [[NSFileManager alloc] init];
आप रूबी में ऐसा कुछ बना सकते हैं, एक default_api क्लास मेथड के साथ:
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]) end
और कार्यान्वयन कुछ इस तरह दिख सकता है:
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 end
यहां, मैंने default_api में एनवायरनमेंट वेरिएबल्स का उपयोग किया, लेकिन आप कॉन्फिग फाइल्स का भी उपयोग कर सकते हैं। और आप थ्रेड- या रिक्वेस्ट-लोकल स्टोरेज का उपयोग करने के लिए ||= को स्विच कर सकते हैं।
लेकिन यह एक सभ्य शुरुआत है।
मैंने अधिकांश जेम्स को देखा है, जैसे ट्विटर जेम, जब आपको उनकी आवश्यकता होती है तो प्रत्येक API ऑब्जेक्ट को कॉन्फ़िगर और बनाने के लिए होगा। यह एक ठीक समाधान है (हालांकि मैं आमतौर पर लोगों को वैसे भी इन्हें ग्लोबल्स में असाइन करते हुए देखता हूँ)।
लेकिन यदि आप एक कदम आगे जाते हैं, और एक प्री-कॉन्फ़िगर डिफ़ॉल्ट ऑब्जेक्ट का भी उपयोग करते हैं, तो आपका समय बहुत अधिक आरामदायक होगा।